From: <ale...@us...> - 2012-06-20 11:56:44
|
Revision: 54644 http://firebird.svn.sourceforge.net/firebird/?rev=54644&view=rev Author: alexpeshkoff Date: 2012-06-20 11:56:36 +0000 (Wed, 20 Jun 2012) Log Message: ----------- Backported implementation of CORE-2666: Make it possible to use API to do remote backups/restores Modified Paths: -------------- firebird/branches/B2_5_Release/doc/README.services_extension firebird/branches/B2_5_Release/src/burp/burp.cpp firebird/branches/B2_5_Release/src/burp/burp.h firebird/branches/B2_5_Release/src/burp/mvol.cpp firebird/branches/B2_5_Release/src/burp/spit.cpp firebird/branches/B2_5_Release/src/burp/spit.h firebird/branches/B2_5_Release/src/burp/std_desc.h firebird/branches/B2_5_Release/src/common/UtilSvc.cpp firebird/branches/B2_5_Release/src/common/UtilSvc.h firebird/branches/B2_5_Release/src/include/consts_pub.h firebird/branches/B2_5_Release/src/include/gen/msgs.h firebird/branches/B2_5_Release/src/jrd/svc.cpp firebird/branches/B2_5_Release/src/jrd/svc.h firebird/branches/B2_5_Release/src/lock/lock.cpp firebird/branches/B2_5_Release/src/msgs/messages2.sql firebird/branches/B2_5_Release/src/utilities/fbsvcmgr.cpp Modified: firebird/branches/B2_5_Release/doc/README.services_extension =================================================================== --- firebird/branches/B2_5_Release/doc/README.services_extension 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/doc/README.services_extension 2012-06-20 11:56:36 UTC (rev 54644) @@ -31,6 +31,7 @@ Return to normal state: fbsvcmgr service_mgr action_properties dbname employee prp_online_mode prp_sm_normal + 2) Services API extension - nbackup support. (Alex Peshkov, pes...@ma..., 2008) @@ -82,7 +83,7 @@ Stop trace session action - isc_action_svc_trace_stop + isc_action_svc_trace_stop parameter(s) isc_spb_trc_id : trace session ID, integer, mandatory @@ -96,7 +97,7 @@ Suspend trace session action - isc_action_svc_trace_suspend + isc_action_svc_trace_suspend parameter(s) isc_spb_trc_id : trace session ID, integer, mandatory @@ -109,7 +110,7 @@ Resume trace session action - isc_action_svc_trace_resume + isc_action_svc_trace_resume parameter(s) isc_spb_trc_id : trace session ID, integer, mandatory @@ -122,7 +123,7 @@ List of existing trace sessions action - isc_action_svc_trace_list + isc_action_svc_trace_list parameter(s) none @@ -134,7 +135,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 +150,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/branches/B2_5_Release/src/burp/burp.cpp =================================================================== --- firebird/branches/B2_5_Release/src/burp/burp.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/burp.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -1127,12 +1127,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()); + } } } @@ -1682,10 +1687,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; } @@ -1697,6 +1702,7 @@ #endif tdgbl->uSvc->setDataMode(true); fil->fil_fd = GBAK_STDOUT_DESC(); + tdgbl->stdIoMode = true; break; } else @@ -1801,10 +1807,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/branches/B2_5_Release/src/burp/burp.h =================================================================== --- firebird/branches/B2_5_Release/src/burp/burp.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/burp.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -815,7 +815,8 @@ defaultCollations(*getDefaultMemoryPool()), flag_on_line(true), uSvc(us), - firstMap(true) + firstMap(true), + stdIoMode(false) { // this is VERY dirty hack to keep current behaviour memset (&gbl_database_file_name, 0, @@ -977,6 +978,7 @@ bool flag_on_line; // indicates whether we will bring the database on-line Firebird::UtilSvc* uSvc; 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 @@ -988,17 +990,8 @@ indices */ // 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/branches/B2_5_Release/src/burp/mvol.cpp =================================================================== --- firebird/branches/B2_5_Release/src/burp/mvol.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/mvol.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -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; @@ -260,12 +266,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(); @@ -300,14 +342,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; } @@ -316,7 +350,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(); @@ -348,14 +382,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 @@ -512,169 +538,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_length > 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(false, 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; } + else + { + BURP_error(270, true); + // msg 270 free disk space exhausted + } + cnt = 0; + continue; + } - 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; - } - 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 @@ -956,27 +991,27 @@ if (strlen(tdgbl->mvol_old_file) > 0) { BURP_msg_get(225, msg, SafeArg() << (tdgbl->mvol_volume_count - 1) << tdgbl->mvol_old_file); - fprintf(term_out, msg); + fprintf(term_out, "%s", msg); BURP_msg_get(226, msg); // \tPress return to reopen that file, or type a new\n\tname // followed by return to open a different file.\n - fprintf(term_out, msg); + fprintf(term_out, "%s", msg); } else // First volume { BURP_msg_get(227, msg); // Type a file name to open and hit return - fprintf(term_out, msg); + fprintf(term_out, "%s", msg); } BURP_msg_get(228, msg); // " Name: " - fprintf(term_out, msg); + fprintf(term_out, "%s", msg); fflush(term_out); if (fgets(name, length, term_in) == NULL) { BURP_msg_get(229, msg); // \n\nERROR: Backup incomplete\n - fprintf(term_out, msg); + fprintf(term_out, "%s", msg); BURP_exit_local(FINI_ERROR, tdgbl); } @@ -1073,13 +1108,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 @@ -1140,7 +1183,7 @@ { BURP_msg_get(230, msg, SafeArg() << tdgbl->gbl_backup_start_time << buffer); // Expected backup start time %s, found %s\n - printf(msg); + printf("%s", msg); return false; } break; @@ -1174,7 +1217,7 @@ { BURP_msg_get(231, msg, SafeArg() << tdgbl->gbl_database_file_name << buffer); // Expected backup database %s, found %s\n - printf(msg); + printf("%s", msg); return false; } if (init_flag) @@ -1203,7 +1246,7 @@ { BURP_msg_get(232, msg, SafeArg() << tdgbl->mvol_volume_count << temp); // Expected volume number %d, found volume %d\n - printf(msg); + printf("%s", msg); return false; } break; Modified: firebird/branches/B2_5_Release/src/burp/spit.cpp =================================================================== --- firebird/branches/B2_5_Release/src/burp/spit.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/spit.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -46,7 +46,9 @@ # include <time.h> # endif #endif +//#include "../burp/burp.h" #include "../burp/spit.h" +#include "../burp/std_desc.h" #include "../burp/burpswi.h" #ifdef HAVE_UNISTD_H @@ -61,6 +63,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 { @@ -279,7 +328,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) { fprintf(stderr, "%s: progam fails to generate multi-volumn back-up files\n", prog_name); @@ -598,8 +647,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); return FB_FAILURE; @@ -665,8 +714,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); return FB_FAILURE; @@ -767,21 +816,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; @@ -790,12 +839,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: @@ -803,7 +852,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; } @@ -832,17 +881,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; @@ -850,12 +899,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: @@ -863,7 +912,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; } } @@ -888,7 +937,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(). @@ -946,16 +995,16 @@ 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; } @@ -963,7 +1012,7 @@ const TEXT* char_ptr1 = reinterpret_cast<char*>(*io_buffer); 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; @@ -991,13 +1040,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) @@ -1005,23 +1054,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: @@ -1029,7 +1078,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 } @@ -1114,11 +1163,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: @@ -1166,14 +1215,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; @@ -1181,7 +1230,7 @@ if (write_cnt == remaining_io_len) // write ok *flush_done = true; else { // could not write out all remaining data - close(output_fl_desc); + close_platf(output_fl_desc); *flush_done = false; } *byte_write = write_cnt; @@ -1207,18 +1256,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/branches/B2_5_Release/src/burp/spit.h =================================================================== --- firebird/branches/B2_5_Release/src/burp/spit.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/spit.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -42,8 +42,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/branches/B2_5_Release/src/burp/std_desc.h =================================================================== --- firebird/branches/B2_5_Release/src/burp/std_desc.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/burp/std_desc.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -61,4 +61,6 @@ #endif //WIN_NT +typedef DESC FILE_DESC; + #endif //GBAK_STD_DESC_H Modified: firebird/branches/B2_5_Release/src/common/UtilSvc.cpp =================================================================== --- firebird/branches/B2_5_Release/src/common/UtilSvc.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/common/UtilSvc.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -127,6 +127,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/branches/B2_5_Release/src/common/UtilSvc.h =================================================================== --- firebird/branches/B2_5_Release/src/common/UtilSvc.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/common/UtilSvc.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -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; @@ -71,10 +72,6 @@ virtual void hidePasswd(ArgvType&, int) = 0; virtual void getAddressPath(Firebird::ClumpletWriter& dpb) = 0; virtual bool finished() = 0; - void setDataMode(bool value) - { - usvcDataMode = value; - } virtual ~UtilSvc() { } @@ -100,6 +97,11 @@ switches += ' '; } + void setDataMode(bool value) + { + usvcDataMode = value; + } + public: ArgvType argv; bool usvcDataMode; Modified: firebird/branches/B2_5_Release/src/include/consts_pub.h =================================================================== --- firebird/branches/B2_5_Release/src/include/consts_pub.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/include/consts_pub.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -318,6 +318,7 @@ #define isc_info_svc_limbo_trans 66 /* Retrieve the limbo transactions */ #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_stdin 78 /* Returns size of data, needed as stdin for service */ /****************************************************** * Parameters for isc_action_{add|del|mod|disp)_user * Modified: firebird/branches/B2_5_Release/src/include/gen/msgs.h =================================================================== --- firebird/branches/B2_5_Release/src/include/gen/msgs.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/include/gen/msgs.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -852,7 +852,7 @@ {336331015, "file @1 out of sequence"}, /* 825, gbak_file_outof_sequence */ {336331016, "can't join -- one of the files missing"}, /* 826, gbak_join_file_missing */ {336331017, " standard input is not supported when using join operation"}, /* 827, gbak_stdin_not_supptd */ - {336331018, "standard output is not supported when using split operation"}, /* 828, gbak_stdout_not_supptd */ + {336331018, "standard output is not supported when using split operation or in verbose mode"}, /* 828, gbak_stdout_not_supptd */ {336331019, "backup file @1 might be corrupt"}, /* 829, gbak_bkup_corrupt */ {336331020, "database file specification missing"}, /* 830, gbak_unk_db_file_spec */ {336331021, "can't write a header record to file @1"}, /* 831, gbak_hdr_write_failed */ Modified: firebird/branches/B2_5_Release/src/jrd/svc.cpp =================================================================== --- firebird/branches/B2_5_Release/src/jrd/svc.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/jrd/svc.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -115,6 +115,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"; @@ -448,6 +449,7 @@ void Service::finish() { + svc_sem_full.release(); finish(SVC_finished); } @@ -657,7 +659,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; @@ -792,7 +794,9 @@ svc_trusted_login(getPool()), svc_trusted_role(false), svc_uses_security_database(false), svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool()), svc_network_protocol(getPool()), svc_remote_address(getPool()), svc_remote_process(getPool()), - svc_remote_pid(0), svc_current_guard(NULL) + svc_remote_pid(0), 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) { svc_trace_manager = NULL; memset(svc_status, 0, sizeof svc_status); @@ -1095,7 +1099,7 @@ AllServices& all(allServices); ULONG cnt = 0; - + // don't count already detached services for (size_t i = 0; i < all.getCount(); i++) { @@ -1135,14 +1139,16 @@ AllServices& all(allServices); unsigned int pos; - + // signal once for every still running service for (pos = 0; pos < all.getCount(); pos++) { 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(); ) { if (all[pos]->svc_flags & SVC_thd_running) @@ -1172,18 +1178,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++)) @@ -1199,10 +1209,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); @@ -1460,6 +1470,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) { @@ -1482,7 +1507,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); @@ -1523,7 +1548,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); @@ -1555,6 +1580,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 @@ -1570,7 +1600,7 @@ { *info++ = isc_info_svc_timeout; } - else + else //if (!svc_stdin_size_requested) { if (!length && !(svc_flags & SVC_finished)) { @@ -1600,6 +1630,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); @@ -1612,6 +1644,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(); @@ -1699,10 +1748,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); @@ -1931,7 +1980,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); @@ -1974,7 +2023,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); @@ -2373,19 +2422,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(1); + 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; } } @@ -2403,10 +2462,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(); } @@ -2427,6 +2488,7 @@ svc_flags &= ~SVC_timeout; } + bool flagFirst = true; while (length) { if ((empty() && (svc_flags & SVC_finished)) || checkForShutdown()) @@ -2436,7 +2498,24 @@ if (empty()) { - THREAD_SLEEP(1); + 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); @@ -2456,6 +2535,7 @@ while (head != svc_stdout_tail && length > 0) { + flagFirst = true; const UCHAR ch = svc_stdout[head]; head = add_one(head); length--; @@ -2476,15 +2556,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) @@ -2501,8 +2669,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/branches/B2_5_Release/src/jrd/svc.h =================================================================== --- firebird/branches/B2_5_Release/src/jrd/svc.h 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/jrd/svc.h 2012-06-20 11:56:36 UTC (rev 54644) @@ -36,7 +36,18 @@ #include "../common/classes/array.h" #include "../common/classes/SafeArg.h" #include "../common/UtilSvc.h" +#include "../burp/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. struct serv_entry; namespace Firebird { @@ -115,6 +126,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 @@ -211,8 +224,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); @@ -288,6 +302,8 @@ private: StatusStringsHelper svc_thread_strings; + Firebird::Semaphore svc_sem_empty, svc_sem_full; + //Service existence guard class ExistenceGuard { @@ -302,6 +318,23 @@ friend class ExistenceGuard; 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/branches/B2_5_Release/src/lock/lock.cpp =================================================================== --- firebird/branches/B2_5_Release/src/lock/lock.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/lock/lock.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -103,7 +103,7 @@ #endif #ifdef DEV_BUILD -#define VALIDATE_LOCK_TABLE +//#define VALIDATE_LOCK_TABLE #endif #ifdef DEV_BUILD Modified: firebird/branches/B2_5_Release/src/msgs/messages2.sql =================================================================== --- firebird/branches/B2_5_Release/src/msgs/messages2.sql 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/msgs/messages2.sql 2012-06-20 11:56:36 UTC (rev 54644) @@ -2432,7 +2432,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/branches/B2_5_Release/src/utilities/fbsvcmgr.cpp =================================================================== --- firebird/branches/B2_5_Release/src/utilities/fbsvcmgr.cpp 2012-06-20 11:47:30 UTC (rev 54643) +++ firebird/branches/B2_5_Release/src/utilities/fbsvcmgr.cpp 2012-06-20 11:56:36 UTC (rev 54644) @@ -40,6 +40,7 @@ #include "../common/utils_proto.h" #include "../common/classes/MsgPrint.h" #include "../jrd/license.h" +#include "../burp/std_desc.h" using namespace Firebird; @@ -475,7 +476,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}, @@ -527,9 +528,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; } @@ -599,12 +614,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++) { @@ -759,9 +776,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: @@ -769,12 +787,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; } @@ -916,6 +946,8 @@ if (spbItems.getBufferLength() > 0) { + spbItems.insertTag(isc_info_svc_stdin); + // use one second timeout to poll service char send[16]; char* p = send; @@ -925,10 +957,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)) @@ -937,10 +1012,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) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |