diff options
Diffstat (limited to 'bin/bbstored')
-rw-r--r-- | bin/bbstored/BBStoreDHousekeeping.cpp | 16 | ||||
-rw-r--r-- | bin/bbstored/BackupCommands.cpp | 165 | ||||
-rw-r--r-- | bin/bbstored/BackupConstants.h | 2 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreContext.cpp (renamed from bin/bbstored/BackupContext.cpp) | 211 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreContext.h (renamed from bin/bbstored/BackupContext.h) | 50 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreDaemon.cpp | 34 | ||||
-rw-r--r-- | bin/bbstored/BackupStoreDaemon.h | 15 | ||||
-rw-r--r-- | bin/bbstored/HousekeepStoreAccount.cpp | 274 | ||||
-rw-r--r-- | bin/bbstored/HousekeepStoreAccount.h | 3 | ||||
-rw-r--r-- | bin/bbstored/backupprotocol.txt | 8 | ||||
-rwxr-xr-x | bin/bbstored/bbstored-config.in | 4 | ||||
-rw-r--r-- | bin/bbstored/bbstored.cpp | 2 |
12 files changed, 525 insertions, 259 deletions
diff --git a/bin/bbstored/BBStoreDHousekeeping.cpp b/bin/bbstored/BBStoreDHousekeeping.cpp index 16a1432a..1c1767ca 100644 --- a/bin/bbstored/BBStoreDHousekeeping.cpp +++ b/bin/bbstored/BBStoreDHousekeeping.cpp @@ -46,6 +46,12 @@ void BackupStoreDaemon::HousekeepingProcess() { RunHousekeepingIfNeeded(); + // Stop early? + if(StopRun()) + { + break; + } + // Calculate how long should wait before doing the next // housekeeping run int64_t timeNow = GetCurrentBoxTime(); @@ -155,7 +161,11 @@ void BackupStoreDaemon::RunHousekeepingIfNeeded() void BackupStoreDaemon::OnIdle() { - #ifdef WIN32 + if (!IsSingleProcess()) + { + return; + } + if (!mHousekeepingInited) { HousekeepingInit(); @@ -163,7 +173,6 @@ void BackupStoreDaemon::OnIdle() } RunHousekeepingIfNeeded(); - #endif } // -------------------------------------------------------------------------- @@ -193,7 +202,8 @@ bool BackupStoreDaemon::CheckForInterProcessMsg(int AccountNum, int MaximumWaitT std::string line; if(mInterProcessComms.GetLine(line, false /* no pre-processing */, MaximumWaitTime)) { - TRACE1("Housekeeping received command '%s' over interprocess comms\n", line.c_str()); + BOX_TRACE("Housekeeping received command '" << line << + "' over interprocess comms"); int account = 0; diff --git a/bin/bbstored/BackupCommands.cpp b/bin/bbstored/BackupCommands.cpp index bca52c04..38cda234 100644 --- a/bin/bbstored/BackupCommands.cpp +++ b/bin/bbstored/BackupCommands.cpp @@ -13,25 +13,25 @@ #include <sstream> #include "autogen_BackupProtocolServer.h" +#include "autogen_RaidFileException.h" #include "BackupConstants.h" -#include "BackupContext.h" -#include "CollectInBufferStream.h" +#include "BackupStoreContext.h" +#include "BackupStoreConstants.h" #include "BackupStoreDirectory.h" #include "BackupStoreException.h" #include "BackupStoreFile.h" -#include "StreamableMemBlock.h" -#include "BackupStoreConstants.h" -#include "RaidFileController.h" #include "BackupStoreInfo.h" -#include "RaidFileController.h" +#include "BufferedStream.h" +#include "CollectInBufferStream.h" #include "FileStream.h" #include "InvisibleTempFileStream.h" -#include "BufferedStream.h" +#include "RaidFileController.h" +#include "StreamableMemBlock.h" #include "MemLeakFindOn.h" #define CHECK_PHASE(phase) \ - if(rContext.GetPhase() != BackupContext::phase) \ + if(rContext.GetPhase() != BackupStoreContext::phase) \ { \ return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( \ BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_NotInRightProtocolPhase)); \ @@ -47,12 +47,12 @@ // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerVersion::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerVersion::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Return the current version, or an error if the requested version isn't allowed // Created: 2003/08/20 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Version) @@ -64,7 +64,7 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProto } // Mark the next phase - rContext.SetPhase(BackupContext::Phase_Login); + rContext.SetPhase(BackupStoreContext::Phase_Login); // Return our version return std::auto_ptr<ProtocolObject>(new BackupProtocolServerVersion(BACKUP_STORE_SERVER_VERSION)); @@ -73,12 +73,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerVersion::DoCommand(BackupProto // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerLogin::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerLogin::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Return the current version, or an error if the requested version isn't allowed // Created: 2003/08/20 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Login) @@ -131,7 +131,7 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco int64_t clientStoreMarker = rContext.GetClientStoreMarker(); // Mark the next phase - rContext.SetPhase(BackupContext::Phase_Commands); + rContext.SetPhase(BackupStoreContext::Phase_Commands); // Log login BOX_NOTICE("Login from Client ID " << @@ -151,12 +151,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerLogin::DoCommand(BackupProtoco // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerFinished::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerFinished::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Marks end of conversation (Protocol framework handles this) // Created: 2003/08/20 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { BOX_NOTICE("Session finished for Client ID " << BOX_FORMAT_ACCOUNT(rContext.GetClientID())); @@ -172,47 +172,72 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerFinished::DoCommand(BackupProt // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerListDirectory::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerListDirectory::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Command to list a directory // Created: 2003/09/02 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerListDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerListDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) - // Ask the context for a directory - const BackupStoreDirectory &rdir(rContext.GetDirectory(mObjectID)); - // Store the listing to a stream std::auto_ptr<CollectInBufferStream> stream(new CollectInBufferStream); - rdir.WriteToStream(*stream, mFlagsMustBeSet, mFlagsNotToBeSet, mSendAttributes, - false /* never send dependency info to the client */); + + try + { + // Ask the context for a directory + const BackupStoreDirectory &rdir( + rContext.GetDirectory(mObjectID)); + rdir.WriteToStream(*stream, mFlagsMustBeSet, + mFlagsNotToBeSet, mSendAttributes, + false /* never send dependency info to the client */); + } + catch (RaidFileException &e) + { + if (e.GetSubType() == RaidFileException::RaidFileDoesntExist) + { + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerError( + BackupProtocolServerError::ErrorType, + BackupProtocolServerError::Err_DoesNotExist)); + } + throw; + } + stream->SetForReading(); // Get the protocol to send the stream rProtocol.SendStreamAfterCommand(stream.release()); - return std::auto_ptr<ProtocolObject>(new BackupProtocolServerSuccess(mObjectID)); + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerSuccess(mObjectID)); } // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerStoreFile::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerStoreFile::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Command to store a file on the server // Created: 2003/09/02 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerStoreFile::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerStoreFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION + + std::auto_ptr<ProtocolObject> hookResult = + rContext.StartCommandHook(*this); + if(hookResult.get()) + { + return hookResult; + } // Check that the diff from file actually exists, if it's specified if(mDiffFromFileID != 0) { - if(!rContext.ObjectExists(mDiffFromFileID, BackupContext::ObjectExists_File)) + if(!rContext.ObjectExists(mDiffFromFileID, BackupStoreContext::ObjectExists_File)) { return std::auto_ptr<ProtocolObject>(new BackupProtocolServerError( BackupProtocolServerError::ErrorType, BackupProtocolServerError::Err_DiffFromFileDoesNotExist)); @@ -257,12 +282,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerStoreFile::DoCommand(BackupPro // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetObject::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerGetObject::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Command to get an arbitary object from the server // Created: 2003/09/03 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetObject::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -285,13 +310,13 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetObject::DoCommand(BackupPro // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetFile::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerGetFile::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Command to get an file object from the server -- may have to do a bit of // work to get the object. // Created: 2003/09/03 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -457,12 +482,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetFile::DoCommand(BackupProto // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerCreateDirectory::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerCreateDirectory::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Create directory command // Created: 2003/09/04 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerCreateDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerCreateDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -500,12 +525,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerCreateDirectory::DoCommand(Bac // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerChangeDirAttributes::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerChangeDirAttributes::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Change attributes on directory // Created: 2003/09/06 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerChangeDirAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerChangeDirAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -528,12 +553,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerChangeDirAttributes::DoCommand // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerSetReplacementFileAttributes::DoCommand(Protocol &, BackupContext &) +// Name: BackupProtocolServerSetReplacementFileAttributes::DoCommand(Protocol &, BackupStoreContext &) // Purpose: Change attributes on directory // Created: 2003/09/06 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerSetReplacementFileAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerSetReplacementFileAttributes::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -563,12 +588,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerSetReplacementFileAttributes:: // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Delete a file // Created: 2003/10/21 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteFile::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -585,12 +610,36 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteFile::DoCommand(BackupPr // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerUndeleteFile::DoCommand( +// BackupProtocolServer &, BackupStoreContext &) +// Purpose: Undelete a file +// Created: 2008-09-12 +// +// -------------------------------------------------------------------------- +std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteFile::DoCommand( + BackupProtocolServer &rProtocol, BackupStoreContext &rContext) +{ + CHECK_PHASE(Phase_Commands) + CHECK_WRITEABLE_SESSION + + // Context handles this + bool result = rContext.UndeleteFile(mObjectID, mInDirectory); + + // return the object ID or zero for not found + return std::auto_ptr<ProtocolObject>( + new BackupProtocolServerSuccess(result ? mObjectID : 0)); +} + + +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Delete a directory // Created: 2003/10/21 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -613,12 +662,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerDeleteDirectory::DoCommand(Bac // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Undelete a directory // Created: 23/11/03 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteDirectory::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -640,12 +689,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerUndeleteDirectory::DoCommand(B // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Command to set the client's store marker // Created: 2003/10/29 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerSetClientStoreMarker::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -661,12 +710,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerSetClientStoreMarker::DoComman // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Command to move an object from one directory to another // Created: 2003/11/12 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerMoveObject::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) CHECK_WRITEABLE_SESSION @@ -704,12 +753,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerMoveObject::DoCommand(BackupPr // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Command to find the name of an object // Created: 12/11/03 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -730,7 +779,7 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(Backu do { // Check the directory really exists - if(!rContext.ObjectExists(dirID, BackupContext::ObjectExists_Directory)) + if(!rContext.ObjectExists(dirID, BackupStoreContext::ObjectExists_Directory)) { return std::auto_ptr<ProtocolObject>(new BackupProtocolServerObjectName(BackupProtocolServerObjectName::NumNameElements_ObjectDoesntExist, 0, 0, 0)); } @@ -795,12 +844,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetObjectName::DoCommand(Backu // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Get the block index from a file, by ID // Created: 19/1/04 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByID::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -821,12 +870,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByID::DoCommand(B // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Get the block index from a file, by name within a directory // Created: 19/1/04 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByName::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -873,12 +922,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetBlockIndexByName::DoCommand // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Return the amount of disc space used // Created: 19/4/04 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) @@ -904,12 +953,12 @@ std::auto_ptr<ProtocolObject> BackupProtocolServerGetAccountUsage::DoCommand(Bac // -------------------------------------------------------------------------- // // Function -// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupContext &) +// Name: BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &, BackupStoreContext &) // Purpose: Return the amount of disc space used // Created: 19/4/04 // // -------------------------------------------------------------------------- -std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupContext &rContext) +std::auto_ptr<ProtocolObject> BackupProtocolServerGetIsAlive::DoCommand(BackupProtocolServer &rProtocol, BackupStoreContext &rContext) { CHECK_PHASE(Phase_Commands) diff --git a/bin/bbstored/BackupConstants.h b/bin/bbstored/BackupConstants.h index 515b3bcd..19d06a15 100644 --- a/bin/bbstored/BackupConstants.h +++ b/bin/bbstored/BackupConstants.h @@ -10,8 +10,6 @@ #ifndef BACKUPCONSTANTS__H #define BACKUPCONSTANTS__H -#define BACKUP_STORE_DEFAULT_ACCOUNT_DATABASE_FILE "/etc/box/backupstoreaccounts" - // 15 minutes to timeout (milliseconds) #define BACKUP_STORE_TIMEOUT (15*60*1000) diff --git a/bin/bbstored/BackupContext.cpp b/bin/bbstored/BackupStoreContext.cpp index 16388099..990be05d 100644 --- a/bin/bbstored/BackupContext.cpp +++ b/bin/bbstored/BackupStoreContext.cpp @@ -1,7 +1,7 @@ // -------------------------------------------------------------------------- // // File -// Name: BackupContext.cpp +// Name: BackupStoreContext.cpp // Purpose: Context for backup store server // Created: 2003/08/20 // @@ -11,7 +11,7 @@ #include <stdio.h> -#include "BackupContext.h" +#include "BackupStoreContext.h" #include "RaidFileWrite.h" #include "RaidFileRead.h" #include "BackupStoreDirectory.h" @@ -33,7 +33,7 @@ // Maximum number of directories to keep in the cache // When the cache is bigger than this, everything gets // deleted. -#ifdef NDEBUG +#ifdef BOX_RELEASE_BUILD #define MAX_CACHE_SIZE 32 #else #define MAX_CACHE_SIZE 2 @@ -48,31 +48,33 @@ // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::BackupContext() +// Name: BackupStoreContext::BackupStoreContext() // Purpose: Constructor // Created: 2003/08/20 // // -------------------------------------------------------------------------- -BackupContext::BackupContext(int32_t ClientID, BackupStoreDaemon &rDaemon) +BackupStoreContext::BackupStoreContext(int32_t ClientID, + HousekeepingInterface &rDaemon) : mClientID(ClientID), mrDaemon(rDaemon), mProtocolPhase(Phase_START), mClientHasAccount(false), mStoreDiscSet(-1), mReadOnly(true), - mSaveStoreInfoDelay(STORE_INFO_SAVE_DELAY) + mSaveStoreInfoDelay(STORE_INFO_SAVE_DELAY), + mpTestHook(NULL) { } // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::~BackupContext() +// Name: BackupStoreContext::~BackupStoreContext() // Purpose: Destructor // Created: 2003/08/20 // // -------------------------------------------------------------------------- -BackupContext::~BackupContext() +BackupStoreContext::~BackupStoreContext() { // Delete the objects in the cache for(std::map<int64_t, BackupStoreDirectory*>::iterator i(mDirectoryCache.begin()); i != mDirectoryCache.end(); ++i) @@ -85,12 +87,12 @@ BackupContext::~BackupContext() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::CleanUp() +// Name: BackupStoreContext::CleanUp() // Purpose: Clean up after a connection // Created: 16/12/03 // // -------------------------------------------------------------------------- -void BackupContext::CleanUp() +void BackupStoreContext::CleanUp() { // Make sure the store info is saved, if it has been loaded, isn't read only and has been modified if(mpStoreInfo.get() && !(mpStoreInfo->IsReadOnly()) && mpStoreInfo->IsModified()) @@ -102,12 +104,12 @@ void BackupContext::CleanUp() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::ReceivedFinishCommand() +// Name: BackupStoreContext::ReceivedFinishCommand() // Purpose: Called when the finish command is received by the protocol // Created: 16/12/03 // // -------------------------------------------------------------------------- -void BackupContext::ReceivedFinishCommand() +void BackupStoreContext::ReceivedFinishCommand() { if(!mReadOnly && mpStoreInfo.get()) { @@ -120,12 +122,12 @@ void BackupContext::ReceivedFinishCommand() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::AttemptToGetWriteLock() +// Name: BackupStoreContext::AttemptToGetWriteLock() // Purpose: Attempt to get a write lock for the store, and if so, unset the read only flags // Created: 2003/09/02 // // -------------------------------------------------------------------------- -bool BackupContext::AttemptToGetWriteLock() +bool BackupStoreContext::AttemptToGetWriteLock() { // Make the filename of the write lock file std::string writeLockFile; @@ -166,12 +168,12 @@ bool BackupContext::AttemptToGetWriteLock() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::LoadStoreInfo() +// Name: BackupStoreContext::LoadStoreInfo() // Purpose: Load the store info from disc // Created: 2003/09/03 // // -------------------------------------------------------------------------- -void BackupContext::LoadStoreInfo() +void BackupStoreContext::LoadStoreInfo() { if(mpStoreInfo.get() != 0) { @@ -195,12 +197,12 @@ void BackupContext::LoadStoreInfo() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::SaveStoreInfo(bool) +// Name: BackupStoreContext::SaveStoreInfo(bool) // Purpose: Potentially delayed saving of the store info // Created: 16/12/03 // // -------------------------------------------------------------------------- -void BackupContext::SaveStoreInfo(bool AllowDelay) +void BackupStoreContext::SaveStoreInfo(bool AllowDelay) { if(mpStoreInfo.get() == 0) { @@ -233,13 +235,13 @@ void BackupContext::SaveStoreInfo(bool AllowDelay) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::MakeObjectFilename(int64_t, std::string &, bool) +// Name: BackupStoreContext::MakeObjectFilename(int64_t, std::string &, bool) // Purpose: Create the filename of an object in the store, optionally creating the // containing directory if it doesn't already exist. // Created: 2003/09/02 // // -------------------------------------------------------------------------- -void BackupContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists) +void BackupStoreContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists) { // Delegate to utility function StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, mStoreDiscSet, rOutput, EnsureDirectoryExists); @@ -249,7 +251,7 @@ void BackupContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, b // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::GetDirectoryInternal(int64_t) +// Name: BackupStoreContext::GetDirectoryInternal(int64_t) // Purpose: Return a reference to a directory. Valid only until the // next time a function which affects directories is called. // Mainly this funciton, and creation of files. @@ -257,7 +259,7 @@ void BackupContext::MakeObjectFilename(int64_t ObjectID, std::string &rOutput, b // Created: 2003/09/02 // // -------------------------------------------------------------------------- -BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID) +BackupStoreDirectory &BackupStoreContext::GetDirectoryInternal(int64_t ObjectID) { // Get the filename std::string filename; @@ -277,9 +279,17 @@ BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID) if(revID == item->second->GetRevisionID()) { // Looks good... return the cached object + BOX_TRACE("Returning object " << + BOX_FORMAT_OBJECTID(ObjectID) << + " from cache, modtime = " << revID); return *(item->second); } + BOX_TRACE("Refreshing object " << + BOX_FORMAT_OBJECTID(ObjectID) << + " in cache, modtime changed from " << + item->second->GetRevisionID() << " to " << revID); + // Delete this cached object delete item->second; mDirectoryCache.erase(item); @@ -335,12 +345,12 @@ BackupStoreDirectory &BackupContext::GetDirectoryInternal(int64_t ObjectID) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::AllocateObjectID() +// Name: BackupStoreContext::AllocateObjectID() // Purpose: Allocate a new object ID, tolerant of failures to save store info // Created: 16/12/03 // // -------------------------------------------------------------------------- -int64_t BackupContext::AllocateObjectID() +int64_t BackupStoreContext::AllocateObjectID() { if(mpStoreInfo.get() == 0) { @@ -374,7 +384,8 @@ int64_t BackupContext::AllocateObjectID() // Mark that the store info should be saved as soon as possible mSaveStoreInfoDelay = 0; - TRACE1("When allocating object ID, found that %lld is already in use\n", id); + BOX_WARNING("When allocating object ID, found that " << + BOX_FORMAT_OBJECTID(id) << " is already in use"); } THROW_EXCEPTION(BackupStoreException, CouldNotFindUnusedIDDuringAllocation) @@ -384,13 +395,13 @@ int64_t BackupContext::AllocateObjectID() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::AddFile(IOStream &, int64_t, int64_t, int64_t, const BackupStoreFilename &, bool) +// Name: BackupStoreContext::AddFile(IOStream &, int64_t, int64_t, int64_t, const BackupStoreFilename &, bool) // Purpose: Add a file to the store, from a given stream, into a specified directory. // Returns object ID of the new file. // Created: 2003/09/03 // // -------------------------------------------------------------------------- -int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t ModificationTime, +int64_t BackupStoreContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t ModificationTime, int64_t AttributesHash, int64_t DiffFromFileID, const BackupStoreFilename &rFilename, bool MarkFileWithSameNameAsOldVersions) { @@ -672,18 +683,19 @@ int64_t BackupContext::AddFile(IOStream &rFile, int64_t InDirectory, int64_t Mod // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &) +// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &) // Purpose: Deletes a file, returning true if the file existed. Object ID returned too, set to zero if not found. // Created: 2003/10/21 // // -------------------------------------------------------------------------- -bool BackupContext::DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut) +bool BackupStoreContext::DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut) { // Essential checks! if(mpStoreInfo.get() == 0) { THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded) } + if(mReadOnly) { THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly) @@ -748,23 +760,102 @@ bool BackupContext::DeleteFile(const BackupStoreFilename &rFilename, int64_t InD RemoveDirectoryFromCache(InDirectory); throw; } - return fileExisted; } +// -------------------------------------------------------------------------- +// +// Function +// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &) +// Purpose: Deletes a file, returning true if the file existed. Object ID returned too, set to zero if not found. +// Created: 2003/10/21 +// +// -------------------------------------------------------------------------- +bool BackupStoreContext::UndeleteFile(int64_t ObjectID, int64_t InDirectory) +{ + // Essential checks! + if(mpStoreInfo.get() == 0) + { + THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded) + } + + if(mReadOnly) + { + THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly) + } + + // Find the directory the file is in (will exception if it fails) + BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory)); + + // Setup flags + bool fileExisted = false; + bool madeChanges = false; + + // Count of deleted blocks + int64_t blocksDel = 0; + + try + { + // Iterate through directory, only looking at files which have been deleted + BackupStoreDirectory::Iterator i(dir); + BackupStoreDirectory::Entry *e = 0; + while((e = i.Next(BackupStoreDirectory::Entry::Flags_File | + BackupStoreDirectory::Entry::Flags_Deleted, 0)) != 0) + { + // Compare name + if(e->GetObjectID() == ObjectID) + { + // Check that it's definitely already deleted + ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0); + // Clear deleted flag + e->RemoveFlags(BackupStoreDirectory::Entry::Flags_Deleted); + // Mark as made a change + madeChanges = true; + blocksDel -= e->GetSizeInBlocks(); + + // Is this the last version? + if((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0) + { + // Yes. It's been found. + fileExisted = true; + } + } + } + + // Save changes? + if(madeChanges) + { + // Save the directory back + SaveDirectory(dir, InDirectory); + + // Modify the store info, and write + mpStoreInfo->ChangeBlocksInDeletedFiles(blocksDel); + + // Maybe postponed save of store info + SaveStoreInfo(); + } + } + catch(...) + { + RemoveDirectoryFromCache(InDirectory); + throw; + } + + return fileExisted; +} // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::RemoveDirectoryFromCache(int64_t) +// Name: BackupStoreContext::RemoveDirectoryFromCache(int64_t) // Purpose: Remove directory from cache // Created: 2003/09/04 // // -------------------------------------------------------------------------- -void BackupContext::RemoveDirectoryFromCache(int64_t ObjectID) +void BackupStoreContext::RemoveDirectoryFromCache(int64_t ObjectID) { std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID)); if(item != mDirectoryCache.end()) @@ -780,12 +871,12 @@ void BackupContext::RemoveDirectoryFromCache(int64_t ObjectID) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::SaveDirectory(BackupStoreDirectory &, int64_t) +// Name: BackupStoreContext::SaveDirectory(BackupStoreDirectory &, int64_t) // Purpose: Save directory back to disc, update time in cache // Created: 2003/09/04 // // -------------------------------------------------------------------------- -void BackupContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID) +void BackupStoreContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID) { if(mpStoreInfo.get() == 0) { @@ -842,12 +933,12 @@ void BackupContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::AddDirectory(int64_t, const BackupStoreFilename &, bool &) +// Name: BackupStoreContext::AddDirectory(int64_t, const BackupStoreFilename &, bool &) // Purpose: Creates a directory (or just returns the ID of an existing one). rAlreadyExists set appropraitely. // Created: 2003/09/04 // // -------------------------------------------------------------------------- -int64_t BackupContext::AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists) +int64_t BackupStoreContext::AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists) { if(mpStoreInfo.get() == 0) { @@ -936,12 +1027,12 @@ int64_t BackupContext::AddDirectory(int64_t InDirectory, const BackupStoreFilena // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &, bool) +// Name: BackupStoreContext::DeleteFile(const BackupStoreFilename &, int64_t, int64_t &, bool) // Purpose: Recusively deletes a directory (or undeletes if Undelete = true) // Created: 2003/10/21 // // -------------------------------------------------------------------------- -void BackupContext::DeleteDirectory(int64_t ObjectID, bool Undelete) +void BackupStoreContext::DeleteDirectory(int64_t ObjectID, bool Undelete) { // Essential checks! if(mpStoreInfo.get() == 0) @@ -1018,12 +1109,12 @@ void BackupContext::DeleteDirectory(int64_t ObjectID, bool Undelete) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::DeleteDirectoryRecurse(BackupStoreDirectory &, int64_t) +// Name: BackupStoreContext::DeleteDirectoryRecurse(BackupStoreDirectory &, int64_t) // Purpose: Private. Deletes a directory depth-first recusively. // Created: 2003/10/21 // // -------------------------------------------------------------------------- -void BackupContext::DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete) +void BackupStoreContext::DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete) { try { @@ -1120,12 +1211,12 @@ void BackupContext::DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDel // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::ChangeDirAttributes(int64_t, const StreamableMemBlock &, int64_t) +// Name: BackupStoreContext::ChangeDirAttributes(int64_t, const StreamableMemBlock &, int64_t) // Purpose: Change the attributes of a directory // Created: 2003/09/06 // // -------------------------------------------------------------------------- -void BackupContext::ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime) +void BackupStoreContext::ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime) { if(mpStoreInfo.get() == 0) { @@ -1157,12 +1248,12 @@ void BackupContext::ChangeDirAttributes(int64_t Directory, const StreamableMemBl // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::ChangeFileAttributes(int64_t, int64_t, const StreamableMemBlock &, int64_t) +// Name: BackupStoreContext::ChangeFileAttributes(int64_t, int64_t, const StreamableMemBlock &, int64_t) // Purpose: Sets the attributes on a directory entry. Returns true if the object existed, false if it didn't. // Created: 2003/09/06 // // -------------------------------------------------------------------------- -bool BackupContext::ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut) +bool BackupStoreContext::ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut) { if(mpStoreInfo.get() == 0) { @@ -1222,12 +1313,12 @@ bool BackupContext::ChangeFileAttributes(const BackupStoreFilename &rFilename, i // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::ObjectExists(int64_t) +// Name: BackupStoreContext::ObjectExists(int64_t) // Purpose: Test to see if an object of this ID exists in the store // Created: 2003/09/03 // // -------------------------------------------------------------------------- -bool BackupContext::ObjectExists(int64_t ObjectID, int MustBe) +bool BackupStoreContext::ObjectExists(int64_t ObjectID, int MustBe) { if(mpStoreInfo.get() == 0) { @@ -1293,12 +1384,12 @@ bool BackupContext::ObjectExists(int64_t ObjectID, int MustBe) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::OpenObject(int64_t) +// Name: BackupStoreContext::OpenObject(int64_t) // Purpose: Opens an object // Created: 2003/09/03 // // -------------------------------------------------------------------------- -std::auto_ptr<IOStream> BackupContext::OpenObject(int64_t ObjectID) +std::auto_ptr<IOStream> BackupStoreContext::OpenObject(int64_t ObjectID) { if(mpStoreInfo.get() == 0) { @@ -1315,12 +1406,12 @@ std::auto_ptr<IOStream> BackupContext::OpenObject(int64_t ObjectID) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::GetClientStoreMarker() +// Name: BackupStoreContext::GetClientStoreMarker() // Purpose: Retrieve the client store marker // Created: 2003/10/29 // // -------------------------------------------------------------------------- -int64_t BackupContext::GetClientStoreMarker() +int64_t BackupStoreContext::GetClientStoreMarker() { if(mpStoreInfo.get() == 0) { @@ -1334,12 +1425,12 @@ int64_t BackupContext::GetClientStoreMarker() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::GetStoreDiscUsageInfo(int64_t &, int64_t &, int64_t &) +// Name: BackupStoreContext::GetStoreDiscUsageInfo(int64_t &, int64_t &, int64_t &) // Purpose: Get disc usage info from store info // Created: 1/1/04 // // -------------------------------------------------------------------------- -void BackupContext::GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit) +void BackupStoreContext::GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit) { if(mpStoreInfo.get() == 0) { @@ -1355,12 +1446,12 @@ void BackupContext::GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocks // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::HardLimitExceeded() +// Name: BackupStoreContext::HardLimitExceeded() // Purpose: Returns true if the hard limit has been exceeded // Created: 1/1/04 // // -------------------------------------------------------------------------- -bool BackupContext::HardLimitExceeded() +bool BackupStoreContext::HardLimitExceeded() { if(mpStoreInfo.get() == 0) { @@ -1374,12 +1465,12 @@ bool BackupContext::HardLimitExceeded() // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::SetClientStoreMarker(int64_t) +// Name: BackupStoreContext::SetClientStoreMarker(int64_t) // Purpose: Sets the client store marker, and commits it to disc // Created: 2003/10/29 // // -------------------------------------------------------------------------- -void BackupContext::SetClientStoreMarker(int64_t ClientStoreMarker) +void BackupStoreContext::SetClientStoreMarker(int64_t ClientStoreMarker) { if(mpStoreInfo.get() == 0) { @@ -1398,12 +1489,12 @@ void BackupContext::SetClientStoreMarker(int64_t ClientStoreMarker) // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::MoveObject(int64_t, int64_t, int64_t, const BackupStoreFilename &, bool) +// Name: BackupStoreContext::MoveObject(int64_t, int64_t, int64_t, const BackupStoreFilename &, bool) // Purpose: Move an object (and all objects with the same name) from one directory to another // Created: 12/11/03 // // -------------------------------------------------------------------------- -void BackupContext::MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject) +void BackupStoreContext::MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject) { if(mReadOnly) { @@ -1643,12 +1734,12 @@ void BackupContext::MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int6 // -------------------------------------------------------------------------- // // Function -// Name: BackupContext::GetBackupStoreInfo() +// Name: BackupStoreContext::GetBackupStoreInfo() // Purpose: Return the backup store info object, exception if it isn't loaded // Created: 19/4/04 // // -------------------------------------------------------------------------- -const BackupStoreInfo &BackupContext::GetBackupStoreInfo() const +const BackupStoreInfo &BackupStoreContext::GetBackupStoreInfo() const { if(mpStoreInfo.get() == 0) { diff --git a/bin/bbstored/BackupContext.h b/bin/bbstored/BackupStoreContext.h index 18f2f25c..4cfdb601 100644 --- a/bin/bbstored/BackupContext.h +++ b/bin/bbstored/BackupStoreContext.h @@ -1,7 +1,7 @@ // -------------------------------------------------------------------------- // // File -// Name: BackupContext.h +// Name: BackupStoreContext.h // Purpose: Context for backup store server // Created: 2003/08/20 // @@ -15,6 +15,7 @@ #include <memory> #include "NamedLock.h" +#include "ProtocolObject.h" #include "Utils.h" class BackupStoreDirectory; @@ -22,23 +23,31 @@ class BackupStoreFilename; class BackupStoreDaemon; class BackupStoreInfo; class IOStream; +class BackupProtocolObject; class StreamableMemBlock; +class HousekeepingInterface +{ + public: + virtual ~HousekeepingInterface() { } + virtual void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) = 0; +}; + // -------------------------------------------------------------------------- // // Class -// Name: BackupContext +// Name: BackupStoreContext // Purpose: Context for backup store server // Created: 2003/08/20 // // -------------------------------------------------------------------------- -class BackupContext +class BackupStoreContext { public: - BackupContext(int32_t ClientID, BackupStoreDaemon &rDaemon); - ~BackupContext(); + BackupStoreContext(int32_t ClientID, HousekeepingInterface &rDaemon); + ~BackupStoreContext(); private: - BackupContext(const BackupContext &rToCopy); + BackupStoreContext(const BackupStoreContext &rToCopy); public: void ReceivedFinishCommand(); @@ -83,7 +92,7 @@ public: // -------------------------------------------------------------------------- // // Function - // Name: BackupContext::GetDirectory(int64_t) + // Name: BackupStoreContext::GetDirectory(int64_t) // Purpose: Return a reference to a directory. Valid only until the // next time a function which affects directories is called. // Mainly this funciton, and creation of files. @@ -103,6 +112,7 @@ public: void ChangeDirAttributes(int64_t Directory, const StreamableMemBlock &Attributes, int64_t AttributesModTime); bool ChangeFileAttributes(const BackupStoreFilename &rFilename, int64_t InDirectory, const StreamableMemBlock &Attributes, int64_t AttributesHash, int64_t &rObjectIDOut); bool DeleteFile(const BackupStoreFilename &rFilename, int64_t InDirectory, int64_t &rObjectIDOut); + bool UndeleteFile(int64_t ObjectID, int64_t InDirectory); void DeleteDirectory(int64_t ObjectID, bool Undelete = false); void MoveObject(int64_t ObjectID, int64_t MoveFromDirectory, int64_t MoveToDirectory, const BackupStoreFilename &rNewFilename, bool MoveAllWithSameName, bool AllowMoveOverDeletedObject); @@ -129,7 +139,7 @@ private: private: int32_t mClientID; - BackupStoreDaemon &mrDaemon; + HousekeepingInterface &mrDaemon; int mProtocolPhase; bool mClientHasAccount; std::string mStoreRoot; // has final directory separator @@ -143,6 +153,30 @@ private: // Directory cache std::map<int64_t, BackupStoreDirectory*> mDirectoryCache; + +public: + class TestHook + { + public: + virtual std::auto_ptr<ProtocolObject> StartCommand(BackupProtocolObject& + rCommand) = 0; + virtual ~TestHook() { } + }; + void SetTestHook(TestHook& rTestHook) + { + mpTestHook = &rTestHook; + } + std::auto_ptr<ProtocolObject> StartCommandHook(BackupProtocolObject& rCommand) + { + if(mpTestHook) + { + return mpTestHook->StartCommand(rCommand); + } + return std::auto_ptr<ProtocolObject>(); + } + +private: + TestHook* mpTestHook; }; #endif // BACKUPCONTEXT__H diff --git a/bin/bbstored/BackupStoreDaemon.cpp b/bin/bbstored/BackupStoreDaemon.cpp index 28e28176..4de0a078 100644 --- a/bin/bbstored/BackupStoreDaemon.cpp +++ b/bin/bbstored/BackupStoreDaemon.cpp @@ -17,7 +17,7 @@ #include <syslog.h> #endif -#include "BackupContext.h" +#include "BackupStoreContext.h" #include "BackupStoreDaemon.h" #include "BackupStoreConfigVerify.h" #include "autogen_BackupProtocolServer.h" @@ -43,7 +43,8 @@ BackupStoreDaemon::BackupStoreDaemon() mHaveForkedHousekeeping(false), mIsHousekeepingProcess(false), mHousekeepingInited(false), - mInterProcessComms(mInterProcessCommsSocket) + mInterProcessComms(mInterProcessCommsSocket), + mpTestHook(NULL) { } @@ -171,11 +172,12 @@ void BackupStoreDaemon::Run() const Configuration &config(GetConfiguration()); mExtendedLogging = config.GetKeyValueBool("ExtendedLogging"); -#ifdef WIN32 - // Housekeeping runs synchronously on Win32 -#else - // Fork off housekeeping daemon -- must only do this the first time Run() is called - if(!mHaveForkedHousekeeping) + // Fork off housekeeping daemon -- must only do this the first + // time Run() is called. Housekeeping runs synchronously on Win32 + // because IsSingleProcess() is always true + +#ifndef WIN32 + if(!IsSingleProcess() && !mHaveForkedHousekeeping) { // Open a socket pair for communication int sv[2] = {-1,-1}; @@ -205,7 +207,9 @@ void BackupStoreDaemon::Run() // Log that housekeeping started BOX_INFO("Housekeeping process started"); // Ignore term and hup - // Parent will handle these and alert the child via the socket, don't want to randomly die + // Parent will handle these and alert the + // child via the socket, don't want to + // randomly die! ::signal(SIGHUP, SIG_IGN); ::signal(SIGTERM, SIG_IGN); } @@ -317,10 +321,18 @@ void BackupStoreDaemon::Connection2(SocketStreamTLS &rStream) } // Make ps listings clearer - SetProcessTitle("client %08x", id); + std::ostringstream tag; + tag << "client=" << BOX_FORMAT_ACCOUNT(id); + SetProcessTitle(tag.str().c_str()); + Logging::Tagger tagWithClientID(tag.str()); // Create a context, using this ID - BackupContext context(id, *this); + BackupStoreContext context(id, *this); + + if (mpTestHook) + { + context.SetTestHook(*mpTestHook); + } // See if the client has an account? if(mpAccounts && mpAccounts->AccountExists(id)) @@ -352,7 +364,7 @@ void BackupStoreDaemon::LogConnectionStats(const char *commonName, const SocketStreamTLS &s) { // Log the amount of data transferred - BOX_INFO("Connection statistics for " << commonName << ":" + BOX_NOTICE("Connection statistics for " << commonName << ":" " IN=" << s.GetBytesRead() << " OUT=" << s.GetBytesWritten() << " TOTAL=" << (s.GetBytesRead() + s.GetBytesWritten())); diff --git a/bin/bbstored/BackupStoreDaemon.h b/bin/bbstored/BackupStoreDaemon.h index 387a1d5b..a5d216f4 100644 --- a/bin/bbstored/BackupStoreDaemon.h +++ b/bin/bbstored/BackupStoreDaemon.h @@ -13,6 +13,7 @@ #include "ServerTLS.h" #include "BoxPortsAndFiles.h" #include "BackupConstants.h" +#include "BackupStoreContext.h" #include "IOStreamGetLine.h" class BackupStoreAccounts; @@ -27,7 +28,8 @@ class HousekeepStoreAccount; // Created: 2003/08/20 // // -------------------------------------------------------------------------- -class BackupStoreDaemon : public ServerTLS<BOX_PORT_BBSTORED> +class BackupStoreDaemon : public ServerTLS<BOX_PORT_BBSTORED>, + HousekeepingInterface { friend class HousekeepStoreAccount; @@ -38,7 +40,7 @@ private: BackupStoreDaemon(const BackupStoreDaemon &rToCopy); public: - // For BackupContext to communicate with housekeeping process + // For BackupStoreContext to communicate with housekeeping process void SendMessageToHousekeepingProcess(const void *Msg, int MsgLen) { #ifndef WIN32 @@ -81,6 +83,15 @@ private: void HousekeepingInit(); void RunHousekeepingIfNeeded(); int64_t mLastHousekeepingRun; + +public: + void SetTestHook(BackupStoreContext::TestHook& rTestHook) + { + mpTestHook = &rTestHook; + } + +private: + BackupStoreContext::TestHook* mpTestHook; }; diff --git a/bin/bbstored/HousekeepStoreAccount.cpp b/bin/bbstored/HousekeepStoreAccount.cpp index 9f4239e7..dbb9b544 100644 --- a/bin/bbstored/HousekeepStoreAccount.cpp +++ b/bin/bbstored/HousekeepStoreAccount.cpp @@ -85,16 +85,19 @@ void HousekeepStoreAccount::DoHousekeeping() { // Attempt to lock the account std::string writeLockFilename; - StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, writeLockFilename); + StoreStructure::MakeWriteLockFilename(mStoreRoot, mStoreDiscSet, + writeLockFilename); NamedLock writeLock; - if(!writeLock.TryAndGetLock(writeLockFilename.c_str(), 0600 /* restrictive file permissions */)) + if(!writeLock.TryAndGetLock(writeLockFilename.c_str(), + 0600 /* restrictive file permissions */)) { // Couldn't lock the account -- just stop now return; } // Load the store info to find necessary info for the housekeeping - std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(mAccountID, mStoreRoot, mStoreDiscSet, false /* Read/Write */)); + std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(mAccountID, + mStoreRoot, mStoreDiscSet, false /* Read/Write */)); // Calculate how much should be deleted mDeletionSizeTarget = info->GetBlocksUsed() - info->GetBlocksSoftLimit(); @@ -104,14 +107,18 @@ void HousekeepStoreAccount::DoHousekeeping() } // Scan the directory for potential things to delete - // This will also remove elegiable items marked with RemoveASAP + // This will also remove eligible items marked with RemoveASAP bool continueHousekeeping = ScanDirectory(BACKUPSTORE_ROOT_DIRECTORY_ID); - // If scan directory stopped for some reason, probably parent instructed to teminate, stop now. + // If scan directory stopped for some reason, probably parent + // instructed to terminate, stop now. if(!continueHousekeeping) { - // If any files were marked "delete now", then update the size of the store. - if(mBlocksUsedDelta != 0 || mBlocksInOldFilesDelta != 0 || mBlocksInDeletedFilesDelta != 0) + // If any files were marked "delete now", then update + // the size of the store. + if(mBlocksUsedDelta != 0 || + mBlocksInOldFilesDelta != 0 || + mBlocksInDeletedFilesDelta != 0) { info->ChangeBlocksUsed(mBlocksUsedDelta); info->ChangeBlocksInOldFiles(mBlocksInOldFilesDelta); @@ -124,8 +131,8 @@ void HousekeepStoreAccount::DoHousekeeping() return; } - // Log any difference in opinion between the values recorded in the store info, and - // the values just calculated for space usage. + // Log any difference in opinion between the values recorded in + // the store info, and the values just calculated for space usage. // BLOCK { int64_t used = info->GetBlocksUsed(); @@ -133,9 +140,12 @@ void HousekeepStoreAccount::DoHousekeeping() int64_t usedDeleted = info->GetBlocksInDeletedFiles(); int64_t usedDirectories = info->GetBlocksInDirectories(); - // If the counts were wrong, taking into account RemoveASAP items deleted, log a message - if((used + mBlocksUsedDelta) != mBlocksUsed || (usedOld + mBlocksInOldFilesDelta) != mBlocksInOldFiles - || (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles || usedDirectories != mBlocksInDirectories) + // If the counts were wrong, taking into account RemoveASAP + // items deleted, log a message + if((used + mBlocksUsedDelta) != mBlocksUsed + || (usedOld + mBlocksInOldFilesDelta) != mBlocksInOldFiles + || (usedDeleted + mBlocksInDeletedFilesDelta) != mBlocksInDeletedFiles + || usedDirectories != mBlocksInDirectories) { // Log this BOX_ERROR("Housekeeping on account " << @@ -153,18 +163,25 @@ void HousekeepStoreAccount::DoHousekeeping() } // If the current values don't match, store them - if(used != mBlocksUsed || usedOld != mBlocksInOldFiles - || usedDeleted != mBlocksInDeletedFiles || usedDirectories != (mBlocksInDirectories + mBlocksInDirectoriesDelta)) + if(used != mBlocksUsed + || usedOld != mBlocksInOldFiles + || usedDeleted != mBlocksInDeletedFiles + || usedDirectories != (mBlocksInDirectories + mBlocksInDirectoriesDelta)) { // Set corrected values in store info - info->CorrectAllUsedValues(mBlocksUsed, mBlocksInOldFiles, mBlocksInDeletedFiles, mBlocksInDirectories + mBlocksInDirectoriesDelta); + info->CorrectAllUsedValues(mBlocksUsed, + mBlocksInOldFiles, mBlocksInDeletedFiles, + mBlocksInDirectories + mBlocksInDirectoriesDelta); info->Save(); } } - // Reset the delta counts for files, as they will include RemoveASAP flagged files deleted - // during the initial scan. - int64_t removeASAPBlocksUsedDelta = mBlocksUsedDelta; // keep for reporting + // Reset the delta counts for files, as they will include + // RemoveASAP flagged files deleted during the initial scan. + + // keep for reporting + int64_t removeASAPBlocksUsedDelta = mBlocksUsedDelta; + mBlocksUsedDelta = 0; mBlocksInOldFilesDelta = 0; mBlocksInDeletedFilesDelta = 0; @@ -172,7 +189,8 @@ void HousekeepStoreAccount::DoHousekeeping() // Go and delete items from the accounts bool deleteInterrupted = DeleteFiles(); - // If that wasn't interrupted, remove any empty directories which are also marked as deleted in their containing directory + // If that wasn't interrupted, remove any empty directories which + // are also marked as deleted in their containing directory if(!deleteInterrupted) { deleteInterrupted = DeleteEmptyDirectories(); @@ -190,8 +208,9 @@ void HousekeepStoreAccount::DoHousekeeping() (deleteInterrupted?" and was interrupted":"")); } - // Make sure the delta's won't cause problems if the counts are really wrong, and - // it wasn't fixed because the store was updated during the scan. + // Make sure the delta's won't cause problems if the counts are + // really wrong, and it wasn't fixed because the store was + // updated during the scan. if(mBlocksUsedDelta < (0 - info->GetBlocksUsed())) { mBlocksUsedDelta = (0 - info->GetBlocksUsed()); @@ -218,7 +237,8 @@ void HousekeepStoreAccount::DoHousekeeping() // Save the store info back info->Save(); - // Explicity release the lock (would happen automatically on going out of scope, included for code clarity) + // Explicity release the lock (would happen automatically on + // going out of scope, included for code clarity) writeLock.ReleaseLock(); } @@ -243,8 +263,9 @@ void HousekeepStoreAccount::MakeObjectFilename(int64_t ObjectID, std::string &rF // // Function // Name: HousekeepStoreAccount::ScanDirectory(int64_t) -// Purpose: Private. Scan a directory for potenitally deleteable items, and -// add them to the list. Returns true if the scan should continue. +// Purpose: Private. Scan a directory for potentially deleteable +// items, and add them to the list. Returns true if the +// scan should continue. // Created: 11/12/03 // // -------------------------------------------------------------------------- @@ -253,9 +274,12 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) #ifndef WIN32 if((--mCountUntilNextInterprocessMsgCheck) <= 0) { - mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; + mCountUntilNextInterprocessMsgCheck = + POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; + // Check for having to stop - if(mrDaemon.CheckForInterProcessMsg(mAccountID)) // include account ID here as the specified account is locked + // Include account ID here as the specified account is locked + if(mrDaemon.CheckForInterProcessMsg(mAccountID)) { // Need to abort now return false; @@ -268,7 +292,8 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) MakeObjectFilename(ObjectID, objectFilename); // Open it. - std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(mStoreDiscSet, objectFilename)); + std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(mStoreDiscSet, + objectFilename)); // Add the size of the directory on disc to the size being calculated int64_t originalDirSizeInBlocks = dirStream->GetDiscUsageInBlocks(); @@ -290,8 +315,8 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // BLOCK { - // Remove any files which are marked for removal as soon as they become old - // or deleted. + // Remove any files which are marked for removal as soon + // as they become old or deleted. bool deletedSomething = false; do { @@ -324,7 +349,8 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Add files to the list of potential deletions // map to count the distance from the mark - std::map<std::pair<BackupStoreFilename, int32_t>, int32_t> markVersionAges; + typedef std::pair<std::string, int32_t> version_t; + std::map<version_t, int32_t> markVersionAges; // map of pair (filename, mark number) -> version age // NOTE: use a reverse iterator to allow the distance from mark stuff to work @@ -342,7 +368,10 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) // Work out ages of this version from the last mark int32_t enVersionAge = 0; - std::map<std::pair<BackupStoreFilename, int32_t>, int32_t>::iterator enVersionAgeI(markVersionAges.find(std::pair<BackupStoreFilename, int32_t>(en->GetName(), en->GetMarkNumber()))); + std::map<version_t, int32_t>::iterator enVersionAgeI( + markVersionAges.find( + version_t(en->GetName().GetEncodedFilename(), + en->GetMarkNumber()))); if(enVersionAgeI != markVersionAges.end()) { enVersionAge = enVersionAgeI->second + 1; @@ -350,7 +379,7 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) } else { - markVersionAges[std::pair<BackupStoreFilename, int32_t>(en->GetName(), en->GetMarkNumber())] = enVersionAge; + markVersionAges[version_t(en->GetName().GetEncodedFilename(), en->GetMarkNumber())] = enVersionAge; } // enVersionAge is now the age of this version. @@ -364,6 +393,9 @@ bool HousekeepStoreAccount::ScanDirectory(int64_t ObjectID) d.mSizeInBlocks = en->GetSizeInBlocks(); d.mMarkNumber = en->GetMarkNumber(); d.mVersionAgeWithinMark = enVersionAge; + d.mIsFlagDeleted = (enFlags & + BackupStoreDirectory::Entry::Flags_Deleted) + ? true : false; // Add it to the list mPotentialDeletions.insert(d); @@ -541,6 +573,10 @@ bool HousekeepStoreAccount::DeleteFiles() // Delete the file DeleteFile(i->mInDirectory, i->mObjectID, dir, dirFilename, dirSizeInBlocksOrig); + BOX_INFO("Housekeeping removed " << + (i->mIsFlagDeleted ? "deleted" : "old") << + " file " << BOX_FORMAT_OBJECTID(i->mObjectID) << + " from dir " << BOX_FORMAT_OBJECTID(i->mInDirectory)); // Stop if the deletion target has been matched or exceeded // (checking here rather than at the beginning will tend to reduce the @@ -786,99 +822,115 @@ bool HousekeepStoreAccount::DeleteEmptyDirectories() continue; } - // Load up the directory to potentially delete - std::string dirFilename; - BackupStoreDirectory dir; - int64_t dirSizeInBlocks = 0; - { - MakeObjectFilename(*i, dirFilename); - // Check it actually exists (just in case it gets added twice to the list) - if(!RaidFileRead::FileExists(mStoreDiscSet, dirFilename)) - { - // doesn't exist, next! - continue; - } - // load - std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(mStoreDiscSet, dirFilename)); - dirSizeInBlocks = dirStream->GetDiscUsageInBlocks(); - dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); - } + DeleteEmptyDirectory(*i, toExamine); + } - // Make sure this directory is actually empty - if(dir.GetNumberOfEntries() != 0) - { - // Not actually empty, try next one - continue; - } + // Remove contents of empty directories + mEmptyDirectories.clear(); + // Swap in new, so it's examined next time round + mEmptyDirectories.swap(toExamine); + } + + // Not interrupted + return false; +} - // Candiate for deletion... open containing directory - std::string containingDirFilename; - BackupStoreDirectory containingDir; - int64_t containingDirSizeInBlocksOrig = 0; - { - MakeObjectFilename(dir.GetContainerID(), containingDirFilename); - std::auto_ptr<RaidFileRead> containingDirStream(RaidFileRead::Open(mStoreDiscSet, containingDirFilename)); - containingDirSizeInBlocksOrig = containingDirStream->GetDiscUsageInBlocks(); - containingDir.ReadFromStream(*containingDirStream, IOStream::TimeOutInfinite); - } +void HousekeepStoreAccount::DeleteEmptyDirectory(int64_t dirId, + std::vector<int64_t>& rToExamine) +{ + // Load up the directory to potentially delete + std::string dirFilename; + BackupStoreDirectory dir; + int64_t dirSizeInBlocks = 0; - // Find the entry - BackupStoreDirectory::Entry *pdirentry = containingDir.FindEntryByID(dir.GetObjectID()); - if((pdirentry != 0) && ((pdirentry->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0)) - { - // Should be deleted - containingDir.DeleteEntry(dir.GetObjectID()); + // BLOCK + { + MakeObjectFilename(dirId, dirFilename); + // Check it actually exists (just in case it gets + // added twice to the list) + if(!RaidFileRead::FileExists(mStoreDiscSet, dirFilename)) + { + // doesn't exist, next! + return; + } + // load + std::auto_ptr<RaidFileRead> dirStream( + RaidFileRead::Open(mStoreDiscSet, dirFilename)); + dirSizeInBlocks = dirStream->GetDiscUsageInBlocks(); + dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite); + } - // Is the containing dir now a candidate for deletion? - if(containingDir.GetNumberOfEntries() == 0) - { - toExamine.push_back(containingDir.GetObjectID()); - } + // Make sure this directory is actually empty + if(dir.GetNumberOfEntries() != 0) + { + // Not actually empty, try next one + return; + } - // Write revised parent directory - RaidFileWrite writeDir(mStoreDiscSet, containingDirFilename); - writeDir.Open(true /* allow overwriting */); - containingDir.WriteToStream(writeDir); + // Candidate for deletion... open containing directory + std::string containingDirFilename; + BackupStoreDirectory containingDir; + int64_t containingDirSizeInBlocksOrig = 0; + { + MakeObjectFilename(dir.GetContainerID(), containingDirFilename); + std::auto_ptr<RaidFileRead> containingDirStream( + RaidFileRead::Open(mStoreDiscSet, + containingDirFilename)); + containingDirSizeInBlocksOrig = + containingDirStream->GetDiscUsageInBlocks(); + containingDir.ReadFromStream(*containingDirStream, + IOStream::TimeOutInfinite); + } - // get the disc usage (must do this before commiting it) - int64_t dirSize = writeDir.GetDiscUsageInBlocks(); + // Find the entry + BackupStoreDirectory::Entry *pdirentry = + containingDir.FindEntryByID(dir.GetObjectID()); + if((pdirentry != 0) && ((pdirentry->GetFlags() & BackupStoreDirectory::Entry::Flags_Deleted) != 0)) + { + // Should be deleted + containingDir.DeleteEntry(dir.GetObjectID()); - // Commit directory - writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY); + // Is the containing dir now a candidate for deletion? + if(containingDir.GetNumberOfEntries() == 0) + { + rToExamine.push_back(containingDir.GetObjectID()); + } - // adjust usage counts for this directory - if(dirSize > 0) - { - int64_t adjust = dirSize - containingDirSizeInBlocksOrig; - mBlocksUsedDelta += adjust; - mBlocksInDirectoriesDelta += adjust; - } + // Write revised parent directory + RaidFileWrite writeDir(mStoreDiscSet, containingDirFilename); + writeDir.Open(true /* allow overwriting */); + containingDir.WriteToStream(writeDir); - // Delete the directory itself - { - RaidFileWrite del(mStoreDiscSet, dirFilename); - del.Delete(); - } + // get the disc usage (must do this before commiting it) + int64_t dirSize = writeDir.GetDiscUsageInBlocks(); - // And adjust usage counts for the directory that's just been deleted - mBlocksUsedDelta -= dirSizeInBlocks; - mBlocksInDirectoriesDelta -= dirSizeInBlocks; + // Commit directory + writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY); - // Update count - ++mEmptyDirectoriesDeleted; - } + // adjust usage counts for this directory + if(dirSize > 0) + { + int64_t adjust = dirSize - containingDirSizeInBlocksOrig; + mBlocksUsedDelta += adjust; + mBlocksInDirectoriesDelta += adjust; } - // Remove contents of empty directories - mEmptyDirectories.clear(); - // Swap in new, so it's examined next time round - mEmptyDirectories.swap(toExamine); - } - - // Not interrupted - return false; -} + // Delete the directory itself + { + RaidFileWrite del(mStoreDiscSet, dirFilename); + del.Delete(); + } + BOX_INFO("Housekeeping removed empty deleted dir " << + BOX_FORMAT_OBJECTID(dirId)); + // And adjust usage counts for the directory that's + // just been deleted + mBlocksUsedDelta -= dirSizeInBlocks; + mBlocksInDirectoriesDelta -= dirSizeInBlocks; + // Update count + ++mEmptyDirectoriesDeleted; + } +} diff --git a/bin/bbstored/HousekeepStoreAccount.h b/bin/bbstored/HousekeepStoreAccount.h index 6c8f251d..5c2a9885 100644 --- a/bin/bbstored/HousekeepStoreAccount.h +++ b/bin/bbstored/HousekeepStoreAccount.h @@ -42,6 +42,8 @@ private: bool ScanDirectory(int64_t ObjectID); bool DeleteFiles(); bool DeleteEmptyDirectories(); + void DeleteEmptyDirectory(int64_t dirId, + std::vector<int64_t>& rToExamine); void DeleteFile(int64_t InDirectory, int64_t ObjectID, BackupStoreDirectory &rDirectory, const std::string &rDirectoryFilename, int64_t OriginalDirSizeInBlocks); private: @@ -52,6 +54,7 @@ private: int64_t mSizeInBlocks; int32_t mMarkNumber; int32_t mVersionAgeWithinMark; // 0 == current, 1 latest old version, etc + bool mIsFlagDeleted; // false for files flagged "Old" } DelEn; struct DelEnCompare diff --git a/bin/bbstored/backupprotocol.txt b/bin/bbstored/backupprotocol.txt index 62d837ff..3eca514a 100644 --- a/bin/bbstored/backupprotocol.txt +++ b/bin/bbstored/backupprotocol.txt @@ -4,7 +4,7 @@ Name Backup IdentString Box-Backup:v=C -ServerContextClass BackupContext BackupContext.h +ServerContextClass BackupStoreContext BackupStoreContext.h ClientType Filename BackupStoreFilenameClear BackupStoreFilenameClear.h ServerType Filename BackupStoreFilename BackupStoreFilename.h @@ -204,6 +204,12 @@ GetBlockIndexByName 35 Command(Success) # stream of the block index follows the reply if found ID != 0 +UndeleteFile 36 Command(Success) + int64 InDirectory + int64 ObjectID + # will return 0 if the object couldn't be found in the specified directory + + # ------------------------------------------------------------------------------------- # Information commands # ------------------------------------------------------------------------------------- diff --git a/bin/bbstored/bbstored-config.in b/bin/bbstored/bbstored-config.in index 33cfb39a..5ad96d50 100755 --- a/bin/bbstored/bbstored-config.in +++ b/bin/bbstored/bbstored-config.in @@ -196,7 +196,7 @@ TimeBetweenHousekeeping = 900 Server { - PidFile = @localstatedir_expanded@/bbstored.pid + PidFile = @localstatedir_expanded@/run/bbstored.pid User = $username ListenAddresses = inet:$server CertificateFile = $certificate @@ -234,7 +234,7 @@ What you need to do now... 4) Create accounts with bbstoreaccounts 5) Start the backup store daemon with the command - @bindir_expanded@/bbstored$daemon_args + @sbindir_expanded@/bbstored$daemon_args in /etc/rc.local, or your local equivalent. =================================================================== diff --git a/bin/bbstored/bbstored.cpp b/bin/bbstored/bbstored.cpp index 54858dd4..21a9e5f1 100644 --- a/bin/bbstored/bbstored.cpp +++ b/bin/bbstored/bbstored.cpp @@ -18,7 +18,7 @@ int main(int argc, const char *argv[]) { MAINHELPER_START - Logging::SetProgramName("Box Backup (bbstored)"); + Logging::SetProgramName("bbstored"); Logging::ToConsole(true); Logging::ToSyslog (true); |