summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/bbackupd/BackupClientContext.cpp180
-rw-r--r--bin/bbackupd/BackupClientContext.h69
-rw-r--r--bin/bbackupd/BackupClientDirectoryRecord.cpp23
-rw-r--r--bin/bbackupd/BackupDaemon.cpp10
-rw-r--r--bin/bbstored/BackupCommands.cpp17
-rw-r--r--bin/bbstored/backupprotocol.txt7
-rw-r--r--configure.ac3
-rw-r--r--lib/backupclient/BackupDaemonConfigVerify.cpp1
-rw-r--r--lib/backupclient/BackupStoreFile.h35
-rw-r--r--lib/backupclient/BackupStoreFileDiff.cpp156
-rw-r--r--test/backupdiff/testbackupdiff.cpp28
-rw-r--r--test/backupstore/testbackupstore.cpp13
-rw-r--r--test/backupstorepatch/testbackupstorepatch.cpp13
13 files changed, 442 insertions, 113 deletions
diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp
index 38d0b98c..ae4e1cad 100644
--- a/bin/bbackupd/BackupClientContext.cpp
+++ b/bin/bbackupd/BackupClientContext.cpp
@@ -9,8 +9,14 @@
#include "Box.h"
-#ifndef WIN32
-#include <syslog.h>
+#ifdef HAVE_SYSLOG_H
+ #include <syslog.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+ #include <signal.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+ #include <sys/time.h>
#endif
#include "BoxPortsAndFiles.h"
@@ -22,6 +28,7 @@
#include "BackupStoreException.h"
#include "BackupDaemon.h"
#include "autogen_BackupProtocolClient.h"
+#include "BackupStoreFile.h"
#include "MemLeakFindOn.h"
@@ -48,7 +55,11 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS
mpNewIDMap(0),
mStorageLimitExceeded(false),
mpExcludeFiles(0),
- mpExcludeDirs(0)
+ mpExcludeDirs(0),
+ mbIsManaged(false),
+ mTimeMgmtEpoch(0),
+ mMaximumDiffTime(600),
+ mKeepAliveTime(0)
{
}
@@ -453,3 +464,166 @@ bool BackupClientContext::FindFilename(int64_t ObjectID, int64_t ContainingDirec
}
+// maximum time to spend diffing
+static int sMaximumDiffTime = 600;
+// maximum time of SSL inactivity (keep-alive interval)
+static int sKeepAliveTime = 0;
+
+void BackupClientContext::SetMaximumDiffingTime(int iSeconds)
+{
+ sMaximumDiffTime = iSeconds < 0 ? 0 : iSeconds;
+ TRACE1("Set maximum diffing time to %d seconds\n", sMaximumDiffTime);
+}
+
+void BackupClientContext::SetKeepAliveTime(int iSeconds)
+{
+ sKeepAliveTime = iSeconds < 0 ? 0 : iSeconds;
+ TRACE1("Set keep-alive time to %d seconds\n", sKeepAliveTime);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: static TimerSigHandler(int)
+// Purpose: Signal handler
+// Created: 19/3/04
+//
+// --------------------------------------------------------------------------
+static void TimerSigHandler(int iUnused)
+{
+ BackupStoreFile::DiffTimerExpired();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::ManageDiffProcess()
+// Purpose: Initiates a file diff control timer
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::ManageDiffProcess()
+{
+ if (mbIsManaged || !mpConnection)
+ return;
+
+ ASSERT(mTimeMgmtEpoch == 0);
+
+#ifdef PLATFORM_CYGWIN
+ ::signal(SIGALRM, TimerSigHandler);
+#else
+ ::signal(SIGVTALRM, TimerSigHandler);
+#endif // PLATFORM_CYGWIN
+
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+ //
+ //
+ //
+ if (sMaximumDiffTime <= 0 && sKeepAliveTime <= 0)
+ {
+ TRACE0("Diff control not requested - letting things run wild\n");
+ return;
+ }
+ else if (sMaximumDiffTime > 0 && sKeepAliveTime > 0)
+ {
+ timeout.it_value.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
+ timeout.it_interval.tv_sec = sKeepAliveTime < sMaximumDiffTime ? sKeepAliveTime : sMaximumDiffTime;
+ }
+ else
+ {
+ timeout.it_value.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
+ timeout.it_interval.tv_sec = sKeepAliveTime > 0 ? sKeepAliveTime : sMaximumDiffTime;
+ }
+
+ // avoid race
+ mTimeMgmtEpoch = time(NULL);
+
+#ifdef PLATFORM_CYGWIN
+ if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
+#else
+ if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
+#endif // PLATFORM_CYGWIN
+ {
+ mTimeMgmtEpoch = 0;
+
+ TRACE0("WARNING: couldn't set file diff control timeout\n");
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ mbIsManaged = true;
+ TRACE0("Initiated timer for file diff control\n");
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::UnManageDiffProcess()
+// Purpose: suspends file diff control timer
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::UnManageDiffProcess()
+{
+ if (!mbIsManaged /* don't test for active connection, just do it */)
+ return;
+
+ struct itimerval timeout;
+ memset(&timeout, 0, sizeof(timeout));
+
+#ifdef PLATFORM_CYGWIN
+ if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0)
+#else
+ if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
+#endif // PLATFORM_CYGWIN
+ {
+ TRACE0("WARNING: couldn't clear file diff control timeout\n");
+ THROW_EXCEPTION(BackupStoreException, Internal)
+ }
+
+ mbIsManaged = false;
+ mTimeMgmtEpoch = 0;
+
+ TRACE0("Suspended timer for file diff control\n");
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::DoKeepAlive()
+// Purpose: Does something inconsequential over the SSL link to keep it up
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+void BackupClientContext::DoKeepAlive()
+{
+ if (!mpConnection)
+ return;
+
+ mpConnection->QueryGetIsAlive();
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupClientContext::GetTimeMgmtEpoch()
+// Purpose: Returns the unix time when the diff was started, or zero
+// if the diff process is unmanaged.
+// Created: 04/19/2005
+//
+// --------------------------------------------------------------------------
+time_t BackupClientContext::GetTimeMgmtEpoch()
+{
+ return mTimeMgmtEpoch;
+}
+
+int BackupClientContext::GetMaximumDiffingTime()
+{
+ return mMaximumDiffTime;
+}
+
+int BackupClientContext::GetKeepaliveTime()
+{
+ return mKeepAliveTime;
+}
diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h
index 3933dbed..234868db 100644
--- a/bin/bbackupd/BackupClientContext.h
+++ b/bin/bbackupd/BackupClientContext.h
@@ -12,6 +12,7 @@
#include "BoxTime.h"
#include "BackupClientDeleteList.h"
+#include "BackupStoreFile.h"
#include "ExcludeList.h"
class TLSContext;
@@ -31,12 +32,12 @@ class BackupStoreFilenameClear;
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
-class BackupClientContext
+class BackupClientContext : public DiffTimer
{
public:
BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname,
int32_t AccountNumber, bool ExtendedLogging);
- ~BackupClientContext();
+ virtual ~BackupClientContext();
private:
BackupClientContext(const BackupClientContext &);
public:
@@ -134,6 +135,60 @@ public:
bool &rIsCurrentVersionOut, box_time_t *pModTimeOnServer = 0, box_time_t *pAttributesHashOnServer = 0,
BackupStoreFilenameClear *pLeafname = 0); // not const as may connect to server
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::SetMaximumDiffingTime()
+ // Purpose: Sets the maximum time that will be spent diffing a file
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ static void SetMaximumDiffingTime(int iSeconds);
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::SetKeepAliveTime()
+ // Purpose: Sets the time interval for repetitive keep-alive operation
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ static void SetKeepAliveTime(int iSeconds);
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::ManageDiffProcess()
+ // Purpose: Initiates an SSL connection/session keep-alive process
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ void ManageDiffProcess();
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::UnManageDiffProcess()
+ // Purpose: Suspends an SSL connection/session keep-alive process
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ void UnManageDiffProcess();
+
+ // --------------------------------------------------------------------------
+ //
+ // Function
+ // Name: BackupClientContext::DoKeepAlive()
+ // Purpose: Does something inconsequential over the SSL link to
+ // keep it up, implements DiffTimer interface
+ // Created: 04/19/2005
+ //
+ // --------------------------------------------------------------------------
+ virtual void DoKeepAlive();
+ virtual time_t GetTimeMgmtEpoch();
+ virtual int GetMaximumDiffingTime();
+ virtual int GetKeepaliveTime();
+
private:
BackupDaemon &mrDaemon;
TLSContext &mrTLSContext;
@@ -149,8 +204,16 @@ private:
bool mStorageLimitExceeded;
ExcludeList *mpExcludeFiles;
ExcludeList *mpExcludeDirs;
+
+ bool mbIsManaged;
+ // unix time when diff was started
+ time_t mTimeMgmtEpoch;
+ // maximum time to spend diffing, in seconds
+ int mMaximumDiffTime;
+ // maximum time of SSL inactivity (keep-alive interval), in seconds
+ int mKeepAliveTime;
+
};
#endif // BACKUPCLIENTCONTEXT__H
-
diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp
index 1a124333..3e8ceeb2 100644
--- a/bin/bbackupd/BackupClientDirectoryRecord.cpp
+++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp
@@ -1093,14 +1093,28 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
// Found an old version -- get the index
std::auto_ptr<IOStream> blockIndexStream(connection.ReceiveStream());
+ //
// Diff the file
+ //
+
+ rParams.mrContext.ManageDiffProcess();
+
bool isCompletelyDifferent = false;
- std::auto_ptr<IOStream> patchStream(BackupStoreFile::EncodeFileDiff(rFilename.c_str(),
+ std::auto_ptr<IOStream> patchStream(
+ BackupStoreFile::EncodeFileDiff(
+ rFilename.c_str(),
mObjectID, /* containing directory */
rStoreFilename, diffFromID, *blockIndexStream,
- connection.GetTimeout(), 0 /* not interested in the modification time */, &isCompletelyDifferent));
+ connection.GetTimeout(),
+ &rParams.mrContext, // DiffTimer implementation
+ 0 /* not interested in the modification time */,
+ &isCompletelyDifferent));
+ rParams.mrContext.UnManageDiffProcess();
+
+ //
// Upload the patch to the store
+ //
std::auto_ptr<BackupProtocolClientSuccess> stored(connection.QueryStoreFile(mObjectID, ModificationTime,
AttributesHash, isCompletelyDifferent?(0):(diffFromID), rStoreFilename, *patchStream));
@@ -1130,6 +1144,8 @@ int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::Syn
}
catch(BoxException &e)
{
+ rParams.mrContext.UnManageDiffProcess();
+
if(e.GetType() == ConnectionException::ExceptionType && e.GetSubType() == ConnectionException::Protocol_UnexpectedReply)
{
// Check and see what error the protocol has -- as it might be an error...
@@ -1210,6 +1226,3 @@ BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon, Backu
BackupClientDirectoryRecord::SyncParams::~SyncParams()
{
}
-
-
-
diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp
index 954504a6..07a8db4d 100644
--- a/bin/bbackupd/BackupDaemon.cpp
+++ b/bin/bbackupd/BackupDaemon.cpp
@@ -435,10 +435,14 @@ void BackupDaemon::Run2()
// Set up the keys for various things
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
- // Set maximum diffing time?
+ // max diffing time, keep-alive time
if(conf.KeyExists("MaximumDiffingTime"))
{
- BackupStoreFile::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime"));
+ BackupClientContext::SetMaximumDiffingTime(conf.GetKeyValueInt("MaximumDiffingTime"));
+ }
+ if(conf.KeyExists("KeepAliveTime"))
+ {
+ BackupClientContext::SetKeepAliveTime(conf.GetKeyValueInt("KeepAliveTime"));
}
// Setup various timings
@@ -885,7 +889,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
{
#ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
bool uidOK = true;
- ::syslog(LOG_ERR, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
+ ::syslog(LOG_WARNING, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
#else
// Security check -- does the process connecting to this socket have
// the same UID as this process?
diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp
index 1a021a58..35bc095d 100644
--- a/bin/bbstored/BackupCommands.cpp
+++ b/bin/bbstored/BackupCommands.cpp
@@ -859,3 +859,20 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(Bac
));
}
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupContext &)
+// Purpose: Return the amount of disc space used
+// Created: 19/4/04
+//
+// --------------------------------------------------------------------------
+std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext)
+{
+ CHECK_PHASE(Phase_Commands)
+
+ //
+ // NOOP
+ //
+ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerIsAlive());
+}
diff --git a/bin/bbstored/backupprotocol.txt b/bin/bbstored/backupprotocol.txt
index 39cb1fb3..106ac24c 100644
--- a/bin/bbstored/backupprotocol.txt
+++ b/bin/bbstored/backupprotocol.txt
@@ -219,3 +219,10 @@ AccountUsage 41 Reply
int64 BlocksSoftLimit
int64 BlocksHardLimit
int32 BlockSize
+
+GetIsAlive 42 Command(IsAlive)
+ # no data members
+
+IsAlive 43 Reply
+ # no data members
+
diff --git a/configure.ac b/configure.ac
index 3322cf91..2ed3812a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,7 +75,8 @@ AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS([execinfo.h netinet/in.h regex.h sys/types.h sys/xattr.h])
-AC_CHECK_HEADERS([sys/endian.h asm/byteorder.h])
+AC_CHECK_HEADERS([sys/endian.h asm/byteorder.h syslog.h signal.h sys/time.h])
+AC_CHECK_HEADERS([time.h])
### Checks for typedefs, structures, and compiler characteristics.
diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp
index eec2ceaf..f1d5bd16 100644
--- a/lib/backupclient/BackupDaemonConfigVerify.cpp
+++ b/lib/backupclient/BackupDaemonConfigVerify.cpp
@@ -84,6 +84,7 @@ static const ConfigurationVerifyKey verifyrootkeys[] =
{"ExtendedLogging", "no", ConfigTest_IsBool, 0}, // make value "yes" to enable in config file
{"CommandSocket", 0, 0, 0}, // not compulsory to have this
+ {"KeepAliveTime", 0, ConfigTest_IsInt, 0}, // optional
{"NotifyScript", 0, 0, 0}, // optional script to run when backup needs attention, eg store full
diff --git a/lib/backupclient/BackupStoreFile.h b/lib/backupclient/BackupStoreFile.h
index 446e9422..27b2ef98 100644
--- a/lib/backupclient/BackupStoreFile.h
+++ b/lib/backupclient/BackupStoreFile.h
@@ -38,6 +38,24 @@ typedef struct
// --------------------------------------------------------------------------
//
// Class
+// Name: DiffTimer
+// Purpose: Interface for classes that can keep track of diffing time,
+// and send SSL keepalive messages
+// Created: 2006/01/19
+//
+// --------------------------------------------------------------------------
+class DiffTimer
+{
+public:
+ virtual void DoKeepAlive() = 0;
+ virtual time_t GetTimeMgmtEpoch() = 0;
+ virtual int GetMaximumDiffingTime() = 0;
+ virtual int GetKeepaliveTime() = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
// Name: BackupStoreFile
// Purpose: Class to hold together utils for maniplating files.
// Created: 2003/08/28
@@ -95,9 +113,16 @@ public:
// Main interface
static std::auto_ptr<IOStream> EncodeFile(const char *Filename, int64_t ContainerID, const BackupStoreFilename &rStoreFilename, int64_t *pModificationTime = 0);
- static std::auto_ptr<IOStream> EncodeFileDiff(const char *Filename, int64_t ContainerID,
- const BackupStoreFilename &rStoreFilename, int64_t DiffFromObjectID, IOStream &rDiffFromBlockIndex,
- int Timeout, int64_t *pModificationTime = 0, bool *pIsCompletelyDifferent = 0);
+ static std::auto_ptr<IOStream> EncodeFileDiff
+ (
+ const char *Filename, int64_t ContainerID,
+ const BackupStoreFilename &rStoreFilename,
+ int64_t DiffFromObjectID, IOStream &rDiffFromBlockIndex,
+ int Timeout,
+ DiffTimer *pDiffTimer,
+ int64_t *pModificationTime = 0,
+ bool *pIsCompletelyDifferent = 0
+ );
static bool VerifyEncodedFileFormat(IOStream &rFile, int64_t *pDiffFromObjectIDOut = 0, int64_t *pContainerIDOut = 0);
static void CombineFile(IOStream &rDiff, IOStream &rDiff2, IOStream &rFrom, IOStream &rOut);
static void CombineDiffs(IOStream &rDiff1, IOStream &rDiff2, IOStream &rDiff2b, IOStream &rOut);
@@ -144,8 +169,7 @@ public:
free(a);
}
- // Limits
- static void SetMaximumDiffingTime(int Seconds);
+ static void DiffTimerExpired();
// Building blocks
class EncodingBuffer
@@ -192,4 +216,3 @@ public:
#include "MemLeakFindOff.h"
#endif // BACKUPSTOREFILE__H
-
diff --git a/lib/backupclient/BackupStoreFileDiff.cpp b/lib/backupclient/BackupStoreFileDiff.cpp
index c1d0492d..571f4351 100644
--- a/lib/backupclient/BackupStoreFileDiff.cpp
+++ b/lib/backupclient/BackupStoreFileDiff.cpp
@@ -11,11 +11,11 @@
#include <new>
#include <map>
-#include <signal.h>
-#ifdef WIN32
-#include <time.h>
-#else
-#include <sys/time.h>
+
+#ifdef HAVE_TIME_H
+ #include <time.h>
+#elif HAVE_SYS_TIME_H
+ #include <sys/time.h>
#endif
#include "BackupStoreFile.h"
@@ -43,33 +43,37 @@ using namespace BackupStoreFileCreation;
static void LoadIndex(IOStream &rBlockIndex, int64_t ThisID, BlocksAvailableEntry **ppIndex, int64_t &rNumBlocksOut, int Timeout, bool &rCanDiffFromThis);
static void FindMostUsedSizes(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES]);
-static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t> &rFoundBlocks, BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES]);
+static void SearchForMatchingBlocks(IOStream &rFile,
+ std::map<int64_t, int64_t> &rFoundBlocks, BlocksAvailableEntry *pIndex,
+ int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES],
+ DiffTimer *pDiffTimer);
static void SetupHashTable(BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t BlockSize, BlocksAvailableEntry **pHashTable);
static bool SecondStageMatch(BlocksAvailableEntry *pFirstInHashList, RollingChecksum &fastSum, uint8_t *pBeginnings, uint8_t *pEndings, int Offset, int32_t BlockSize, int64_t FileBlockNumber,
BlocksAvailableEntry *pIndex, std::map<int64_t, int64_t> &rFoundBlocks);
static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksAvailableEntry *pIndex, int64_t NumBlocks, std::map<int64_t, int64_t> &rFoundBlocks, int64_t SizeOfInputFile);
-// Avoid running on too long with diffs
-static int sMaximumDiffTime = 600; // maximum time to spend diffing
-static bool sDiffTimedOut = false;
-static bool sSetTimerSignelHandler = false;
-static void TimerSignalHandler(int signal);
-static void StartDiffTimer();
+// sDiffTimerExpired flags when the diff timer has expired. When true, the
+// diff routine should check the wall clock as soon as possible, to determine
+// whether it's time for a keepalive to be sent, or whether the diff has been
+// running for too long and should be terminated.
+static bool sDiffTimerExpired = false;
// --------------------------------------------------------------------------
//
// Function
-// Name: BackupStoreFile::SetMaximumDiffingTime(int)
-// Purpose: Sets the maximum time to spend diffing, in seconds. Time is
-// process virutal time.
-// Created: 19/3/04
+// Name: BackupStoreFile::DiffTimerExpired()
+// Purpose: Notifies BackupStoreFile object that the diff operation
+// timer has expired, which may mean that a keepalive should
+// be sent, or the diff should be terminated. Called from an
+// external timer, so it should not do more than set a flag.
+//
+// Created: 19/1/06
//
// --------------------------------------------------------------------------
-void BackupStoreFile::SetMaximumDiffingTime(int Seconds)
+void BackupStoreFile::DiffTimerExpired()
{
- sMaximumDiffTime = Seconds;
- TRACE1("Set maximum diffing time to %d seconds\n", Seconds);
+ sDiffTimerExpired = true;
}
@@ -139,9 +143,12 @@ void BackupStoreFile::MoveStreamPositionToBlockIndex(IOStream &rStream)
// Created: 12/1/04
//
// --------------------------------------------------------------------------
-std::auto_ptr<IOStream> BackupStoreFile::EncodeFileDiff(const char *Filename, int64_t ContainerID,
- const BackupStoreFilename &rStoreFilename, int64_t DiffFromObjectID, IOStream &rDiffFromBlockIndex,
- int Timeout, int64_t *pModificationTime, bool *pIsCompletelyDifferent)
+std::auto_ptr<IOStream> BackupStoreFile::EncodeFileDiff
+(
+ const char *Filename, int64_t ContainerID,
+ const BackupStoreFilename &rStoreFilename, int64_t DiffFromObjectID,
+ IOStream &rDiffFromBlockIndex, int Timeout, DiffTimer *pDiffTimer,
+ int64_t *pModificationTime, bool *pIsCompletelyDifferent)
{
// Is it a symlink?
{
@@ -180,9 +187,6 @@ std::auto_ptr<IOStream> BackupStoreFile::EncodeFileDiff(const char *Filename, in
// Pointer to recipe we're going to create
BackupStoreFileEncodeStream::Recipe *precipe = 0;
-
- // Start the timeout timer, so that the operation doesn't continue for ever
- StartDiffTimer();
try
{
@@ -204,7 +208,8 @@ std::auto_ptr<IOStream> BackupStoreFile::EncodeFileDiff(const char *Filename, in
// Get size of file
sizeOfInputFile = file.BytesLeftToRead();
// Find all those lovely matching blocks
- SearchForMatchingBlocks(file, foundBlocks, pindex, blocksInIndex, sizesToScan);
+ SearchForMatchingBlocks(file, foundBlocks, pindex,
+ blocksInIndex, sizesToScan, pDiffTimer);
// Is it completely different?
completelyDifferent = (foundBlocks.size() == 0);
@@ -475,8 +480,20 @@ static void FindMostUsedSizes(BlocksAvailableEntry *pIndex, int64_t NumBlocks, i
//
// --------------------------------------------------------------------------
static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t> &rFoundBlocks,
- BlocksAvailableEntry *pIndex, int64_t NumBlocks, int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES])
+ BlocksAvailableEntry *pIndex, int64_t NumBlocks,
+ int32_t Sizes[BACKUP_FILE_DIFF_MAX_BLOCK_SIZES], DiffTimer *pDiffTimer)
{
+ time_t TimeMgmtEpoch = 0;
+ int MaximumDiffingTime = 0;
+ int KeepAliveTime = 0;
+
+ if (pDiffTimer)
+ {
+ TimeMgmtEpoch = pDiffTimer->GetTimeMgmtEpoch();
+ MaximumDiffingTime = pDiffTimer->GetMaximumDiffingTime();
+ KeepAliveTime = pDiffTimer->GetKeepaliveTime();
+ }
+
std::map<int64_t, int32_t> goodnessOfFit;
// Allocate the hash lookup table
@@ -643,8 +660,39 @@ static void SearchForMatchingBlocks(IOStream &rFile, std::map<int64_t, int64_t>
// End this loop, so the final byte isn't used again
break;
}
+
+ bool DiffTimedOut = false;
+
+ if(sDiffTimerExpired)
+ {
+ ASSERT(TimeMgmtEpoch > 0);
+ ASSERT(pDiffTimer != NULL);
+
+ time_t tTotalRunIntvl = time(NULL) - TimeMgmtEpoch;
+
+ if(MaximumDiffingTime > 0 &&
+ tTotalRunIntvl >= MaximumDiffingTime)
+ {
+ TRACE0("MaximumDiffingTime reached - "
+ "suspending file diff\n");
+ DiffTimedOut = true;
+ }
+ else if(KeepAliveTime > 0)
+ {
+ TRACE0("KeepAliveTime reached - "
+ "initiating keep-alive\n");
+ pDiffTimer->DoKeepAlive();
+ }
+
+ sDiffTimerExpired = false;
+ }
+
+ int64_t NumBlocksFound = static_cast<int64_t>(
+ rFoundBlocks.size());
+ int64_t MaxBlocksFound = NumBlocks *
+ BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE;
- if(static_cast<int64_t>(rFoundBlocks.size()) > (NumBlocks * BACKUP_FILE_DIFF_MAX_BLOCK_FIND_MULTIPLE) || sDiffTimedOut)
+ if(NumBlocksFound > MaxBlocksFound || DiffTimedOut)
{
abortSearch = true;
break;
@@ -1005,55 +1053,3 @@ static void GenerateRecipe(BackupStoreFileEncodeStream::Recipe &rRecipe, BlocksA
}
#endif
}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: static TimerSignalHandler(int)
-// Purpose: Signal handler
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-void TimerSignalHandler(int signal)
-{
- sDiffTimedOut = true;
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: static StartDiffTimer()
-// Purpose: Starts the diff timeout timer
-// Created: 19/3/04
-//
-// --------------------------------------------------------------------------
-void StartDiffTimer()
-{
- // Set timer signal handler
- if(!sSetTimerSignelHandler)
- {
- ::signal(SIGVTALRM, TimerSignalHandler);
- sSetTimerSignelHandler = true;
- }
-
- struct itimerval timeout;
- // Don't want this to repeat
- timeout.it_interval.tv_sec = 0;
- timeout.it_interval.tv_usec = 0;
- // Single timeout after the specified number of seconds
- timeout.it_value.tv_sec = sMaximumDiffTime;
- timeout.it_value.tv_usec = 0;
- // Set timer
- if(::setitimer(ITIMER_VIRTUAL, &timeout, NULL) != 0)
- {
- TRACE0("WARNING: couldn't set diff timeout\n");
- }
-
- // Unset flag (last thing)
- sDiffTimedOut = false;
-}
-
-
-
diff --git a/test/backupdiff/testbackupdiff.cpp b/test/backupdiff/testbackupdiff.cpp
index 4408b69f..584dd70c 100644
--- a/test/backupdiff/testbackupdiff.cpp
+++ b/test/backupdiff/testbackupdiff.cpp
@@ -169,9 +169,17 @@ void test_diff(int from, int to, int new_blocks_expected, int old_blocks_expecte
{
BackupStoreFilenameClear f1name("filename");
FileStream out(to_diff, O_WRONLY | O_CREAT | O_EXCL);
- std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFileDiff(to_orig, 1 /* dir ID */, f1name,
- 1000 + from /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite,
- 0, &completelyDifferent));
+ std::auto_ptr<IOStream> encoded(
+ BackupStoreFile::EncodeFileDiff(
+ to_orig,
+ 1 /* dir ID */,
+ f1name,
+ 1000 + from /* object ID of the file diffing from */,
+ blockindex,
+ IOStream::TimeOutInfinite,
+ NULL, // DiffTimer interface
+ 0,
+ &completelyDifferent));
encoded->CopyStreamTo(out);
}
TEST_THAT(completelyDifferent == expect_completely_different);
@@ -443,9 +451,17 @@ int test(int argc, const char *argv[])
BackupStoreFilenameClear f1name("filename");
FileStream out("testfiles/f2.symlink.diff", O_WRONLY | O_CREAT | O_EXCL);
- std::auto_ptr<IOStream> encoded(BackupStoreFile::EncodeFileDiff("testfiles/f2.symlink", 1 /* dir ID */, f1name,
- 1001 /* object ID of the file diffing from */, blockindex, IOStream::TimeOutInfinite,
- 0, &completelyDifferent));
+ std::auto_ptr<IOStream> encoded(
+ BackupStoreFile::EncodeFileDiff(
+ "testfiles/f2.symlink",
+ 1 /* dir ID */,
+ f1name,
+ 1001 /* object ID of the file diffing from */,
+ blockindex,
+ IOStream::TimeOutInfinite,
+ NULL, // DiffTimer interface
+ 0,
+ &completelyDifferent));
encoded->CopyStreamTo(out);
}
TEST_THAT(completelyDifferent == true);
diff --git a/test/backupstore/testbackupstore.cpp b/test/backupstore/testbackupstore.cpp
index 1d297f16..f89d2ff7 100644
--- a/test/backupstore/testbackupstore.cpp
+++ b/test/backupstore/testbackupstore.cpp
@@ -1072,9 +1072,16 @@ int test_server(const char *hostname)
// Do the patching
bool isCompletelyDifferent = false;
int64_t modtime;
- std::auto_ptr<IOStream> patchstream(BackupStoreFile::EncodeFileDiff(TEST_FILE_FOR_PATCHING ".mod", BackupProtocolClientListDirectory::RootDirectory,
- uploads[UPLOAD_PATCH_EN].name, uploads[UPLOAD_PATCH_EN].allocated_objid, *blockIndexStream,
- IOStream::TimeOutInfinite, &modtime, &isCompletelyDifferent));
+ std::auto_ptr<IOStream> patchstream(
+ BackupStoreFile::EncodeFileDiff(
+ TEST_FILE_FOR_PATCHING ".mod",
+ BackupProtocolClientListDirectory::RootDirectory,
+ uploads[UPLOAD_PATCH_EN].name,
+ uploads[UPLOAD_PATCH_EN].allocated_objid,
+ *blockIndexStream,
+ IOStream::TimeOutInfinite,
+ NULL, // pointer to DiffTimer impl
+ &modtime, &isCompletelyDifferent));
TEST_THAT(isCompletelyDifferent == false);
// Sent this to a file, so we can check the size, rather than uploading it directly
{
diff --git a/test/backupstorepatch/testbackupstorepatch.cpp b/test/backupstorepatch/testbackupstorepatch.cpp
index a4a1ece3..5d77c3fd 100644
--- a/test/backupstorepatch/testbackupstorepatch.cpp
+++ b/test/backupstorepatch/testbackupstorepatch.cpp
@@ -376,10 +376,17 @@ int test(int argc, const char *argv[])
char filename[64];
::sprintf(filename, "testfiles/%d.test", f);
bool isCompletelyDifferent = false;
- std::auto_ptr<IOStream> patchStream(BackupStoreFile::EncodeFileDiff(filename,
+ std::auto_ptr<IOStream> patchStream(
+ BackupStoreFile::EncodeFileDiff(
+ filename,
BackupProtocolClientListDirectory::RootDirectory, /* containing directory */
- storeFilename, diffFromID, *blockIndexStream,
- protocol.GetTimeout(), 0 /* not interested in the modification time */, &isCompletelyDifferent));
+ storeFilename,
+ diffFromID,
+ *blockIndexStream,
+ protocol.GetTimeout(),
+ NULL, // DiffTimer impl
+ 0 /* not interested in the modification time */,
+ &isCompletelyDifferent));
// Upload the patch to the store
std::auto_ptr<BackupProtocolClientSuccess> stored(protocol.QueryStoreFile(