|
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.
|