From: <ale...@us...> - 2012-06-20 11:47:41
|
Revision: 54643 http://firebird.svn.sourceforge.net/firebird/?rev=54643&view=rev Author: alexpeshkoff Date: 2012-06-20 11:47:30 +0000 (Wed, 20 Jun 2012) Log Message: ----------- Implemented CORE-2666: Make it possible to use API to do remote backups/restores Modified Paths: -------------- firebird/trunk/doc/README.services_extension firebird/trunk/src/burp/burp.cpp firebird/trunk/src/burp/burp.h firebird/trunk/src/burp/mvol.cpp firebird/trunk/src/burp/split/spit.cpp firebird/trunk/src/burp/split/spit.h firebird/trunk/src/burp/std_desc.h firebird/trunk/src/common/UtilSvc.cpp firebird/trunk/src/common/UtilSvc.h firebird/trunk/src/common/utils.cpp firebird/trunk/src/include/consts_pub.h firebird/trunk/src/include/gen/msgs.h firebird/trunk/src/jrd/svc.cpp firebird/trunk/src/jrd/svc.h firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp firebird/trunk/src/utilities/ntrace/TracePluginImpl.cpp Modified: firebird/trunk/doc/README.services_extension =================================================================== --- firebird/trunk/doc/README.services_extension 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/doc/README.services_extension 2012-06-20 11:47:30 UTC (rev 54643) @@ -134,7 +134,7 @@ - user: <string> - date: YYYY-MM-DD HH:NN:SS - flags: <string> - + "name" is trace session name and not printed if empty. "user" is creator user name "date" is session start date and time @@ -149,4 +149,45 @@ Output of every service is obtained as usually using isc_service_query call with isc_info_svc_line or isc_info_svc_to_eof information items. -See also README.trace_services \ No newline at end of file +See also README.trace_services + + +4) Services API extension - running gbak at server side with .fbk at the client. +(Alex Peshkov, pes...@ma..., 2011-2012) + +This way of doing backups is specially efficient when one needs to perform +backup/restore operation for database, located on ther server accessed using +internet, due to serious performance instrease. + +The simplest way to use this feature is fbsvcmgr. To backup database run +approximately the following: +fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \ + action_backup -dbname some.fdb -bkp_file stdout >some.fbk + +and to restore it: +fbsvcmgr remotehost:service_mgr -user sysdba -password XXX \ + action_restore -dbname some.fdb -bkp_file stdin <some.fbk + +Please notice - you can't use "verbose" switch when performing backup because +data channel from server to client is used to deliver blocks of fbk files. You +will get appropriate error message if you try to do it. When restoring database +verbose mode may be used without limitations. + +If you want to perform backup/restore from your own program, you should use +services API for it. Backup is very simple - just pass "stdout" as backup file +name to server and use isc_info_svc_to_eof in isc_service_query() call. Data, +returned by repeating calls to isc_service_query() (certainly with +isc_info_svc_to_eof tag) is a stream, representing image of backup file. Restore +is a bit more tricky. Client sends new spb parameter isc_info_svc_stdin to server +in isc_service_query(). If service needs some data in stdin, it returns +isc_info_svc_stdin in query results, followed by 4-bytes value - number of bytes +server is ready to accept from client. (0 value means no more data is needed right +now.) The main trick is that client should NOT send more data than requested by +server - this causes an error "Size of data is more than requested". The data is +sent in next isc_service_query() call in the send_items block, using +isc_info_svc_line tag in tradition form: isc_info_svc_line, 2 bytes length, data. +When server needs next portion, it once more returns non-zero isc_info_svc_stdin +value from isc_service_query(). + +A sample of how services API should be used for remote backup and restore can be +found in source code of fbsvcmgr. Modified: firebird/trunk/src/burp/burp.cpp =================================================================== --- firebird/trunk/src/burp/burp.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/burp.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -1255,12 +1255,17 @@ // Close the gbak file handles if they still open for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) { - if (file->fil_fd != INVALID_HANDLE_VALUE) - close_platf(file->fil_fd); - if (exit_code != FINI_OK && - (tdgbl->action->act_action == ACT_backup_split || tdgbl->action->act_action == ACT_backup)) + if (file->fil_fd != GBAK_STDIN_DESC() && file->fil_fd != GBAK_STDOUT_DESC()) { - unlink_platf(file->fil_name.c_str()); + if (file->fil_fd != INVALID_HANDLE_VALUE) + { + close_platf(file->fil_fd); + } + if (exit_code != FINI_OK && + (tdgbl->action->act_action == ACT_backup_split || tdgbl->action->act_action == ACT_backup)) + { + unlink_platf(file->fil_name.c_str()); + } } } @@ -1840,10 +1845,10 @@ } if (fil->fil_name == "stdout") { - if (tdgbl->action->act_total >= 2 || fil->fil_next) + if (tdgbl->action->act_total >= 2 || fil->fil_next || sw_verbose) { BURP_error(266, true); - // msg 266 standard output is not supported when using split operation + // msg 266 standard output is not supported when using split operation or in verbose mode flag = QUIT; break; } @@ -1855,6 +1860,7 @@ #endif tdgbl->uSvc->setDataMode(true); fil->fil_fd = GBAK_STDOUT_DESC(); + tdgbl->stdIoMode = true; break; } else @@ -1959,10 +1965,13 @@ { fil->fil_fd = GBAK_STDIN_DESC(); tdgbl->file_desc = fil->fil_fd; + tdgbl->stdIoMode = true; tdgbl->gbl_sw_files = fil->fil_next; } else { + tdgbl->stdIoMode = false; + // open first file #ifdef WIN_NT if ((fil->fil_fd = MVOL_open(fil->fil_name.c_str(), MODE_READ, OPEN_EXISTING)) == Modified: firebird/trunk/src/burp/burp.h =================================================================== --- firebird/trunk/src/burp/burp.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/burp.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -871,10 +871,11 @@ BurpGlobals(Firebird::UtilSvc* us) : ThreadData(ThreadData::tddGBL), defaultCollations(*getDefaultMemoryPool()), - flag_on_line(true), uSvc(us), + verboseInterval(10000), + flag_on_line(true), firstMap(true), - verboseInterval(10000) + stdIoMode(false) { // this is VERY dirty hack to keep current behaviour memset (&gbl_database_file_name, 0, @@ -886,8 +887,6 @@ // would be set to FINI_OK (==0) in exit_local } - Firebird::Array<Firebird::Pair<Firebird::NonPooled<Firebird::MetaName, Firebird::MetaName> > > - defaultCollations; const TEXT* gbl_database_file_name; TEXT gbl_backup_start_time[30]; bool gbl_sw_verbose; @@ -1034,10 +1033,13 @@ char veryEnd; //starting after this members must be initialized in constructor explicitly - bool flag_on_line; // indicates whether we will bring the database on-line + Firebird::Array<Firebird::Pair<Firebird::NonPooled<Firebird::MetaName, Firebird::MetaName> > > + defaultCollations; Firebird::UtilSvc* uSvc; - bool firstMap; // this is the first time we entered get_mapping() ULONG verboseInterval; // How many records should be backed up or restored before we show this message + bool flag_on_line; // indicates whether we will bring the database on-line + bool firstMap; // this is the first time we entered get_mapping() + bool stdIoMode; // stdin or stdout is used as backup file }; // CVC: This aux routine declared here to not force inclusion of burp.h with burp_proto.h @@ -1048,17 +1050,8 @@ const int FINI_DB_NOT_ONLINE = 2; // I/O definitions +const int GBAK_IO_BUFFER_SIZE = SVC_IO_BUFFER_SIZE; -#ifndef IO_BUFFER_SIZE -#ifdef BUFSIZ -const int GBAK_IO_BUFFER_SIZE = (16 * (BUFSIZ)); -#else -const int GBAK_IO_BUFFER_SIZE = (16 * (1024)); -#endif -#else -const int GBAK_IO_BUFFER_SIZE = (16 * (IO_BUFFER_SIZE)); -#endif - /* Burp will always write a backup in multiples of the following number * of bytes. The initial value is the smallest which ensures that writes * to fixed-block SCSI tapes such as QIC-150 will work. The value should Modified: firebird/trunk/src/burp/mvol.cpp =================================================================== --- firebird/trunk/src/burp/mvol.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/mvol.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -100,6 +100,7 @@ static bool read_header(DESC, ULONG*, USHORT*, bool); static bool write_header(DESC, ULONG, bool); static DESC next_volume(DESC, ULONG, bool); +static void mvol_read(int*, UCHAR**); //____________________________________________________________ @@ -109,15 +110,16 @@ { BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - if (strcmp(tdgbl->mvol_old_file, "stdin") != 0) + if (!tdgbl->stdIoMode) { close_platf(tdgbl->file_desc); + } - for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + { + if (file->fil_fd == tdgbl->file_desc) { - if (file->fil_fd == tdgbl->file_desc) { - file->fil_fd = INVALID_HANDLE_VALUE; - } + file->fil_fd = INVALID_HANDLE_VALUE; } } @@ -139,15 +141,19 @@ MVOL_write(rec_end, io_cnt, io_ptr); flush_platf(tdgbl->file_desc); - if (strcmp(tdgbl->mvol_old_file, "stdout") != 0) + + if (!tdgbl->stdIoMode) { close_platf(tdgbl->file_desc); - for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + } + for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + { + if (file->fil_fd == tdgbl->file_desc) { - if (file->fil_fd == tdgbl->file_desc) - file->fil_fd = INVALID_HANDLE_VALUE; + file->fil_fd = INVALID_HANDLE_VALUE; } } + tdgbl->file_desc = INVALID_HANDLE_VALUE; BURP_free(tdgbl->mvol_io_header); tdgbl->mvol_io_header = NULL; @@ -255,12 +261,48 @@ } +//____________________________________________________________ +// +// Read a buffer's worth of data. (common) +// +int MVOL_read(int* cnt, UCHAR** ptr) +{ + BurpGlobals* tdgbl = BurpGlobals::getSpecific(); + + if (tdgbl->stdIoMode && tdgbl->uSvc->isService()) + { + tdgbl->uSvc->started(); + tdgbl->mvol_io_cnt = tdgbl->uSvc->getBytes(tdgbl->mvol_io_buffer, tdgbl->mvol_io_buffer_size); + if (!tdgbl->mvol_io_cnt) + { + BURP_error_redirect(0, 220); + // msg 220 Unexpected I/O error while reading from backup file + } + tdgbl->mvol_io_ptr = tdgbl->mvol_io_buffer; + } + else + { + mvol_read(cnt, ptr); + } + + tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt; + file_not_empty(); + + if (ptr) + *ptr = tdgbl->mvol_io_ptr + 1; + if (cnt) + *cnt = tdgbl->mvol_io_cnt - 1; + + return *tdgbl->mvol_io_ptr; +} + + #ifndef WIN_NT //____________________________________________________________ // // Read a buffer's worth of data. (non-WIN_NT) // -int MVOL_read(int* cnt, UCHAR** ptr) +static void mvol_read(int* cnt, UCHAR** ptr) { BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -295,14 +337,6 @@ } } } - - tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt; - file_not_empty(); - - *ptr = tdgbl->mvol_io_ptr + 1; - *cnt = tdgbl->mvol_io_cnt - 1; - - return *tdgbl->mvol_io_ptr; } @@ -311,7 +345,7 @@ // // Read a buffer's worth of data. (WIN_NT) // -int MVOL_read(int* cnt, UCHAR** ptr) +static void mvol_read(int* cnt, UCHAR** ptr) { BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -343,14 +377,6 @@ // msg 50 unexpected end of file on backup file } } - - tdgbl->mvol_cumul_count += tdgbl->mvol_io_cnt; - file_not_empty(); - - *ptr = tdgbl->mvol_io_ptr + 1; - *cnt = tdgbl->mvol_io_cnt - 1; - - return *tdgbl->mvol_io_ptr; } #endif // !WIN_NT @@ -507,169 +533,178 @@ const ULONG size_to_write = BURP_UP_TO_BLOCK(*io_ptr - tdgbl->mvol_io_buffer); ULONG left = size_to_write; - for (ptr = tdgbl->mvol_io_buffer; left > 0; ptr += cnt, left -= cnt) + if (tdgbl->stdIoMode && tdgbl->uSvc->isService()) { - if (tdgbl->action->act_action == ACT_backup_split) + tdgbl->uSvc->started(); + tdgbl->uSvc->putBytes(tdgbl->mvol_io_buffer, left); + left = 0; + } + else + { + for (ptr = tdgbl->mvol_io_buffer; left > 0; ptr += cnt, left -= cnt) { - // Write to the current file till fil_lingth > 0, otherwise - // switch to the next one - if (tdgbl->action->act_file->fil_length == 0) + if (tdgbl->action->act_action == ACT_backup_split) { - if (tdgbl->action->act_file->fil_next) + // Write to the current file till fil_lingth > 0, otherwise + // switch to the next one + if (tdgbl->action->act_file->fil_length == 0) { - close_platf(tdgbl->file_desc); - for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + if (tdgbl->action->act_file->fil_next) { - if (file->fil_fd == tdgbl->file_desc) - file->fil_fd = INVALID_HANDLE_VALUE; + close_platf(tdgbl->file_desc); + for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + { + if (file->fil_fd == tdgbl->file_desc) + file->fil_fd = INVALID_HANDLE_VALUE; + } + tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE; + tdgbl->action->act_file = tdgbl->action->act_file->fil_next; + tdgbl->file_desc = tdgbl->action->act_file->fil_fd; } - tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE; - tdgbl->action->act_file = tdgbl->action->act_file->fil_next; - tdgbl->file_desc = tdgbl->action->act_file->fil_fd; + else + { + // This is a last file. Keep writing in a hope that there is + // enough free disk space ... + tdgbl->action->act_file->fil_length = MAX_LENGTH; + } } - else - { - // This is a last file. Keep writing in a hope that there is - // enough free disk space ... - tdgbl->action->act_file->fil_length = MAX_LENGTH; - } } - } - const size_t nBytesToWrite = - (tdgbl->action->act_action == ACT_backup_split && - tdgbl->action->act_file->fil_length < left) ? - tdgbl->action->act_file->fil_length : left; + const size_t nBytesToWrite = + (tdgbl->action->act_action == ACT_backup_split && + tdgbl->action->act_file->fil_length < left) ? + tdgbl->action->act_file->fil_length : left; #ifndef WIN_NT - cnt = write(tdgbl->file_desc, ptr, nBytesToWrite); + cnt = write(tdgbl->file_desc, ptr, nBytesToWrite); #else - DWORD ret = 0; - if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL)) - { - ret = GetLastError(); - } + DWORD ret = 0; + if (!WriteFile(tdgbl->file_desc, ptr, (DWORD) nBytesToWrite, &cnt, NULL)) + { + ret = GetLastError(); + } #endif // !WIN_NT - tdgbl->mvol_io_buffer = tdgbl->mvol_io_data; - if (cnt > 0) - { - tdgbl->mvol_cumul_count += cnt; - file_not_empty(); - if (tdgbl->action->act_action == ACT_backup_split) + tdgbl->mvol_io_buffer = tdgbl->mvol_io_data; + if (cnt > 0) { - if (tdgbl->action->act_file->fil_length < left) - tdgbl->action->act_file->fil_length = 0; - else - tdgbl->action->act_file->fil_length -= left; + tdgbl->mvol_cumul_count += cnt; + file_not_empty(); + if (tdgbl->action->act_action == ACT_backup_split) + { + if (tdgbl->action->act_file->fil_length < left) + tdgbl->action->act_file->fil_length = 0; + else + tdgbl->action->act_file->fil_length -= left; + } } - } - else - { - if (!cnt || + else + { + if (!cnt || #ifndef WIN_NT - errno == ENOSPC || errno == EIO || errno == ENXIO || - errno == EFBIG) + errno == ENOSPC || errno == EIO || errno == ENXIO || + errno == EFBIG) #else - ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL) + ret == ERROR_DISK_FULL || ret == ERROR_HANDLE_DISK_FULL) #endif // !WIN_NT - { - if (tdgbl->action->act_action == ACT_backup_split) { - // Close the current file and switch to the next one. - // If there is no more specified files left then - // issue an error and give up - if (tdgbl->action->act_file->fil_next) + if (tdgbl->action->act_action == ACT_backup_split) { - close_platf(tdgbl->file_desc); - for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + // Close the current file and switch to the next one. + // If there is no more specified files left then + // issue an error and give up + if (tdgbl->action->act_file->fil_next) { - if (file->fil_fd == tdgbl->file_desc) - file->fil_fd = INVALID_HANDLE_VALUE; - } + close_platf(tdgbl->file_desc); + for (burp_fil* file = tdgbl->gbl_sw_backup_files; file; file = file->fil_next) + { + if (file->fil_fd == tdgbl->file_desc) + file->fil_fd = INVALID_HANDLE_VALUE; + } - tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE; - BURP_print(true, 272, SafeArg() << - tdgbl->action->act_file->fil_name.c_str() << - tdgbl->action->act_file->fil_length << - tdgbl->action->act_file->fil_next->fil_name.c_str()); - // msg 272 Warning -- free disk space exhausted for file %s, - // the rest of the bytes (%d) will be written to file %s - tdgbl->action->act_file->fil_next->fil_length += + tdgbl->action->act_file->fil_fd = INVALID_HANDLE_VALUE; + BURP_print(true, 272, SafeArg() << + tdgbl->action->act_file->fil_name.c_str() << + tdgbl->action->act_file->fil_length << + tdgbl->action->act_file->fil_next->fil_name.c_str()); + // msg 272 Warning -- free disk space exhausted for file %s, + // the rest of the bytes (%d) will be written to file %s + tdgbl->action->act_file->fil_next->fil_length += tdgbl->action->act_file->fil_length; - tdgbl->action->act_file = tdgbl->action->act_file->fil_next; - tdgbl->file_desc = tdgbl->action->act_file->fil_fd; + tdgbl->action->act_file = tdgbl->action->act_file->fil_next; + tdgbl->file_desc = tdgbl->action->act_file->fil_fd; + } + else + { + BURP_error(270, true); + // msg 270 free disk space exhausted + } + cnt = 0; + continue; } - else + + if (tdgbl->uSvc->isService()) { BURP_error(270, true); // msg 270 free disk space exhausted } - cnt = 0; - continue; - } - if (tdgbl->uSvc->isService()) - { - BURP_error(270, true); - // msg 270 free disk space exhausted - } + // Note: there is an assumption here, that if header data is being + // written, it is really being rewritten, so at least all the + // header data will be written - // Note: there is an assumption here, that if header data is being - // written, it is really being rewritten, so at least all the - // header data will be written + if (left != size_to_write) + { + // Wrote some, move remainder up in buffer. - if (left != size_to_write) - { - // Wrote some, move remainder up in buffer. - - // NOTE: We should NOT use memcpy here. We're moving overlapped - // data and memcpy does not guanantee the order the data - // is moved in - memcpy(tdgbl->mvol_io_data, ptr, left); + // NOTE: We should NOT use memcpy here. We're moving overlapped + // data and memcpy does not guanantee the order the data + // is moved in + memcpy(tdgbl->mvol_io_data, ptr, left); + } + left += tdgbl->mvol_io_data - tdgbl->mvol_io_header; + bool full_buffer; + if (left >= tdgbl->mvol_io_buffer_size) + full_buffer = true; + else + full_buffer = false; + tdgbl->file_desc = next_volume(tdgbl->file_desc, MODE_WRITE, full_buffer); + if (full_buffer) + { + left -= tdgbl->mvol_io_buffer_size; + memcpy(tdgbl->mvol_io_data, + tdgbl->mvol_io_header + tdgbl->mvol_io_buffer_size, + left); + tdgbl->mvol_cumul_count += tdgbl->mvol_io_buffer_size; + tdgbl->mvol_io_buffer = tdgbl->mvol_io_data; + } + else + tdgbl->mvol_io_buffer = tdgbl->mvol_io_header; + break; } - left += tdgbl->mvol_io_data - tdgbl->mvol_io_header; - bool full_buffer; - if (left >= tdgbl->mvol_io_buffer_size) - full_buffer = true; - else - full_buffer = false; - tdgbl->file_desc = next_volume(tdgbl->file_desc, MODE_WRITE, full_buffer); - if (full_buffer) + else if (!SYSCALL_INTERRUPTED(errno)) { - left -= tdgbl->mvol_io_buffer_size; - memcpy(tdgbl->mvol_io_data, - tdgbl->mvol_io_header + tdgbl->mvol_io_buffer_size, - left); - tdgbl->mvol_cumul_count += tdgbl->mvol_io_buffer_size; - tdgbl->mvol_io_buffer = tdgbl->mvol_io_data; + BURP_error_redirect(0, 221); + // msg 221 Unexpected I/O error while writing to backup file } - else - tdgbl->mvol_io_buffer = tdgbl->mvol_io_header; - break; } - else if (!SYSCALL_INTERRUPTED(errno)) - { - BURP_error_redirect(0, 221); - // msg 221 Unexpected I/O error while writing to backup file + if (left < cnt) { // this is impossible, but... + cnt = left; } - } - if (left < cnt) { // this is impossible, but... - cnt = left; - } - } // for + } // for #ifdef DEBUG - { - int dbg_cnt; - if (debug_on) { - for (dbg_cnt = 0; dbg_cnt < cnt; dbg_cnt++) - printf("%d,\n", *(ptr + dbg_cnt)); + int dbg_cnt; + if (debug_on) + { + for (dbg_cnt = 0; dbg_cnt < cnt; dbg_cnt++) + printf("%d,\n", *(ptr + dbg_cnt)); + } } +#endif } -#endif // After the first block of first volume is written (using a default block size) // change the block size to one that reflects the user's blocking factor. By @@ -1069,13 +1104,21 @@ // Headers are a version number, and a volume number + if (tdgbl->stdIoMode && tdgbl->uSvc->isService()) + { + tdgbl->uSvc->started(); + tdgbl->mvol_io_cnt = tdgbl->uSvc->getBytes(tdgbl->mvol_io_buffer, tdgbl->mvol_io_buffer_size); + } + else + { #ifndef WIN_NT - tdgbl->mvol_io_cnt = read(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size); + tdgbl->mvol_io_cnt = read(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size); #else - DWORD bytesRead = 0; - ReadFile(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size, &bytesRead, NULL); - tdgbl->mvol_io_cnt = bytesRead; + DWORD bytesRead = 0; + ReadFile(handle, tdgbl->mvol_io_buffer, tdgbl->mvol_actual_buffer_size, &bytesRead, NULL); + tdgbl->mvol_io_cnt = bytesRead; #endif + } if (!tdgbl->mvol_io_cnt) BURP_error_redirect(0, 45); // maybe there's a better message Modified: firebird/trunk/src/burp/split/spit.cpp =================================================================== --- firebird/trunk/src/burp/split/spit.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/split/spit.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -47,6 +47,7 @@ #endif #include "../burp/split/spit.h" #include "../common/classes/Switches.h" +#include "../burp/std_desc.h" #include "../burp/burpswi.h" #ifdef HAVE_UNISTD_H @@ -61,6 +62,53 @@ static const int mode_write = O_WRONLY | O_CREAT; static const int mask = 0666; +static DESC open_platf(const char* name, int writeFlag) +{ +#ifdef WIN_NT + return CreateFile(name, writeFlag ? GENERIC_WRITE : GENERIC_READ, 0, NULL, + writeFlag ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +#else + return open(name, writeFlag ? mode_write : mode_read, mask); +#endif +} + +static int read_platf(DESC file, void* buf, int count) +{ +#ifdef WIN_NT + DWORD act; + if (!ReadFile(file, buf, count, &act, NULL)) + { + return -1; + } + return act; +#else + return read(file, buf, count); +#endif +} + +static int write_platf(DESC file, const void* buf, int count) +{ +#ifdef WIN_NT + DWORD act; + if (!WriteFile(file, buf, count, &act, NULL)) + { + return -1; + } + return act; +#else + return write(file, buf, count); +#endif +} + +static void close_platf(DESC file) +{ +#ifdef WIN_NT + CloseHandle(file); +#else + close(file); +#endif +} + // Definitions for GSPLIT enum gsplit_option { @@ -291,7 +339,7 @@ switch (sw_replace) { case IN_SW_SPIT_SP: - input_file_desc = GBAK_STDIN_DESC; + input_file_desc = GBAK_STDIN_DESC(); ret_cd = gen_multy_bakup_files(file_list, input_file_desc, file_num); if (ret_cd == FB_FAILURE) { @@ -610,8 +658,8 @@ file_size = fl_ptr->b_fil_size - header_rec_len; file_name = fl_ptr->b_fil_name; - output_fl_desc = open(file_name, mode_write, mask); - if (output_fl_desc == -1) + output_fl_desc = open_platf(file_name, 1); + if (output_fl_desc == INVALID_HANDLE_VALUE) { free(io_buffer); fprintf(stderr, "can not open back up file %s\n", file_name); @@ -681,8 +729,8 @@ file_size = fl_ptr->b_fil_size - header_rec_len; file_name = fl_ptr->b_fil_name; - output_fl_desc = open(file_name, mode_write, mask); - if (output_fl_desc == -1) + output_fl_desc = open_platf(file_name, 1); + if (output_fl_desc == INVALID_HANDLE_VALUE) { free(io_buffer); fprintf(stderr, "can not open back up file %s\n", file_name); @@ -793,21 +841,21 @@ if (*byte_read + io_size > file_size) { last_read_size = (SLONG) (file_size - *byte_read); - read_cnt = read(input_file_desc, *io_buffer, last_read_size); + read_cnt = read_platf(input_file_desc, *io_buffer, last_read_size); } else - read_cnt = read(input_file_desc, *io_buffer, io_size); + read_cnt = read_platf(input_file_desc, *io_buffer, io_size); switch (read_cnt) { case 0: // no more data to be read - close(output_fl_desc); + close_platf(output_fl_desc); *end_of_input = true; *byte_read = *byte_read + read_cnt; return FB_SUCCESS; case -1: // read failed - close(output_fl_desc); + close_platf(output_fl_desc); fprintf(stderr, "fail to read input from stdin, errno = %d\n", errno); return FB_FAILURE; @@ -816,12 +864,12 @@ break; } - const SLONG write_cnt = write(output_fl_desc, *io_buffer, read_cnt); + const SLONG write_cnt = write_platf(output_fl_desc, *io_buffer, read_cnt); switch (write_cnt) { case -1: // write failed - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; default: @@ -829,7 +877,7 @@ return FB_SUCCESS; // write less data than it reads in - close(output_fl_desc); + close_platf(output_fl_desc); *byte_write = write_cnt; return FILE_IS_FULL; } @@ -858,17 +906,17 @@ ********************************************************************* */ - const SLONG read_cnt = read(input_file_desc, *io_buffer, io_size); + const SLONG read_cnt = read_platf(input_file_desc, *io_buffer, io_size); switch (read_cnt) { case 0: // no more data to be read - close(output_fl_desc); + close_platf(output_fl_desc); *end_of_input = true; return FB_SUCCESS; case -1: // read failed - close(output_fl_desc); + close_platf(output_fl_desc); fprintf(stderr, "problem when reading input file, errno = %d\n", errno); return FB_FAILURE; @@ -876,12 +924,12 @@ break; } - const SLONG write_cnt = write(output_fl_desc, *io_buffer, read_cnt); + const SLONG write_cnt = write_platf(output_fl_desc, *io_buffer, read_cnt); switch (write_cnt) { case -1: // write failed - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; default: @@ -889,7 +937,7 @@ return FB_SUCCESS; fprintf(stderr, "There is no enough space to write to back up file %s\n", file_name); - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; } } @@ -914,7 +962,7 @@ ********************************************************************* */ - FILE_DESC output_fl_desc = GBAK_STDOUT_DESC; + FILE_DESC output_fl_desc = GBAK_STDOUT_DESC(); // See comment near the beginning of gen_multy_bakup_files() as it // also applies to read_and_write_for_join(). @@ -974,18 +1022,18 @@ TEXT num_arr[5], total_arr[5]; header_rec hdr_rec; - FILE_DESC input_fl_desc = open(file_name, mode_read); + FILE_DESC input_fl_desc = open_platf(file_name, mode_read); - if (input_fl_desc == -1) + if (input_fl_desc == INVALID_HANDLE_VALUE) { fprintf(stderr, "can not open input file %s\n", file_name); return FB_FAILURE; } - int read_cnt = read(input_fl_desc, io_buffer, header_rec_len); + int read_cnt = read_platf(input_fl_desc, io_buffer, header_rec_len); if (read_cnt != static_cast<int>(header_rec_len)) { - close(input_fl_desc); + close_platf(input_fl_desc); fprintf(stderr, "progam fails to read gsplit header record in back-up file%s\n", file_name); return FB_FAILURE; } @@ -994,7 +1042,7 @@ SLONG ret_cd = strncmp(char_ptr1, header_rec_name, sizeof(hdr_rec.name) - 1); if (ret_cd != 0) { - close(input_fl_desc); + close_platf(input_fl_desc); fprintf(stderr, "gsplit: expected GSPLIT description record\n"); fprintf(stderr, "gsplit: Exiting before completion due to errors\n"); return FB_FAILURE; @@ -1026,13 +1074,13 @@ if ((num_int != cnt) || (num_int > *total_int)) { - close(input_fl_desc); + close_platf(input_fl_desc); fprintf(stderr, "gsplit: join backup file is out of sequence\n"); fprintf(stderr, "gsplit: Exiting before completion due to errors\n"); return FB_FAILURE; } - read_cnt = read(input_fl_desc, io_buffer, IO_BUFFER_SIZE); + read_cnt = read_platf(input_fl_desc, io_buffer, IO_BUFFER_SIZE); while (true) @@ -1040,23 +1088,23 @@ switch (read_cnt) { case 0: // no more data to be read - close(input_fl_desc); + close_platf(input_fl_desc); return FB_SUCCESS; case -1: // read failed - close(input_fl_desc); + close_platf(input_fl_desc); return FB_FAILURE; default: // this is the last read break; } - SLONG write_cnt = write(output_fl_desc, io_buffer, read_cnt); + SLONG write_cnt = write_platf(output_fl_desc, io_buffer, read_cnt); switch (write_cnt) { case -1: // write failed - close(input_fl_desc); + close_platf(input_fl_desc); return FB_FAILURE; default: @@ -1064,7 +1112,7 @@ break; } - read_cnt = read(input_fl_desc, io_buffer, IO_BUFFER_SIZE); + read_cnt = read_platf(input_fl_desc, io_buffer, IO_BUFFER_SIZE); } // end of while (true) loop } @@ -1150,11 +1198,11 @@ ret_cd = set_hdr_str(header_str, file_name, pos, strlen(file_name)); SLONG end, indx; - SLONG write_cnt = write(output_fl_desc, header_str, header_rec_len); + SLONG write_cnt = write_platf(output_fl_desc, header_str, header_rec_len); switch (write_cnt) { case -1: // write failed - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; default: @@ -1202,14 +1250,14 @@ SLONG write_cnt; if (file_size > remaining_io_len) - write_cnt = write(output_fl_desc, remaining_io, remaining_io_len); + write_cnt = write_platf(output_fl_desc, remaining_io, remaining_io_len); else // file_size <= remaining_io_len - write_cnt = write(output_fl_desc, remaining_io, (unsigned int) file_size); + write_cnt = write_platf(output_fl_desc, remaining_io, (unsigned int) file_size); switch (write_cnt) { case -1: // write failed - close(output_fl_desc); + close_platf(output_fl_desc); *flush_done = false; return FB_FAILURE; @@ -1219,7 +1267,7 @@ else { // could not write out all remaining data - close(output_fl_desc); + close_platf(output_fl_desc); *flush_done = false; } *byte_write = write_cnt; @@ -1245,18 +1293,18 @@ ********************************************************************* */ - SLONG write_cnt = write(output_fl_desc, remaining_io, remaining_io_len); + SLONG write_cnt = write_platf(output_fl_desc, remaining_io, remaining_io_len); switch (write_cnt) { case -1: // write failed - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; default: if (write_cnt == remaining_io_len) // write ok return FB_SUCCESS; - close(output_fl_desc); + close_platf(output_fl_desc); return FB_FAILURE; } } Modified: firebird/trunk/src/burp/split/spit.h =================================================================== --- firebird/trunk/src/burp/split/spit.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/split/spit.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -40,8 +40,3 @@ const int MIN_FILE_SIZE = M_BYTES; const char NEW_LINE = '\n'; const char TERMINAL = '\0'; - -typedef int FILE_DESC; - -const FILE_DESC GBAK_STDIN_DESC = 0; // standard input file descriptor -const FILE_DESC GBAK_STDOUT_DESC = 1; // standard output file descriptor Modified: firebird/trunk/src/burp/std_desc.h =================================================================== --- firebird/trunk/src/burp/std_desc.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/burp/std_desc.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -61,4 +61,6 @@ #endif //WIN_NT +typedef DESC FILE_DESC; + #endif //GBAK_STD_DESC_H Modified: firebird/trunk/src/common/UtilSvc.cpp =================================================================== --- firebird/trunk/src/common/UtilSvc.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/common/UtilSvc.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -137,6 +137,7 @@ virtual void putSLong(char, SLONG) { } virtual void putChar(char, char) { } virtual void putBytes(const UCHAR*, size_t) { } + virtual ULONG getBytes(UCHAR*, ULONG) { return 0; } virtual void setServiceStatus(const ISC_STATUS*) { } virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) { } virtual const ISC_STATUS* getStatus() { return 0; } Modified: firebird/trunk/src/common/UtilSvc.h =================================================================== --- firebird/trunk/src/common/UtilSvc.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/common/UtilSvc.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -63,6 +63,7 @@ virtual void putSLong(char, SLONG) = 0; virtual void putChar(char, char) = 0; virtual void putBytes(const UCHAR*, size_t) = 0; + virtual ULONG getBytes(UCHAR*, ULONG) = 0; virtual void setServiceStatus(const ISC_STATUS*) = 0; virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) = 0; virtual const ISC_STATUS* getStatus() = 0; Modified: firebird/trunk/src/common/utils.cpp =================================================================== --- firebird/trunk/src/common/utils.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/common/utils.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -1143,6 +1143,7 @@ case isc_info_svc_limbo_trans: case isc_info_svc_running: case isc_info_svc_get_users: + case isc_info_svc_stdin: if (state == S_INF) { (Firebird::Arg::Gds(isc_random) << "Wrong info items combination").raise(); Modified: firebird/trunk/src/include/consts_pub.h =================================================================== --- firebird/trunk/src/include/consts_pub.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/include/consts_pub.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -334,6 +334,7 @@ #define isc_info_svc_running 67 /* Checks to see if a service is running on an attachment */ #define isc_info_svc_get_users 68 /* Returns the user information from isc_action_svc_display_users */ #define isc_info_svc_auth_block 69 /* Sets authentication block for service query() call */ +#define isc_info_svc_stdin 78 /* Returns maximum size of data, needed as stdin for service */ /****************************************************** Modified: firebird/trunk/src/include/gen/msgs.h =================================================================== --- firebird/trunk/src/include/gen/msgs.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/include/gen/msgs.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -939,7 +939,7 @@ {336331015, "file @1 out of sequence"}, /* gbak_file_outof_sequence */ {336331016, "can't join -- one of the files missing"}, /* gbak_join_file_missing */ {336331017, " standard input is not supported when using join operation"}, /* gbak_stdin_not_supptd */ - {336331018, "standard output is not supported when using split operation"}, /* gbak_stdout_not_supptd */ + {336331018, "standard output is not supported when using split operation or in verbose mode"}, /* gbak_stdout_not_supptd */ {336331019, "backup file @1 might be corrupt"}, /* gbak_bkup_corrupt */ {336331020, "database file specification missing"}, /* gbak_unk_db_file_spec */ {336331021, "can't write a header record to file @1"}, /* gbak_hdr_write_failed */ Modified: firebird/trunk/src/jrd/svc.cpp =================================================================== --- firebird/trunk/src/jrd/svc.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/jrd/svc.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -119,6 +119,7 @@ const int GET_LINE = 1; const int GET_EOF = 2; const int GET_BINARY = 4; +const int GET_ONCE = 8; const char* const SPB_SEC_USERNAME = "isc_spb_sec_username"; @@ -433,6 +434,7 @@ void Service::finish() { + svc_sem_full.release(); finish(SVC_finished); } @@ -661,7 +663,7 @@ bool Service::ck_space_for_numeric(UCHAR*& info, const UCHAR* const end) { if ((info + 1 + sizeof(ULONG)) > end) - { + { if (info < end) *info++ = isc_info_truncated; return false; @@ -706,7 +708,9 @@ svc_command_line(getPool()), svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remote_process(getPool()), svc_remote_pid(0), svc_trace_manager(NULL), svc_crypt_callback(crypt_callback), - svc_current_guard(NULL) + svc_current_guard(NULL), + svc_stdin_size_requested(0), svc_stdin_buffer(NULL), svc_stdin_size_preload(0), + svc_stdin_preload_requested(0), svc_stdin_user_size(0) { initStatus(); ThreadIdHolder holdId(svc_thread_strings); @@ -1004,6 +1008,8 @@ { if (all[pos]->svc_flags & SVC_thd_running) all[pos]->svc_detach_sem.release(); + if (all[pos]->svc_stdin_size_requested) + all[pos]->svc_stdin_semaphore.release(); } for (pos = 0; pos < all.getCount(); ) @@ -1035,18 +1041,22 @@ UCHAR item; UCHAR buffer[MAXPATHLEN]; USHORT l, length, version, get_flags; + UCHAR* stdin_request_notification = NULL; ThreadIdHolder holdId(svc_thread_strings); // Setup the status vector Arg::StatusVector status; + ULONG requestFromPut = 0; + try { // Process the send portion of the query first. USHORT timeout = 0; const UCHAR* items = send_items; const UCHAR* const end_items = items + send_item_length; + while (items < end_items && *items != isc_info_end) { switch ((item = *items++)) @@ -1064,10 +1074,10 @@ switch (item) { case isc_info_svc_line: - put(items, l); + requestFromPut = put(items, l); break; case isc_info_svc_message: - put(items - 3, l + 3); + //put(items - 3, l + 3); break; case isc_info_svc_timeout: timeout = (USHORT) gds__vax_integer(items, l); @@ -1311,6 +1321,21 @@ } // scope break; + case isc_info_svc_stdin: + // Check - is stdin data required for server + if (!ck_space_for_numeric(info, end)) + { + return 0; + } + *info++ = item; + if (!stdin_request_notification) + { + stdin_request_notification = info; + } + ADD_SPB_NUMERIC(info, 0); + + break; + case isc_info_svc_user_dbpath: if (svc_user_flag & SVC_user_dba) { @@ -1335,7 +1360,7 @@ *info++ = isc_info_truncated; break; } - put(&item, 1); + //put(&item, 1); get(&item, 1, GET_BINARY, 0, &length); get(buffer, 2, GET_BINARY, 0, &length); l = (USHORT) gds__vax_integer(buffer, 2); @@ -1380,7 +1405,7 @@ break; case isc_info_svc_total_length: - put(&item, 1); + //put(&item, 1); get(&item, 1, GET_BINARY, 0, &length); get(buffer, 2, GET_BINARY, 0, &length); l = (USHORT) gds__vax_integer(buffer, 2); @@ -1413,6 +1438,11 @@ break; } + if (requestFromPut) + { + get_flags |= GET_ONCE; + } + get(info + 3, end - (info + 5), get_flags, timeout, &length); // If the read timed out, return the data, if any, & a timeout @@ -1428,7 +1458,7 @@ { *info++ = isc_info_svc_timeout; } - else + else //if (!svc_stdin_size_requested) { if (!length && !(svc_flags & SVC_finished)) { @@ -1458,6 +1488,8 @@ const SLONG number = info - start_info; fb_assert(number > 0); memmove(start_info + 7, start_info, number); + if (stdin_request_notification) + stdin_request_notification += 7; USHORT length2 = INF_convert(number, buffer); fb_assert(length2 == 4); // We only accept SLONG INF_put_item(isc_info_length, length2, buffer, start_info, end, true); @@ -1470,6 +1502,23 @@ recv_item_length, recv_items, res_successful); } + if (!requestFromPut) + { + requestFromPut = svc_stdin_size_requested; + } + + if (requestFromPut) + { + if (stdin_request_notification) + { + ADD_SPB_NUMERIC(stdin_request_notification, requestFromPut); + } + else + { + (Arg::Gds(isc_random) << "No request from user for stdin data").raise(); + } + } + if (status.hasData()) { status.raise(); @@ -1538,10 +1587,10 @@ switch (item) { case isc_info_svc_line: - put(items, l); + //put(items, l); break; case isc_info_svc_message: - put(items - 3, l + 3); + //put(items - 3, l + 3); break; case isc_info_svc_timeout: timeout = (USHORT) gds__vax_integer(items, l); @@ -1764,7 +1813,7 @@ *info++ = isc_info_truncated; break; } - put(&item, 1); + //put(&item, 1); get(&item, 1, GET_BINARY, 0, &length); get(buffer, 2, GET_BINARY, 0, &length); l = (USHORT) gds__vax_integer(buffer, 2); @@ -1809,7 +1858,7 @@ break; case isc_info_svc_total_length: - put(&item, 1); + //put(&item, 1); get(&item, 1, GET_BINARY, 0, &length); get(buffer, 2, GET_BINARY, 0, &length); l = (USHORT) gds__vax_integer(buffer, 2); @@ -2181,19 +2230,29 @@ void Service::enqueue(const UCHAR* s, ULONG len) { + static int transferCount = 0; + if (checkForShutdown() || (svc_flags & SVC_detached)) { + svc_sem_full.release(); return; } while (len) { // Wait for space in buffer + bool flagFirst = true; while (full()) { - THREAD_SLEEP(ENQUEUE_DEQUEUE_DELAY); + if (flagFirst) + { + svc_sem_full.release(); + flagFirst = false; + } + svc_sem_empty.tryEnter(1, 0); if (checkForShutdown() || (svc_flags & SVC_detached)) { + svc_sem_full.release(); return; } } @@ -2211,10 +2270,12 @@ } memcpy(&svc_stdout[svc_stdout_tail], s, cnt); + transferCount += cnt; svc_stdout_tail = add_val(svc_stdout_tail, cnt); s += cnt; len -= cnt; } + svc_sem_full.release(); } @@ -2235,6 +2296,7 @@ svc_flags &= ~SVC_timeout; } + bool flagFirst = true; while (length) { if ((empty() && (svc_flags & SVC_finished)) || checkForShutdown()) @@ -2244,7 +2306,24 @@ if (empty()) { - THREAD_SLEEP(ENQUEUE_DEQUEUE_DELAY); + if (svc_stdin_size_requested && (!(flags & GET_BINARY))) + { + // service needs data from user - notify him + break; + } + + if (flagFirst) + { + svc_sem_empty.release(); + flagFirst = false; + } + + if (flags & GET_ONCE) + { + break; + } + + svc_sem_full.tryEnter(1, 0); } #ifdef HAVE_GETTIMEOFDAY GETTIMEOFDAY(&end_time); @@ -2264,6 +2343,7 @@ while (head != svc_stdout_tail && length > 0) { + flagFirst = true; const UCHAR ch = svc_stdout[head]; head = add_one(head); length--; @@ -2283,15 +2363,103 @@ svc_stdout_head = head; } + svc_sem_empty.release(); } -void Service::put(const UCHAR* /*buffer*/, USHORT /*length*/) +ULONG Service::put(const UCHAR* buffer, ULONG length) { - // Nothing + MutexLockGuard guard(svc_stdin_mutex); + + // check length correctness + if (length > svc_stdin_size_requested && length > svc_stdin_preload_requested) + { + (Arg::Gds(isc_random) << "Size of data is more than requested").raise(); + } + + if (svc_stdin_size_requested) // service waits for data from us + { + svc_stdin_user_size = MIN(length, svc_stdin_size_requested); + memcpy(svc_stdin_buffer, buffer, svc_stdin_user_size); + // reset satisfied request + ULONG blockSize = svc_stdin_size_requested; + svc_stdin_size_requested = 0; + // let data be used + svc_stdin_semaphore.release(); + + if (length == 0) + { + return 0; + } + + // reset used block of data + length -= svc_stdin_user_size; + buffer += svc_stdin_user_size; + + if (length == 0) // ask user to preload next block of data + { + if (!svc_stdin_preload) + { + svc_stdin_preload.reset(FB_NEW(getPool()) UCHAR[PRELOAD_BUFFER_SIZE]); + } + + svc_stdin_preload_requested = MIN(blockSize, PRELOAD_BUFFER_SIZE); + return svc_stdin_preload_requested; + } + } + + // Store data in preload buffer + fb_assert(length <= PRELOAD_BUFFER_SIZE); + fb_assert(length <= svc_stdin_preload_requested); + fb_assert(svc_stdin_size_preload == 0); + + memcpy(svc_stdin_preload, buffer, length); + svc_stdin_size_preload = length; + return 0; } +ULONG Service::getBytes(UCHAR* buffer, ULONG size) +{ + { // Guard scope + MutexLockGuard guard(svc_stdin_mutex); + + if (svc_flags & SVC_detached) // no more data for this service please + { + return 0; + } + + if (svc_stdin_size_preload != 0) // use data, preloaded by user + { + // Use data from preload buffer + size = MIN(size, svc_stdin_size_preload); + memcpy(buffer, svc_stdin_preload, size); + if (size < svc_stdin_size_preload) + { + // not good, client should not request so small block + svc_stdin_size_preload -= size; + memmove(svc_stdin_preload, svc_stdin_preload + size, svc_stdin_size_preload); + } + else + { + svc_stdin_size_preload = 0; + } + return size; + } + + // Request new data portion + svc_stdin_size_requested = size; + svc_stdin_buffer = buffer; + // Wakeup Service::query() if it waits for data from service + svc_sem_full.release(); + } + + // Wait for data from client + svc_stdin_semaphore.enter(); + return svc_stdin_user_size; +} + + void Service::finish(USHORT flag) { if (flag == SVC_finished || flag == SVC_detached) @@ -2308,8 +2476,26 @@ delete this; return; } + + if (svc_flags & SVC_detached) + { + svc_sem_empty.release(); + + // if service waits for data from us - return EOF + { // guard scope + MutexLockGuard guard(svc_stdin_mutex); + + if (svc_stdin_size_requested) + { + svc_stdin_user_size = 0; + svc_stdin_semaphore.release(); + } + } + } + if (svc_flags & SVC_finished) { + svc_sem_full.release(); svc_flags &= ~SVC_thd_running; } else Modified: firebird/trunk/src/jrd/svc.h =================================================================== --- firebird/trunk/src/jrd/svc.h 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/jrd/svc.h 2012-06-20 11:47:30 UTC (rev 54643) @@ -38,7 +38,18 @@ #include "../common/UtilSvc.h" #include "../common/classes/Switches.h" #include "../common/classes/ClumpletReader.h" +#include "../burp/split/spit.h" +#ifndef IO_BUFFER_SIZE +#ifdef BUFSIZ +const int SVC_IO_BUFFER_SIZE = (16 * (BUFSIZ)); +#else // BUFSIZ +const int SVC_IO_BUFFER_SIZE = (16 * (1024)); +#endif // BUFSIZ +#else // IO_BUFFER_SIZE +const int SVC_IO_BUFFER_SIZE = (16 * (IO_BUFFER_SIZE)); +#endif // IO_BUFFER_SIZE + // forward decl. namespace Jrd { @@ -121,6 +132,8 @@ virtual void putChar(char tag, char val); // put raw bytes to svc_stdout virtual void putBytes(const UCHAR*, size_t); + // get raw bytes from svc_stdin + virtual ULONG getBytes(UCHAR*, ULONG); // append status_vector to service's status virtual void setServiceStatus(const ISC_STATUS* status_vector); // append error message to service's status @@ -218,8 +231,9 @@ bool checkForShutdown(); // Transfer data from svc_stdout into buffer void get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, USHORT* return_length); - // Designed to send output to a service - does nothing. - void put(const UCHAR* buffer, USHORT length); + // Sends stdin for a service + // Returns number of bytes service wants more + ULONG put(const UCHAR* buffer, ULONG length); // Increment circular buffer pointer static ULONG add_one(ULONG i); @@ -301,6 +315,8 @@ private: StatusStringsHelper svc_thread_strings; + Firebird::Semaphore svc_sem_empty, svc_sem_full; + //Service existence guard class ExistenceGuard { @@ -318,6 +334,23 @@ Firebird::Mutex svc_existence_lock; ExistenceGuard* svc_current_guard; + + // Data pipe from client to service + Firebird::Semaphore svc_stdin_semaphore; + Firebird::Mutex svc_stdin_mutex; + // Size of data, requested by service (set in getBytes, reset in put) + ULONG svc_stdin_size_requested; + // Buffer passed by service + UCHAR* svc_stdin_buffer; + // Size of data, preloaded by user (set in put, reset in getBytes) + ULONG svc_stdin_size_preload; + // Buffer for datam preloaded by user + Firebird::AutoPtr<UCHAR> svc_stdin_preload; + // Size of data, requested from user to preload (set in getBytes) + ULONG svc_stdin_preload_requested; + // Size of data, placed into svc_stdin_buffer (set in put) + ULONG svc_stdin_user_size; + static const ULONG PRELOAD_BUFFER_SIZE = SVC_IO_BUFFER_SIZE; }; } //namespace Jrd Modified: firebird/trunk/src/msgs/messages2.sql =================================================================== --- firebird/trunk/src/msgs/messages2.sql 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/msgs/messages2.sql 2012-06-20 11:47:30 UTC (rev 54643) @@ -2144,7 +2144,7 @@ ('gbak_file_outof_sequence', 'open_files', 'burp.c', NULL, 12, 263, NULL, 'file @1 out of sequence', NULL, NULL); ('gbak_join_file_missing', 'open_files', 'burp.c', NULL, 12, 264, NULL, 'can''t join -- one of the files missing', NULL, NULL); ('gbak_stdin_not_supptd', 'open_files', 'burp.c', NULL, 12, 265, NULL, ' standard input is not supported when using join operation', NULL, NULL); -('gbak_stdout_not_supptd', 'open_files', 'burp.c', NULL, 12, 266, NULL, 'standard output is not supported when using split operation', NULL, NULL); +('gbak_stdout_not_supptd', 'open_files', 'burp.c', NULL, 12, 266, NULL, 'standard output is not supported when using split operation or in verbose mode', NULL, NULL); ('gbak_bkup_corrupt', 'open_files', 'burp.c', NULL, 12, 267, NULL, 'backup file @1 might be corrupt', NULL, NULL); ('gbak_unk_db_file_spec', 'open_files', 'burp.c', NULL, 12, 268, NULL, 'database file specification missing', NULL, NULL); ('gbak_hdr_write_failed', 'MVOL_init_write', 'mvol.c', NULL, 12, 269, NULL, 'can''t write a header record to file @1', NULL, NULL); Modified: firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp =================================================================== --- firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -38,6 +38,7 @@ #include "../common/utils_proto.h" #include "../common/classes/MsgPrint.h" #include "../jrd/license.h" +#include "../burp/std_desc.h" using namespace Firebird; @@ -481,7 +482,7 @@ const SvcSwitches actionSwitch[] = { - {"action_backup", putSingleTag, backupOptions, isc_action_svc_backup, isc_info_svc_line}, + {"action_backup", putSingleTag, backupOptions, isc_action_svc_backup, isc_info_svc_to_eof}, {"action_restore", putSingleTag, restoreOptions, isc_action_svc_restore, isc_info_svc_line}, {"action_properties", putSingleTag, propertiesOptions, isc_action_svc_properties, 0}, {"action_repair", putSingleTag, repairOptions, isc_action_svc_repair, 0}, @@ -533,9 +534,23 @@ bool printData(const char*& p) { + static DESC binout = INVALID_HANDLE_VALUE; + if (binout == INVALID_HANDLE_VALUE) + { + binout = GBAK_STDOUT_DESC(); + } + string s; bool rc = getLine(s, p); - printf ("%s", s.c_str()); + if (rc) + { +#ifdef WIN_NT + DWORD cnt; + WriteFile(binout, s.c_str(), s.length(), &cnt, NULL); +#else + write(binout, s.c_str(), s.length()); +#endif + } return rc; } @@ -615,12 +630,14 @@ } }; -bool printInfo(const char* p, UserPrint& up) +bool printInfo(const char* p, size_t pSize, UserPrint& up, ULONG& stdinRq) { bool ret = false; bool ignoreTruncation = false; + stdinRq = 0; + const char* const end = p + pSize; - while (*p != isc_info_end) + while (p < end && *p != isc_info_end) { switch (*p++) { @@ -775,9 +792,10 @@ case isc_info_truncated: if (!ignoreTruncation) { - printf("%s\n", getMessage(18).c_str()); - return false; + printf("\n%s\n", getMessage(18).c_str()); } + fflush(stdout); + ret = true; break; case isc_info_svc_timeout: @@ -785,12 +803,24 @@ ret = true; break; + case isc_info_svc_stdin: + stdinRq = getNumeric(p); + if (stdinRq > 0) + { + ret = true; + } + break; + default: status_exception::raise(Arg::Gds(isc_fbsvcmgr_query_err) << Arg::Num(static_cast<unsigned char>(p[-1]))); +#ifdef DEV_BUILD + abort(); +#endif } } + fflush(stdout); return ret; } @@ -968,6 +998,8 @@ if (spbItems.getBufferLength() > 0) { + spbItems.insertTag(isc_info_svc_stdin); + // use one second timeout to poll service char send[16]; char* p = send; @@ -977,10 +1009,53 @@ *p++ = isc_info_end; char results[maxbuf]; - UserPrint up; + UserPrint uPrint; + ULONG stdinRequest = 0; + Array<char> stdinBuffer; do { - if (isc_service_query(status, &svc_handle, 0, p - send, send, + char *sendBlock = send; + USHORT sendSize = p - send; + if (stdinRequest) + { + --sendSize; + size_t len = sendSize; + len += (1 + 2 + stdinRequest); + if (len > MAX_USHORT - 1) + { + len = MAX_USHORT - 1; + stdinRequest = len - (1 + 2) - sendSize; + } + sendBlock = stdinBuffer.getBuffer(len + 1); + memcpy(sendBlock, send, sendSize); + + static DESC binIn = INVALID_HANDLE_VALUE; + if (binIn == INVALID_HANDLE_VALUE) + { + binIn = GBAK_STDIN_DESC(); + } + +#ifdef WIN_NT + DWORD n; + if (!ReadFile(binIn, &sendBlock[sendSize + 1 + 2], stdinRequest, &n, NULL)) +#else + int n = read(binIn, &sendBlock[sendSize + 1 + 2], stdinRequest); + if (n < 0) +#endif + { + perror("stdin"); + break; + } + stdinRequest = n; + sendBlock[sendSize] = isc_info_svc_line; + sendBlock[sendSize + 1] = stdinRequest; + sendBlock[sendSize + 2] = stdinRequest >> 8; + sendBlock [sendSize + 1 + 2 + stdinRequest] = isc_info_end; + sendSize += (1 + 2 + stdinRequest + 1); + + stdinRequest = 0; + } + if (isc_service_query(status, &svc_handle, 0, sendSize, sendBlock, static_cast<USHORT>(spbItems.getBufferLength()), reinterpret_cast<const char*>(spbItems.getBuffer()), sizeof(results), results)) @@ -989,10 +1064,14 @@ isc_service_detach(status, &svc_handle); return 1; } - } while (printInfo(results, up) && !terminated); + } while (printInfo(results, sizeof(results), uPrint, stdinRequest) && !terminated); } - isc_service_detach(status, &svc_handle); + if (isc_service_detach(status, &svc_handle)) + { + isc_print_status(status); + return 1; + } return 0; } catch (const Exception& e) Modified: firebird/trunk/src/utilities/ntrace/TracePluginImpl.cpp =================================================================== --- firebird/trunk/src/utilities/ntrace/TracePluginImpl.cpp 2012-06-20 09:39:11 UTC (rev 54642) +++ firebird/trunk/src/utilities/ntrace/TracePluginImpl.cpp 2012-06-20 11:47:30 UTC (rev 54643) @@ -903,12 +903,18 @@ case isc_info_svc_to_eof: recv_query.printf(NEWLINE "\t\t retrieve as much of the server output as will fit in the supplied buffer"); break; + case isc_info_svc_limbo_trans: recv_query.printf(NEWLINE "\t\t retrieve the limbo transactions"); break; + case isc_info_svc_get_users: recv_query.printf(NEWLINE "\t\t retrieve the user information"); break; + + case isc_info_svc_stdin: + recv_query.printf(NEWLINE "\t\t retrieve the size of data to send to the server"); + break; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |