Changeset 2541 for box/trunk/bin


Ignore:
Timestamp:
28/06/2009 20:29:10 (3 years ago)
Author:
chris
Message:

Make housekeeping check the object reference counts and fix them if
they're wrong.

Add a callback interface to decouple housekeeping from the
BackupStoreDaemon?, allowing it to be called directly in tests.

Allow housekeeping callers to request it to keep trying forever to get a
lock on the account if it's busy.

Location:
box/trunk/bin/bbstored
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • box/trunk/bin/bbstored/BBStoreDHousekeeping.cpp

    r2281 r2541  
    109109                                 
    110110                                // Do housekeeping on this account 
    111                                 HousekeepStoreAccount housekeeping(*i, rootDir, discSet, *this); 
     111                                HousekeepStoreAccount housekeeping(*i, rootDir, 
     112                                        discSet, this); 
    112113                                housekeeping.DoHousekeeping(); 
    113114                        } 
  • box/trunk/bin/bbstored/BackupStoreDaemon.h

    r2262 r2541  
    1515#include "BackupConstants.h" 
    1616#include "BackupStoreContext.h" 
     17#include "HousekeepStoreAccount.h" 
    1718#include "IOStreamGetLine.h" 
    1819 
    1920class BackupStoreAccounts; 
    2021class BackupStoreAccountDatabase; 
    21 class HousekeepStoreAccount; 
    2222 
    2323// -------------------------------------------------------------------------- 
     
    3030// -------------------------------------------------------------------------- 
    3131class BackupStoreDaemon : public ServerTLS<BOX_PORT_BBSTORED>, 
    32         HousekeepingInterface 
     32        HousekeepingInterface, HousekeepingCallback 
    3333{ 
    34         friend class HousekeepStoreAccount; 
    35  
    3634public: 
    3735        BackupStoreDaemon(); 
     
    6563        // Housekeeping functions 
    6664        void HousekeepingProcess(); 
    67         bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0); 
    6865 
    6966        void LogConnectionStats(const char *commonName, const SocketStreamTLS &s); 
     67 
     68public: 
     69        // HousekeepingInterface implementation 
     70        virtual bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0); 
    7071 
    7172private: 
  • box/trunk/bin/bbstored/HousekeepStoreAccount.cpp

    r2481 r2541  
    4040// 
    4141// -------------------------------------------------------------------------- 
    42 HousekeepStoreAccount::HousekeepStoreAccount(int AccountID, const std::string &rStoreRoot, int StoreDiscSet, BackupStoreDaemon &rDaemon) 
     42HousekeepStoreAccount::HousekeepStoreAccount(int AccountID, 
     43        const std::string &rStoreRoot, int StoreDiscSet, 
     44        HousekeepingCallback* pHousekeepingCallback) 
    4345        : mAccountID(AccountID), 
    4446          mStoreRoot(rStoreRoot), 
    4547          mStoreDiscSet(StoreDiscSet), 
    46           mrDaemon(rDaemon), 
     48          mpHousekeepingCallback(pHousekeepingCallback), 
    4749          mDeletionSizeTarget(0), 
    4850          mPotentialDeletionsTotalSize(0), 
     
    5860          mFilesDeleted(0), 
    5961          mEmptyDirectoriesDeleted(0), 
     62          mSuppressRefCountChangeWarnings(false), 
    6063          mCountUntilNextInterprocessMsgCheck(POLL_INTERPROCESS_MSG_CHECK_FREQUENCY) 
    6164{ 
     
    8285// 
    8386// -------------------------------------------------------------------------- 
    84 void HousekeepStoreAccount::DoHousekeeping() 
     87void HousekeepStoreAccount::DoHousekeeping(bool KeepTryingForever) 
    8588{ 
    8689        // Attempt to lock the account 
     
    9295                0600 /* restrictive file permissions */)) 
    9396        { 
    94                 // Couldn't lock the account -- just stop now 
    95                 return; 
     97                if(KeepTryingForever) 
     98                { 
     99                        BOX_WARNING("Failed to lock account for housekeeping, " 
     100                                "still trying..."); 
     101                        while(!writeLock.TryAndGetLock(writeLockFilename, 
     102                                0600 /* restrictive file permissions */)) 
     103                        { 
     104                                sleep(1); 
     105                        } 
     106                } 
     107                else 
     108                { 
     109                        // Couldn't lock the account -- just stop now 
     110                        return; 
     111                } 
    96112        } 
    97113 
     
    106122                mDeletionSizeTarget = 0; 
    107123        } 
     124 
     125        // initialise the refcount database 
     126        mNewRefCounts.clear(); 
     127        // try to pre-allocate as much memory as we need 
     128        mNewRefCounts.reserve(info->GetLastObjectIDUsed()); 
     129        // initialise the refcount of the root entry 
     130        mNewRefCounts.resize(BACKUPSTORE_ROOT_DIRECTORY_ID + 1, 0); 
     131        mNewRefCounts[BACKUPSTORE_ROOT_DIRECTORY_ID] = 1; 
    108132 
    109133        // Scan the directory for potential things to delete 
     
    208232                        (deleteInterrupted?" and was interrupted":"")); 
    209233        } 
     234 
     235        // We can only update the refcount database if we successfully 
     236        // finished our scan of all directories, otherwise we don't actually 
     237        // know which of the new counts are valid and which aren't 
     238        // (we might not have seen second references to some objects, etc.) 
     239 
     240        BackupStoreAccountDatabase::Entry account(mAccountID, mStoreDiscSet); 
     241        std::auto_ptr<BackupStoreRefCountDatabase> apReferences; 
     242 
     243        // try to load the reference count database 
     244        try 
     245        { 
     246                apReferences = BackupStoreRefCountDatabase::Load(account, 
     247                        false); 
     248        } 
     249        catch(BoxException &e) 
     250        { 
     251                BOX_WARNING("Reference count database is missing or corrupted " 
     252                        "during housekeeping, creating a new one."); 
     253                mSuppressRefCountChangeWarnings = true; 
     254                BackupStoreRefCountDatabase::CreateForRegeneration(account); 
     255                apReferences = BackupStoreRefCountDatabase::Load(account, 
     256                        false); 
     257        } 
     258 
     259        int64_t LastUsedObjectIdOnDisk = apReferences->GetLastObjectIDUsed(); 
     260 
     261        for (int64_t ObjectID = BACKUPSTORE_ROOT_DIRECTORY_ID; 
     262                ObjectID < mNewRefCounts.size(); ObjectID++) 
     263        { 
     264                if (ObjectID > LastUsedObjectIdOnDisk) 
     265                { 
     266                        if (!mSuppressRefCountChangeWarnings) 
     267                        { 
     268                                BOX_WARNING("Reference count of object " << 
     269                                        BOX_FORMAT_OBJECTID(ObjectID) << 
     270                                        " not found in database, added" 
     271                                        " with " << mNewRefCounts[ObjectID] << 
     272                                        " references"); 
     273                        } 
     274                        apReferences->SetRefCount(ObjectID, 
     275                                mNewRefCounts[ObjectID]); 
     276                        LastUsedObjectIdOnDisk = ObjectID; 
     277                        continue; 
     278                } 
     279 
     280                BackupStoreRefCountDatabase::refcount_t OldRefCount = 
     281                        apReferences->GetRefCount(ObjectID); 
     282 
     283                if (OldRefCount != mNewRefCounts[ObjectID]) 
     284                { 
     285                        BOX_WARNING("Reference count of object " << 
     286                                BOX_FORMAT_OBJECTID(ObjectID) << 
     287                                " changed from " << OldRefCount << 
     288                                " to " << mNewRefCounts[ObjectID]); 
     289                        apReferences->SetRefCount(ObjectID, 
     290                                mNewRefCounts[ObjectID]); 
     291                } 
     292        } 
     293 
     294        // zero excess references in the database 
     295        for (int64_t ObjectID = mNewRefCounts.size();  
     296                ObjectID <= LastUsedObjectIdOnDisk; ObjectID++) 
     297        { 
     298                BackupStoreRefCountDatabase::refcount_t OldRefCount = 
     299                        apReferences->GetRefCount(ObjectID); 
     300                BackupStoreRefCountDatabase::refcount_t NewRefCount = 0; 
     301 
     302                if (OldRefCount != NewRefCount) 
     303                { 
     304                        BOX_WARNING("Reference count of object " << 
     305                                BOX_FORMAT_OBJECTID(ObjectID) << 
     306                                " changed from " << OldRefCount << 
     307                                " to " << NewRefCount << " (not found)"); 
     308                        apReferences->SetRefCount(ObjectID, NewRefCount); 
     309                } 
     310        } 
     311 
     312        // force file to be saved and closed before releasing the lock below 
     313        apReferences.reset(); 
    210314         
    211315        // Make sure the delta's won't cause problems if the counts are  
     
    280384                // Check for having to stop 
    281385                // Include account ID here as the specified account is locked 
    282                 if(mrDaemon.CheckForInterProcessMsg(mAccountID)) 
     386                if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID)) 
    283387                { 
    284388                        // Need to abort now 
     
    360464                while((en = i.Next(BackupStoreDirectory::Entry::Flags_File)) != 0) 
    361465                { 
     466                        // This directory references this object 
     467                        if (mNewRefCounts.size() <= en->GetObjectID()) 
     468                        { 
     469                                mNewRefCounts.resize(en->GetObjectID() + 1, 0); 
     470                        } 
     471                        mNewRefCounts[en->GetObjectID()]++; 
     472 
    362473                        // Update recalculated usage sizes 
    363474                        int16_t enFlags = en->GetFlags(); 
     
    468579                while((en = i.Next(BackupStoreDirectory::Entry::Flags_Dir)) != 0) 
    469580                { 
     581                        // This parent directory references this child 
     582                        if (mNewRefCounts.size() <= en->GetObjectID()) 
     583                        { 
     584                                mNewRefCounts.resize(en->GetObjectID() + 1, 0); 
     585                        } 
     586                        mNewRefCounts[en->GetObjectID()]++; 
     587 
    470588                        // Next level 
    471589                        ASSERT((en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) == BackupStoreDirectory::Entry::Flags_Dir); 
     
    552670                        mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; 
    553671                        // Check for having to stop 
    554                         if(mrDaemon.CheckForInterProcessMsg(mAccountID))        // include account ID here as the specified account is now locked 
     672                        if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID))       // include account ID here as the specified account is now locked 
    555673                        { 
    556674                                // Need to abort now 
     
    809927                                mCountUntilNextInterprocessMsgCheck = POLL_INTERPROCESS_MSG_CHECK_FREQUENCY; 
    810928                                // Check for having to stop 
    811                                 if(mrDaemon.CheckForInterProcessMsg(mAccountID))        // include account ID here as the specified account is now locked 
     929                                if(mpHousekeepingCallback && mpHousekeepingCallback->CheckForInterProcessMsg(mAccountID))       // include account ID here as the specified account is now locked 
    812930                                { 
    813931                                        // Need to abort now 
  • box/trunk/bin/bbstored/HousekeepStoreAccount.h

    r2176 r2541  
    1818class BackupStoreDirectory; 
    1919 
     20class HousekeepingCallback 
     21{ 
     22        public: 
     23        virtual ~HousekeepingCallback() {} 
     24        virtual bool CheckForInterProcessMsg(int AccountNum = 0, int MaximumWaitTime = 0) = 0; 
     25}; 
    2026 
    2127// -------------------------------------------------------------------------- 
     
    3036{ 
    3137public: 
    32         HousekeepStoreAccount(int AccountID, const std::string &rStoreRoot, int StoreDiscSet, BackupStoreDaemon &rDaemon); 
     38        HousekeepStoreAccount(int AccountID, const std::string &rStoreRoot, 
     39                int StoreDiscSet, HousekeepingCallback* pHousekeepingCallback); 
    3340        ~HousekeepStoreAccount(); 
    3441         
    35         void DoHousekeeping(); 
     42        void DoHousekeeping(bool KeepTryingForever = false); 
    3643         
    3744         
     
    6673        std::string mStoreRoot; 
    6774        int mStoreDiscSet; 
    68         BackupStoreDaemon &mrDaemon; 
     75        HousekeepingCallback* mpHousekeepingCallback; 
    6976         
    7077        int64_t mDeletionSizeTarget; 
     
    9299        int64_t mFilesDeleted; 
    93100        int64_t mEmptyDirectoriesDeleted; 
     101 
     102        // New reference count list 
     103        std::vector<uint32_t> mNewRefCounts; 
     104        bool mSuppressRefCountChangeWarnings; 
    94105         
    95106        // Poll frequency 
Note: See TracChangeset for help on using the changeset viewer.