Ignore:
Timestamp:
06/05/2008 22:48:52 (4 years ago)
Author:
chris
Message:

Fix O(n2) algorithm to insert lost objects into a directory, which would
become very slow with large directories (e.g. 100,000 files unattached)
due to repeated reading and writing of the directory.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • box/trunk/lib/backupstore/BackupStoreCheck2.cpp

    r2156 r2159  
    9696} 
    9797 
     98class BackupStoreDirectoryFixer 
     99{ 
     100        private: 
     101        BackupStoreDirectory mDirectory; 
     102        std::string mFilename; 
     103        std::string mStoreRoot; 
     104        int mDiscSetNumber; 
     105 
     106        public: 
     107        BackupStoreDirectoryFixer(std::string storeRoot, int discSetNumber, 
     108                int64_t ID); 
     109        void InsertObject(int64_t ObjectID, bool IsDirectory, 
     110                int32_t lostDirNameSerial); 
     111        ~BackupStoreDirectoryFixer(); 
     112}; 
    98113 
    99114// -------------------------------------------------------------------------- 
     
    107122void BackupStoreCheck::CheckUnattachedObjects() 
    108123{ 
     124        typedef std::map<int64_t, BackupStoreDirectoryFixer*> fixers_t; 
     125        typedef std::pair<int64_t, BackupStoreDirectoryFixer*> fixer_pair_t; 
     126        fixers_t fixers; 
     127 
    109128        // Scan all objects, finding ones which have no container 
    110129        for(Info_t::const_iterator i(mInfo.begin()); i != mInfo.end(); ++i) 
     
    119138                        { 
    120139                                // Unattached object... 
    121                                 BOX_WARNING("Object " << BOX_FORMAT_OBJECTID(pblock->mID[e]) << " is unattached."); 
     140                                BOX_WARNING("Object " << 
     141                                        BOX_FORMAT_OBJECTID(pblock->mID[e]) << 
     142                                        " is unattached."); 
    122143                                ++mNumberErrorsFound; 
    123144 
     
    197218                                ASSERT(putIntoDirectoryID != 0); 
    198219 
     220                                if (!mFixErrors) 
     221                                { 
     222                                        continue; 
     223                                } 
     224 
     225                                BackupStoreDirectoryFixer* pFixer; 
     226                                fixers_t::iterator fi =  
     227                                        fixers.find(putIntoDirectoryID); 
     228                                if (fi == fixers.end()) 
     229                                { 
     230                                        // no match, create a new one 
     231                                        pFixer = new BackupStoreDirectoryFixer( 
     232                                                mStoreRoot, mDiscSetNumber, 
     233                                                putIntoDirectoryID); 
     234                                        fixers.insert(fixer_pair_t( 
     235                                                putIntoDirectoryID, pFixer)); 
     236                                } 
     237                                else 
     238                                { 
     239                                        pFixer = fi->second; 
     240                                } 
     241 
     242                                int32_t lostDirNameSerial = 0; 
     243 
     244                                if(flags & Flags_IsDir) 
     245                                { 
     246                                        lostDirNameSerial = mLostDirNameSerial++; 
     247                                } 
     248 
    199249                                // Add it to the directory 
    200                                 InsertObjectIntoDirectory(pblock->mID[e], putIntoDirectoryID, 
    201                                         ((flags & Flags_IsDir) == Flags_IsDir)); 
     250                                pFixer->InsertObject(pblock->mID[e], 
     251                                        ((flags & Flags_IsDir) == Flags_IsDir), 
     252                                        lostDirNameSerial); 
    202253                        } 
    203254                } 
    204255        } 
    205 } 
    206  
     256 
     257        // clean up all the fixers. Deleting them commits them automatically. 
     258        for (fixers_t::iterator i = fixers.begin(); i != fixers.end(); i++) 
     259        { 
     260                BackupStoreDirectoryFixer* pFixer = i->second; 
     261                delete pFixer; 
     262        } 
     263} 
    207264 
    208265// -------------------------------------------------------------------------- 
     
    262319} 
    263320 
     321BackupStoreDirectoryFixer::BackupStoreDirectoryFixer(std::string storeRoot, 
     322        int discSetNumber, int64_t ID) 
     323: mStoreRoot(storeRoot), 
     324  mDiscSetNumber(discSetNumber) 
     325{ 
     326        // Generate filename 
     327        StoreStructure::MakeObjectFilename(ID, mStoreRoot, mDiscSetNumber, 
     328                mFilename, false /* don't make sure the dir exists */); 
     329         
     330        // Read it in 
     331        std::auto_ptr<RaidFileRead> file( 
     332                RaidFileRead::Open(mDiscSetNumber, mFilename)); 
     333        mDirectory.ReadFromStream(*file, IOStream::TimeOutInfinite); 
     334} 
     335 
     336void BackupStoreDirectoryFixer::InsertObject(int64_t ObjectID, bool IsDirectory, 
     337        int32_t lostDirNameSerial) 
     338{ 
     339        // Data for the object 
     340        BackupStoreFilename objectStoreFilename; 
     341        int64_t modTime = 100;  // something which isn't zero or a special time 
     342        int32_t sizeInBlocks = 0; // suitable for directories 
     343 
     344        if(IsDirectory) 
     345        { 
     346                // Directory -- simply generate a name for it. 
     347                char name[32]; 
     348                ::sprintf(name, "dir%08x", lostDirNameSerial); 
     349                objectStoreFilename.SetAsClearFilename(name); 
     350        } 
     351        else 
     352        { 
     353                // Files require a little more work... 
     354                // Open file 
     355                std::string fileFilename; 
     356                StoreStructure::MakeObjectFilename(ObjectID, mStoreRoot, 
     357                        mDiscSetNumber, fileFilename, 
     358                        false /* don't make sure the dir exists */); 
     359                std::auto_ptr<RaidFileRead> file( 
     360                        RaidFileRead::Open(mDiscSetNumber, fileFilename)); 
     361 
     362                // Fill in size information 
     363                sizeInBlocks = file->GetDiscUsageInBlocks(); 
     364 
     365                // Read in header 
     366                file_StreamFormat hdr; 
     367                if(file->Read(&hdr, sizeof(hdr)) != sizeof(hdr) || 
     368                        (ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1 
     369#ifndef BOX_DISABLE_BACKWARDS_COMPATIBILITY_BACKUPSTOREFILE 
     370                        && ntohl(hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V0 
     371#endif           
     372                        )) 
     373                { 
     374                        // This should never happen, everything has been 
     375                        // checked before. 
     376                        THROW_EXCEPTION(BackupStoreException, Internal) 
     377                } 
     378                // This tells us nice things 
     379                modTime = box_ntoh64(hdr.mModificationTime); 
     380                // And the filename comes next 
     381                objectStoreFilename.ReadFromStream(*file, IOStream::TimeOutInfinite); 
     382        } 
     383 
     384        // Add a new entry in an appropriate place 
     385        mDirectory.AddUnattactedObject(objectStoreFilename, modTime, 
     386                ObjectID, sizeInBlocks, 
     387                IsDirectory?(BackupStoreDirectory::Entry::Flags_Dir):(BackupStoreDirectory::Entry::Flags_File)); 
     388} 
     389 
     390BackupStoreDirectoryFixer::~BackupStoreDirectoryFixer() 
     391{ 
     392        // Fix any flags which have been broken, which there's a good chance of doing 
     393        mDirectory.CheckAndFix(); 
     394         
     395        // Write it out 
     396        RaidFileWrite root(mDiscSetNumber, mFilename); 
     397        root.Open(true /* allow overwriting */); 
     398        mDirectory.WriteToStream(root); 
     399        root.Commit(true /* convert to raid now */); 
     400} 
    264401 
    265402// -------------------------------------------------------------------------- 
Note: See TracChangeset for help on using the changeset viewer.