[Box Backup-commit] COMMIT r2756 - in box/invisnet/perfhack1: bin/bbstored lib/backupclient lib/raidfile

subversion at boxbackup.org subversion at boxbackup.org
Fri Sep 24 01:22:35 BST 2010


Author: invisnet
Date: 2010-09-24 01:22:34 +0100 (Fri, 24 Sep 2010)
New Revision: 2756

Modified:
   box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.cpp
   box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.h
   box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.cpp
   box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.h
   box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.cpp
   box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.h
Log:
This should fix ticket #8.

Modified: box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.cpp
===================================================================
--- box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.cpp	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.cpp	2010-09-24 00:22:34 UTC (rev 2756)
@@ -136,7 +136,7 @@
 
 	// Request the lock
 	bool gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
-	
+
 	if(!gotLock)
 	{
 		// The housekeeping process might have the thing open -- ask it to stop
@@ -144,7 +144,7 @@
 		int msgLen = sprintf(msg, "r%x\n", mClientID);
 		// Send message
 		mrDaemon.SendMessageToHousekeepingProcess(msg, msgLen);
-		
+
 		// Then try again a few times
 		int tries = MAX_WAIT_FOR_HOUSEKEEPING_TO_RELEASE_ACCOUNT;
 		do
@@ -152,16 +152,16 @@
 			::sleep(1 /* second */);
 			--tries;
 			gotLock = mWriteLock.TryAndGetLock(writeLockFile.c_str(), 0600 /* restrictive file permissions */);
-			
+
 		} while(!gotLock && tries > 0);
 	}
-	
+
 	if(gotLock)
 	{
 		// Got the lock, mark as not read only
 		mReadOnly = false;
 	}
-	
+
 	return gotLock;
 }
 
@@ -180,16 +180,16 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoAlreadyLoaded)
 	}
-	
+
 	// Load it up!
 	std::auto_ptr<BackupStoreInfo> i(BackupStoreInfo::Load(mClientID, mStoreRoot, mStoreDiscSet, mReadOnly));
-	
+
 	// Check it
 	if(i->GetAccountID() != mClientID)
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoForWrongAccount)
 	}
-	
+
 	// Keep the pointer to it
 	mpStoreInfo = i;
 
@@ -205,7 +205,7 @@
 		BOX_WARNING("Reference count database is missing or corrupted, "
 			"creating a new one, expect housekeeping to find and "
 			"fix problems with reference counts later.");
-		
+
 		BackupStoreRefCountDatabase::CreateForRegeneration(account);
 		mapRefCount = BackupStoreRefCountDatabase::Load(account, false);
 	}
@@ -241,7 +241,7 @@
 		}
 	}
 
-	// Want to save now	
+	// Want to save now
 	mpStoreInfo->Save();
 
 	// Set count for next delay
@@ -254,7 +254,7 @@
 //
 // Function
 //		Name:    BackupStoreContext::MakeObjectFilename(int64_t, std::string &, bool)
-//		Purpose: Create the filename of an object in the store, optionally creating the 
+//		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
 //
@@ -270,7 +270,7 @@
 //
 // Function
 //		Name:    BackupStoreContext::GetDirectoryInternal(int64_t)
-//		Purpose: Return a reference to a directory. Valid only until the 
+//		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.
 //				 Private version of this, which returns non-const directories.
@@ -282,7 +282,7 @@
 	// Get the filename
 	std::string filename;
 	MakeObjectFilename(ObjectID, filename);
-	
+
 	// Already in cache?
 	std::map<int64_t, BackupStoreDirectory*>::iterator item(mDirectoryCache.find(ObjectID));
 	if(item != mDirectoryCache.end())
@@ -293,7 +293,7 @@
 		{
 			THROW_EXCEPTION(BackupStoreException, DirectoryHasBeenDeleted)
 		}
-	
+
 		if(revID == item->second->GetRevisionID())
 		{
 			// Looks good... return the cached object
@@ -302,7 +302,7 @@
 				" from cache, modtime = " << revID);
 			return *(item->second);
 		}
-		
+
 		BOX_TRACE("Refreshing object " <<
 			BOX_FORMAT_OBJECTID(ObjectID) <<
 			" in cache, modtime changed from " <<
@@ -312,9 +312,9 @@
 		delete item->second;
 		mDirectoryCache.erase(item);
 	}
-	
+
 	// Need to load it up
-	
+
 	// First check to see if the cache is too big
 	if(mDirectoryCache.size() > MAX_CACHE_SIZE)
 	{
@@ -330,15 +330,15 @@
 	int64_t revID = 0;
 	std::auto_ptr<RaidFileRead> objectFile(RaidFileRead::Open(mStoreDiscSet, filename, &revID));
 	ASSERT(revID != 0);
-	
+
 	// New directory object
 	std::auto_ptr<BackupStoreDirectory> dir(new BackupStoreDirectory);
-	
+
 	// Read it from the stream, then set it's revision ID
 	BufferedStream buf(*objectFile);
 	dir->ReadFromStream(buf, IOStream::TimeOutInfinite);
 	dir->SetRevisionID(revID);
-			
+
 	// Make sure the size of the directory is available for writing the dir back
 	int64_t dirSize = objectFile->GetDiscUsageInBlocks();
 	ASSERT(dirSize > 0);
@@ -347,7 +347,7 @@
 	// Store in cache
 	BackupStoreDirectory *pdir = dir.release();
 	try
-	{	
+	{
 		mDirectoryCache[ObjectID] = pdir;
 	}
 	catch(...)
@@ -355,7 +355,7 @@
 		delete pdir;
 		throw;
 	}
-	
+
 	// Return it
 	return *pdir;
 }
@@ -380,12 +380,12 @@
 	// to try for finding an unused ID.
 	// (Sizes used in the store info are fixed by the housekeeping process)
 	int retryLimit = (STORE_INFO_SAVE_DELAY * 2);
-	
+
 	while(retryLimit > 0)
 	{
 		// Attempt to allocate an ID from the store
 		int64_t id = mpStoreInfo->AllocateObjectID();
-		
+
 		// Generate filename
 		std::string filename;
 		MakeObjectFilename(id, filename);
@@ -395,17 +395,17 @@
 			// Success!
 			return id;
 		}
-		
+
 		// Decrement retry count, and try again
 		--retryLimit;
-		
+
 		// Mark that the store info should be saved as soon as possible
 		mSaveStoreInfoDelay = 0;
-		
+
 		BOX_WARNING("When allocating object ID, found that " <<
 			BOX_FORMAT_OBJECTID(id) << " is already in use");
 	}
-	
+
 	THROW_EXCEPTION(BackupStoreException, CouldNotFindUnusedIDDuringAllocation)
 }
 
@@ -434,7 +434,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
 	}
-	
+
 	// This is going to be a bit complex to make sure it copes OK
 	// with things going wrong.
 	// The only thing which isn't safe is incrementing the object ID
@@ -443,13 +443,13 @@
 	// be corrected the next time the account has a housekeeping run,
 	// and the object ID allocation code is tolerant of missed IDs.
 	// (the info is written lazily, so these are necessary)
-	
+
 	// Get the directory we want to modify
 	BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-	
+
 	// Allocate the next ID
 	int64_t id = AllocateObjectID();
-	
+
 	// Stream the file to disc
 	std::string fn;
 	MakeObjectFilename(id, fn, true /* make sure the directory it's in exists */);
@@ -479,19 +479,19 @@
 			{
 				THROW_EXCEPTION(BackupStoreException, DiffFromIDNotFoundInDirectory)
 			}
-		
+
 			// Diff file, needs to be recreated.
 			// Choose a temporary filename.
 			std::string tempFn(RaidFileController::DiscSetPathToFileSystemPath(mStoreDiscSet, fn + ".difftemp",
 				1 /* NOT the same disc as the write file, to avoid using lots of space on the same disc unnecessarily */));
-			
+
 			try
 			{
 				// Open it twice
 #ifdef WIN32
-				InvisibleTempFileStream diff(tempFn.c_str(), 
+				InvisibleTempFileStream diff(tempFn.c_str(),
 					O_RDWR | O_CREAT | O_BINARY);
-				InvisibleTempFileStream diff2(tempFn.c_str(), 
+				InvisibleTempFileStream diff2(tempFn.c_str(),
 					O_RDWR | O_BINARY);
 #else
 				FileStream diff(tempFn.c_str(), O_RDWR | O_CREAT | O_EXCL);
@@ -503,13 +503,13 @@
 					THROW_EXCEPTION(CommonException, OSFileError);
 				}
 #endif
-				
+
 				// Stream the incoming diff to this temporary file
 				if(!rFile.CopyStreamTo(diff, BACKUP_STORE_TIMEOUT))
 				{
 					THROW_EXCEPTION(BackupStoreException, ReadFileFromStreamTimedOut)
 				}
-				
+
 				// Verify the diff
 				diff.Seek(0, IOStream::SeekType_Absolute);
 				if(!BackupStoreFile::VerifyEncodedFileFormat(diff))
@@ -523,7 +523,7 @@
 				// Filename of the old version
 				std::string oldVersionFilename;
 				MakeObjectFilename(DiffFromFileID, oldVersionFilename, false /* no need to make sure the directory it's in exists */);
-				
+
 				// Reassemble that diff -- open previous file, and combine the patch and file
 				std::auto_ptr<RaidFileRead> from(RaidFileRead::Open(mStoreDiscSet, oldVersionFilename));
 				BackupStoreFile::CombineFile(diff, diff2, *from, storeFile);
@@ -536,10 +536,10 @@
 				diff.Seek(0, IOStream::SeekType_Absolute);
 				BackupStoreFile::ReverseDiffFile(diff, *from, *from2, *ppreviousVerStoreFile,
 						DiffFromFileID, &reversedDiffIsCompletelyDifferent);
-				
+
 				// Store disc space used
 				oldVersionNewBlocksUsed = ppreviousVerStoreFile->GetDiscUsageInBlocks();
-				
+
 				// And make a space adjustment for the size calculation
 				spaceAdjustFromDiff = from->GetDiscUsageInBlocks() - oldVersionNewBlocksUsed;
 
@@ -552,10 +552,10 @@
 				throw;
 			}
 		}
-		
+
 		// Get the blocks used
 		blocksUsed = storeFile.GetDiscUsageInBlocks();
-		
+
 		// Exceeds the hard limit?
 		if((mpStoreInfo->GetBlocksUsed() + blocksUsed - spaceAdjustFromDiff) > mpStoreInfo->GetBlocksHardLimit())
 		{
@@ -574,7 +574,7 @@
 			delete ppreviousVerStoreFile;
 			ppreviousVerStoreFile = 0;
 		}
-		
+
 		throw;
 	}
 
@@ -589,12 +589,12 @@
 			// Error! Delete the file
 			RaidFileWrite del(mStoreDiscSet, fn);
 			del.Delete();
-			
+
 			// Exception
 			THROW_EXCEPTION(BackupStoreException, AddedFileDoesNotVerify)
 		}
-	}			
-	
+	}
+
 	// Modify the directory -- first make all files with the same name
 	// marked as an old version
 	int64_t blocksInOldFiles = 0;
@@ -617,14 +617,14 @@
 						ASSERT((e->GetFlags() & BackupStoreDirectory::Entry::Flags_OldVersion) == 0);
 						// Set old version flag
 						e->AddFlags(BackupStoreDirectory::Entry::Flags_OldVersion);
-						// Can safely do this, because we know we won't be here if it's already 
+						// Can safely do this, because we know we won't be here if it's already
 						// an old version
 						blocksInOldFiles += e->GetSizeInBlocks();
 					}
 				}
 			}
 		}
-		
+
 		// Then the new entry
 		BackupStoreDirectory::Entry *pnewEntry = dir.AddEntry(rFilename,
 				ModificationTime, id, blocksUsed, BackupStoreDirectory::Entry::Flags_File, AttributesHash);
@@ -635,25 +635,25 @@
 			// Get old version entry
 			BackupStoreDirectory::Entry *poldEntry = dir.FindEntryByID(DiffFromFileID);
 			ASSERT(poldEntry != 0);
-		
+
 			// Adjust dependency info of file?
 			if(!reversedDiffIsCompletelyDifferent)
 			{
 				poldEntry->SetDependsNewer(id);
 				pnewEntry->SetDependsOlder(DiffFromFileID);
 			}
-			
+
 			// Adjust size of old entry
 			int64_t oldSize = poldEntry->GetSizeInBlocks();
 			poldEntry->SetSizeInBlocks(oldVersionNewBlocksUsed);
-			
+
 			// And adjust blocks used count, for later adjustment
 			blocksUsed += (oldVersionNewBlocksUsed - oldSize);
 			blocksInOldFiles += (oldVersionNewBlocksUsed - oldSize);
 		}
 
 		// Write the directory back to disc
-		SaveDirectory(dir, InDirectory);
+		SaveDirectory(dir, InDirectory, (0 == DiffFromFileID) /* Append last (new) entry only */ );
 
 		// Commit the old version's new patched version, now that the directory safely reflects
 		// the state of the files on disc.
@@ -669,35 +669,35 @@
 		// Back out on adding that file
 		RaidFileWrite del(mStoreDiscSet, fn);
 		del.Delete();
-		
+
 		// Remove this entry from the cache
 		RemoveDirectoryFromCache(InDirectory);
-		
+
 		// Delete any previous version store file
 		if(ppreviousVerStoreFile != 0)
 		{
 			delete ppreviousVerStoreFile;
 			ppreviousVerStoreFile = 0;
 		}
-		
+
 		// Don't worry about the incremented number in the store info
 		throw;
 	}
-	
+
 	// Check logic
 	ASSERT(ppreviousVerStoreFile == 0);
-	
+
 	// Modify the store info
 	mpStoreInfo->ChangeBlocksUsed(blocksUsed);
 	mpStoreInfo->ChangeBlocksInOldFiles(blocksInOldFiles);
-	
+
 	// Increment reference count on the new directory to one
 	mapRefCount->AddReference(id);
-	
+
 	// Save the store info -- can cope if this exceptions because infomation
 	// will be rebuilt by housekeeping, and ID allocation can recover.
 	SaveStoreInfo();
-	
+
 	// Return the ID to the caller
 	return id;
 }
@@ -753,7 +753,7 @@
 				e->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
 				// Mark as made a change
 				madeChanges = true;
-				// Can safely do this, because we know we won't be here if it's already 
+				// Can safely do this, because we know we won't be here if it's already
 				// an old version
 				blocksDel += e->GetSizeInBlocks();
 				// Is this the last version?
@@ -765,16 +765,16 @@
 				}
 			}
 		}
-		
+
 		// 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();
 		}
@@ -848,16 +848,16 @@
 				}
 			}
 		}
-		
+
 		// 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();
 		}
@@ -896,12 +896,12 @@
 // --------------------------------------------------------------------------
 //
 // Function
-//		Name:    BackupStoreContext::SaveDirectory(BackupStoreDirectory &, int64_t)
+//		Name:    BackupStoreContext::SaveDirectory(BackupStoreDirectory &, int64_t, bool)
 //		Purpose: Save directory back to disc, update time in cache
 //		Created: 2003/09/04
 //
 // --------------------------------------------------------------------------
-void BackupStoreContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID)
+void BackupStoreContext::SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID, bool AppendLastEntryOnly)
 {
 	if(mpStoreInfo.get() == 0)
 	{
@@ -919,10 +919,17 @@
 		MakeObjectFilename(ObjectID, dirfn);
 		{
 			RaidFileWrite writeDir(mStoreDiscSet, dirfn);
-			writeDir.Open(true /* allow overwriting */);
+			writeDir.Open(true /* allow overwriting */, AppendLastEntryOnly);
 
 			BufferedWriteStream buffer(writeDir);
-			rDir.WriteToStream(buffer);
+			if(AppendLastEntryOnly)
+			{
+				rDir.UpdateToStream(buffer);
+			}
+			else
+			{
+				rDir.WriteToStream(buffer);
+			}
 			buffer.Flush();
 
 			// get the disc usage (must do this before commiting it)
@@ -930,7 +937,7 @@
 
 			// Commit directory
 			writeDir.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
-			
+
 			// Make sure the size of the directory is available for writing the dir back
 			ASSERT(dirSize > 0);
 			int64_t sizeAdjustment = dirSize - rDir.GetUserInfo1_SizeInBlocks();
@@ -978,10 +985,10 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
 	}
-	
+
 	// Flags as not already existing
 	rAlreadyExists = false;
-	
+
 	// Get the directory we want to modify
 	BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
 
@@ -1011,7 +1018,7 @@
 		BackupStoreDirectory emptyDir(id, InDirectory);
 		// add the atttribues
 		emptyDir.SetAttributes(Attributes, AttributesModTime);
-		
+
 		// Write...
 		RaidFileWrite dirFile(mStoreDiscSet, fn);
 		dirFile.Open(false /* no overwriting */);
@@ -1019,7 +1026,7 @@
 		// Get disc usage, before it's commited
 		int64_t dirSize = dirFile.GetDiscUsageInBlocks();
 		// Commit the file
-		dirFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);		
+		dirFile.Commit(BACKUP_STORE_CONVERT_TO_RAID_IMMEDIATELY);
 
 		// Make sure the size of the directory is added to the usage counts in the info
 		ASSERT(dirSize > 0);
@@ -1027,7 +1034,7 @@
 		mpStoreInfo->ChangeBlocksInDirectories(dirSize);
 		// Not added to cache, so don't set the size in the directory
 	}
-	
+
 	// Then add it into the parent directory
 	try
 	{
@@ -1042,12 +1049,12 @@
 		// Back out on adding that directory
 		RaidFileWrite del(mStoreDiscSet, fn);
 		del.Delete();
-		
+
 		// Remove this entry from the cache
 		RemoveDirectoryFromCache(InDirectory);
-		
+
 		// Don't worry about the incremented number in the store info
-		throw;	
+		throw;
 	}
 
 	// Save the store info (may be postponed)
@@ -1079,7 +1086,7 @@
 
 	// Containing directory
 	int64_t InDirectory = 0;
-	
+
 	// Count of blocks deleted
 	int64_t blocksDeleted = 0;
 
@@ -1089,18 +1096,18 @@
 		{
 			// In block, because dir may not be valid after the delete directory call
 			BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-			
+
 			// Store the directory it's in for later
 			InDirectory = dir.GetContainerID();
-		
+
 			// Depth first delete of contents
 			DeleteDirectoryRecurse(ObjectID, blocksDeleted, Undelete);
 		}
-		
+
 		// Remove the entry from the directory it's in
 		ASSERT(InDirectory != 0);
 		BackupStoreDirectory &parentDir(GetDirectoryInternal(InDirectory));
-		
+
 		BackupStoreDirectory::Iterator i(parentDir);
 		BackupStoreDirectory::Entry *en = 0;
 		while((en = i.Next(Undelete?(BackupStoreDirectory::Entry::Flags_Deleted):(BackupStoreDirectory::Entry::Flags_INCLUDE_EVERYTHING),
@@ -1117,18 +1124,18 @@
 				{
 					en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
 				}
-							
+
 				// Save it
 				SaveDirectory(parentDir, InDirectory);
-				
+
 				// Done
 				break;
 			}
 		}
-		
+
 		// Update blocks deleted count
 		mpStoreInfo->ChangeBlocksInDeletedFiles(Undelete?(0 - blocksDeleted):(blocksDeleted));
-		
+
 		// Save store info, may be postponed
 		SaveStoreInfo();
 	}
@@ -1153,12 +1160,12 @@
 	{
 		// Does things carefully to avoid using a directory in the cache after recursive call
 		// because it may have been deleted.
-		
+
 		// Do sub directories
 		{
 			// Get the directory...
 			BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-			
+
 			// Then scan it for directories
 			std::vector<int64_t> subDirs;
 			BackupStoreDirectory::Iterator i(dir);
@@ -1181,24 +1188,24 @@
 					subDirs.push_back(en->GetObjectID());
 				}
 			}
-			
+
 			// Done with the directory for now. Recurse to sub directories
 			for(std::vector<int64_t>::const_iterator i = subDirs.begin(); i != subDirs.end(); ++i)
 			{
-				DeleteDirectoryRecurse((*i), rBlocksDeletedOut, Undelete);	
+				DeleteDirectoryRecurse((*i), rBlocksDeletedOut, Undelete);
 			}
 		}
-		
+
 		// Then, delete the files. Will need to load the directory again because it might have
 		// been removed from the cache.
 		{
 			// Get the directory...
 			BackupStoreDirectory &dir(GetDirectoryInternal(ObjectID));
-	
+
 			// Changes made?
 			bool changesMade = false;
-	
-			// Run through files		
+
+			// Run through files
 			BackupStoreDirectory::Iterator i(dir);
 			BackupStoreDirectory::Entry *en = 0;
 
@@ -1214,17 +1221,17 @@
 				{
 					en->AddFlags(BackupStoreDirectory::Entry::Flags_Deleted);
 				}
-							
+
 				// Keep count of the deleted blocks
 				if((en->GetFlags() & BackupStoreDirectory::Entry::Flags_File) != 0)
 				{
 					rBlocksDeletedOut += en->GetSizeInBlocks();
 				}
-				
+
 				// Did something
 				changesMade = true;
 			}
-			
+
 			// Save the directory
 			if(changesMade)
 			{
@@ -1261,13 +1268,13 @@
 	}
 
 	try
-	{	
+	{
 		// Get the directory we want to modify
 		BackupStoreDirectory &dir(GetDirectoryInternal(Directory));
-	
+
 		// Set attributes
 		dir.SetAttributes(Attributes, AttributesModTime);
-		
+
 		// Save back
 		SaveDirectory(dir, Directory);
 	}
@@ -1296,12 +1303,12 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
 	}
-	
+
 	try
 	{
 		// Get the directory we want to modify
 		BackupStoreDirectory &dir(GetDirectoryInternal(InDirectory));
-	
+
 		// Find the file entry
 		BackupStoreDirectory::Entry *en = 0;
 		// Iterate through current versions of files, only
@@ -1315,10 +1322,10 @@
 			{
 				// Set attributes
 				en->SetAttributes(Attributes, AttributesHash);
-				
+
 				// Tell caller the object ID
 				rObjectIDOut = en->GetObjectID();
-				
+
 				// Done
 				break;
 			}
@@ -1328,7 +1335,7 @@
 			// Didn't find it
 			return false;
 		}
-	
+
 		// Save back
 		SaveDirectory(dir, InDirectory);
 	}
@@ -1337,7 +1344,7 @@
 		RemoveDirectoryFromCache(InDirectory);
 		throw;
 	}
-	
+
 	// Changed, everything OK
 	return true;
 }
@@ -1357,7 +1364,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
 	}
-	
+
 	// Note that we need to allow object IDs a little bit greater than the last one in the store info,
 	// because the store info may not have got saved in an error condition. Max greater ID is
 	// STORE_INFO_SAVE_DELAY in this case, *2 to be safe.
@@ -1366,7 +1373,7 @@
 		// Obviously bad object ID
 		return false;
 	}
-	
+
 	// Test to see if it exists on the disc
 	std::string filename;
 	MakeObjectFilename(ObjectID, filename);
@@ -1375,7 +1382,7 @@
 		// RaidFile reports no file there
 		return false;
 	}
-	
+
 	// Do we need to be more specific?
 	if(MustBe != ObjectExists_Anything)
 	{
@@ -1400,16 +1407,16 @@
 
 		// Right one?
 		u_int32_t requiredMagic = (MustBe == ObjectExists_File)?OBJECTMAGIC_FILE_MAGIC_VALUE_V1:OBJECTMAGIC_DIR_MAGIC_VALUE;
-	
+
 		// Check
 		if(ntohl(magic) != requiredMagic)
 		{
 			return false;
 		}
-		
+
 		// File is implicitly closed
 	}
-	
+
 	return true;
 }
 
@@ -1428,7 +1435,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
 	}
-	
+
 	// Attempt to open the file
 	std::string fn;
 	MakeObjectFilename(ObjectID, fn);
@@ -1450,7 +1457,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
 	}
-	
+
 	return mpStoreInfo->GetClientStoreMarker();
 }
 
@@ -1513,7 +1520,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, ContextIsReadOnly)
 	}
-	
+
 	mpStoreInfo->SetClientStoreMarker(ClientStoreMarker);
 	SaveStoreInfo(false /* don't delay saving this */);
 }
@@ -1538,7 +1545,7 @@
 	int64_t targetSearchExcludeFlags = (AllowMoveOverDeletedObject)
 		?(BackupStoreDirectory::Entry::Flags_Deleted)
 		:(BackupStoreDirectory::Entry::Flags_EXCLUDE_NOTHING);
-	
+
 	// Special case if the directories are the same...
 	if(MoveFromDirectory == MoveToDirectory)
 	{
@@ -1546,16 +1553,16 @@
 		{
 			// Get the first directory
 			BackupStoreDirectory &dir(GetDirectoryInternal(MoveFromDirectory));
-		
+
 			// Find the file entry
 			BackupStoreDirectory::Entry *en = dir.FindEntryByID(ObjectID);
-	
+
 			// Error if not found
 			if(en == 0)
 			{
 				THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
 			}
-			
+
 			// Check the new name doens't already exist (optionally ignoring deleted files)
 			{
 				BackupStoreDirectory::Iterator i(dir);
@@ -1568,7 +1575,7 @@
 					}
 				}
 			}
-			
+
 			// Need to get all the entries with the same name?
 			if(MoveAllWithSameName)
 			{
@@ -1589,7 +1596,7 @@
 				// Just copy this one
 				en->SetName(rNewFilename);
 			}
-			
+
 			// Save the directory back
 			SaveDirectory(dir, MoveFromDirectory);
 		}
@@ -1598,7 +1605,7 @@
 			RemoveDirectoryFromCache(MoveToDirectory); // either will do, as they're the same
 			throw;
 		}
-	
+
 		return;
 	}
 
@@ -1607,27 +1614,27 @@
 
 	// List of entries to move
 	std::vector<BackupStoreDirectory::Entry *> moving;
-	
+
 	// list of directory IDs which need to have containing dir id changed
 	std::vector<int64_t> dirsToChangeContainingID;
 
 	try
 	{
 		// First of all, get copies of the entries to move to the to directory.
-		
+
 		{
 			// Get the first directory
 			BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
-		
+
 			// Find the file entry
 			BackupStoreDirectory::Entry *en = from.FindEntryByID(ObjectID);
-	
+
 			// Error if not found
 			if(en == 0)
 			{
 				THROW_EXCEPTION(BackupStoreException, CouldNotFindEntryInDirectory)
 			}
-			
+
 			// Need to get all the entries with the same name?
 			if(MoveAllWithSameName)
 			{
@@ -1640,7 +1647,7 @@
 					{
 						// Copy
 						moving.push_back(new BackupStoreDirectory::Entry(*c));
-						
+
 						// Check for containing directory correction
 						if(c->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(c->GetObjectID());
 					}
@@ -1656,13 +1663,13 @@
 				if(en->GetFlags() & BackupStoreDirectory::Entry::Flags_Dir) dirsToChangeContainingID.push_back(en->GetObjectID());
 			}
 		}
-		
+
 		// Secondly, insert them into the to directory, and save it
-		
+
 		{
 			// To directory
 			BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
-	
+
 			// Check the new name doens't already exist
 			{
 				BackupStoreDirectory::Iterator i(to);
@@ -1675,7 +1682,7 @@
 					}
 				}
 			}
-			
+
 			// Copy the entries into it, changing the name as we go
 			for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
 			{
@@ -1683,7 +1690,7 @@
 				en->SetName(rNewFilename);
 				to.AddEntry(*en);	// adds copy
 			}
-	
+
 			// Save back
 			SaveDirectory(to, MoveToDirectory);
 		}
@@ -1693,57 +1700,57 @@
 		{
 			// Get directory
 			BackupStoreDirectory &from(GetDirectoryInternal(MoveFromDirectory));
-		
+
 			// Delete each one
 			for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
 			{
 				from.DeleteEntry((*i)->GetObjectID());
 			}
-	
+
 			// Save back
-			SaveDirectory(from, MoveFromDirectory);		
+			SaveDirectory(from, MoveFromDirectory);
 		}
 		catch(...)
 		{
 			// UNDO modification to To directory
-					
+
 			// Get directory
 			BackupStoreDirectory &to(GetDirectoryInternal(MoveToDirectory));
-		
+
 			// Delete each one
 			for(std::vector<BackupStoreDirectory::Entry *>::iterator i(moving.begin()); i != moving.end(); ++i)
 			{
 				to.DeleteEntry((*i)->GetObjectID());
 			}
-	
+
 			// Save back
 			SaveDirectory(to, MoveToDirectory);
 
 			// Throw the error
 			throw;
 		}
-		
+
 		// Finally... for all the directories we moved, modify their containing directory ID
 		for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
 		{
 			// Load the directory
 			BackupStoreDirectory &change(GetDirectoryInternal(*i));
-			
+
 			// Modify containing dir ID
 			change.SetContainerID(MoveToDirectory);
-			
+
 			// Save it back
 			SaveDirectory(change, *i);
 		}
 	}
 	catch(...)
 	{
-		// Make sure directories aren't in the cache, as they may have been modified		
+		// Make sure directories aren't in the cache, as they may have been modified
 		RemoveDirectoryFromCache(MoveToDirectory);
 		RemoveDirectoryFromCache(MoveFromDirectory);
 		for(std::vector<int64_t>::iterator i(dirsToChangeContainingID.begin()); i != dirsToChangeContainingID.end(); ++i)
 		{
-			RemoveDirectoryFromCache(*i);			
+			RemoveDirectoryFromCache(*i);
 		}
 
 		while(!moving.empty())
@@ -1752,7 +1759,7 @@
 			moving.pop_back();
 		}
 		throw;
-	}	
+	}
 
 	// Clean up
 	while(!moving.empty())
@@ -1778,7 +1785,7 @@
 	{
 		THROW_EXCEPTION(BackupStoreException, StoreInfoNotLoaded)
 	}
-	
+
 	return *(mpStoreInfo.get());
 }
 

Modified: box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.h
===================================================================
--- box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.h	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/bin/bbstored/BackupStoreContext.h	2010-09-24 00:22:34 UTC (rev 2756)
@@ -63,10 +63,10 @@
 		Phase_Login		= 1,
 		Phase_Commands	= 2
 	};
-	
+
 	int GetPhase() const {return mProtocolPhase;}
 	void SetPhase(int NewPhase) {mProtocolPhase = NewPhase;}
-	
+
 	// Read only locking
 	bool SessionIsReadOnly() {return mReadOnly;}
 	bool AttemptToGetWriteLock();
@@ -84,7 +84,7 @@
 	// Client marker
 	int64_t GetClientStoreMarker();
 	void SetClientStoreMarker(int64_t ClientStoreMarker);
-	
+
 	// Usage information
 	void GetStoreDiscUsageInfo(int64_t &rBlocksUsed, int64_t &rBlocksSoftLimit, int64_t &rBlocksHardLimit);
 	bool HardLimitExceeded();
@@ -94,7 +94,7 @@
 	//
 	// Function
 	//		Name:    BackupStoreContext::GetDirectory(int64_t)
-	//		Purpose: Return a reference to a directory. Valid only until the 
+	//		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.
 	//		Created: 2003/09/02
@@ -106,7 +106,7 @@
 		// merely turns the the returned directory const.
 		return GetDirectoryInternal(ObjectID);
 	}
-	
+
 	// Manipulating files/directories
 	int64_t AddFile(IOStream &rFile, int64_t InDirectory, int64_t ModificationTime, int64_t AttributesHash, int64_t DiffFromFileID, const BackupStoreFilename &rFilename, bool MarkFileWithSameNameAsOldVersions);
 	int64_t AddDirectory(int64_t InDirectory, const BackupStoreFilename &rFilename, const StreamableMemBlock &Attributes, int64_t AttributesModTime, bool &rAlreadyExists);
@@ -126,14 +126,14 @@
 	};
 	bool ObjectExists(int64_t ObjectID, int MustBe = ObjectExists_Anything);
 	std::auto_ptr<IOStream> OpenObject(int64_t ObjectID);
-	
+
 	// Info
 	int32_t GetClientID() const {return mClientID;}
 
 private:
 	void MakeObjectFilename(int64_t ObjectID, std::string &rOutput, bool EnsureDirectoryExists = false);
 	BackupStoreDirectory &GetDirectoryInternal(int64_t ObjectID);
-	void SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID);
+	void SaveDirectory(BackupStoreDirectory &rDir, int64_t ObjectID, bool AppendLastEntryOnly = false);
 	void RemoveDirectoryFromCache(int64_t ObjectID);
 	void DeleteDirectoryRecurse(int64_t ObjectID, int64_t &rBlocksDeletedOut, bool Undelete);
 	int64_t AllocateObjectID();
@@ -147,13 +147,13 @@
 	bool mReadOnly;
 	NamedLock mWriteLock;
 	int mSaveStoreInfoDelay; // how many times to delay saving the store info
-	
+
 	// Store info
 	std::auto_ptr<BackupStoreInfo> mpStoreInfo;
 
 	// Refcount database
 	std::auto_ptr<BackupStoreRefCountDatabase> mapRefCount;
-	
+
 	// Directory cache
 	std::map<int64_t, BackupStoreDirectory*> mDirectoryCache;
 

Modified: box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.cpp
===================================================================
--- box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.cpp	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.cpp	2010-09-24 00:22:34 UTC (rev 2756)
@@ -267,7 +267,55 @@
 	}
 }
 
+// --------------------------------------------------------------------------
+//
+// Function
+//		Name:    BackupStoreDirectory::UpdateToStream(IOStream &, int16_t, int16_t, bool, bool)
+//		Purpose: Writes the header to a stream
+//		Created: 2010/09/23
+//
+// --------------------------------------------------------------------------
+void BackupStoreDirectory::UpdateToStream(IOStream &rStream, int16_t FlagsMustBeSet, int16_t FlagsNotToBeSet, bool StreamAttributes, bool StreamDependencyInfo) const
+{
+	// Check that sensible IDs have been set
+	ASSERT(mObjectID != 0);
+	ASSERT(mContainerID != 0);
 
+	Entry *pen = mEntries.back();
+
+	if( FlagsMustBeSet == Entry::Flags_INCLUDE_EVERYTHING
+		&& FlagsNotToBeSet == Entry::Flags_EXCLUDE_NOTHING
+		&& !HasDependencyInfo()
+		&& ( (!StreamDependencyInfo && !HasDependencyInfoInline()) || (StreamDependencyInfo && HasDependencyInfoInline() == pen->HasDependencies()) ) )
+	{
+		BOX_TRACE("Appending to directory");
+
+		WriteHeaderToStream(rStream, mEntries.size(), mOptions);
+
+		// Write the attributes?
+		if(StreamAttributes)
+		{
+			mAttributes.WriteToStream(rStream);
+		}
+		else
+		{
+			// Write a blank header instead
+			StreamableMemBlock::WriteEmptyBlockToStream(rStream);
+		}
+
+		rStream.Seek(0, IOStream::SeekType_End);
+		pen->WriteToStream(rStream);
+		if(HasDependencyInfoInline())
+		{
+			pen->WriteToStreamDependencyInfo(rStream);
+		}
+	}
+	else
+	{
+		WriteToStream(rStream, FlagsMustBeSet, FlagsNotToBeSet, StreamAttributes, StreamDependencyInfo);
+	}
+}
+
 // --------------------------------------------------------------------------
 //
 // Function

Modified: box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.h
===================================================================
--- box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.h	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/lib/backupclient/BackupStoreDirectory.h	2010-09-24 00:22:34 UTC (rev 2756)
@@ -130,6 +130,10 @@
 			int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING,
 			int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING,
 			bool StreamAttributes = true, bool StreamDependencyInfo = true) const;
+	void UpdateToStream(IOStream &rStream,
+			int16_t FlagsMustBeSet = Entry::Flags_INCLUDE_EVERYTHING,
+			int16_t FlagsNotToBeSet = Entry::Flags_EXCLUDE_NOTHING,
+			bool StreamAttributes = true, bool StreamDependencyInfo = true) const;
 	void WriteHeaderToStream(IOStream &rStream, int32_t Count, int32_t Options) const;
 
 	Entry *AddEntry(const Entry &rEntryToCopy);

Modified: box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.cpp
===================================================================
--- box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.cpp	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.cpp	2010-09-24 00:22:34 UTC (rev 2756)
@@ -108,8 +108,10 @@
 //		Created: 2003/07/10
 //
 // --------------------------------------------------------------------------
-void RaidFileWrite::Open(bool AllowOverwrite)
+void RaidFileWrite::Open(bool AllowOverwrite, bool UpdateOnly)
 {
+	ASSERT( !(AllowOverwrite && UpdateOnly) );
+
 	if(mOSFileHandle != -1)
 	{
 		THROW_EXCEPTION(RaidFileException, AlreadyOpen)
@@ -134,8 +136,11 @@
 
 	// Get the filename for the write file
 	std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
-	// Add on a temporary extension
-	writeFilename += 'X';
+	if(!UpdateOnly)
+	{
+		// Add on a temporary extension
+		writeFilename += 'X';
+	}
 
 	// Attempt to open
 	mOSFileHandle = ::open(writeFilename.c_str(),
@@ -181,12 +186,16 @@
 		}
 	}
 
-	// Truncate it to size zero
-	if(::ftruncate(mOSFileHandle, 0) != 0)
+	if(!UpdateOnly)
 	{
-		THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFileOnTruncate)
+		// Truncate it to size zero
+		if(::ftruncate(mOSFileHandle, 0) != 0)
+		{
+			THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFileOnTruncate)
+		}
 	}
 
+	mUpdateOnly = UpdateOnly;
 	// Done!
 }
 
@@ -290,40 +299,43 @@
 			RequestedModifyUnreferencedFile);
 	}
 
-	// Rename it into place -- BEFORE it's closed so lock remains
+	if(!mUpdateOnly)
+	{
+		// Rename it into place -- BEFORE it's closed so lock remains
 
 #ifdef WIN32
-	// Except on Win32 which doesn't allow renaming open files
-	// Close file...
-	if(::close(mOSFileHandle) != 0)
-	{
-		THROW_EXCEPTION(RaidFileException, OSError)
-	}
-	mOSFileHandle = -1;
+		// Except on Win32 which doesn't allow renaming open files
+		// Close file...
+		if(::close(mOSFileHandle) != 0)
+		{
+			THROW_EXCEPTION(RaidFileException, OSError)
+		}
+		mOSFileHandle = -1;
 #endif // WIN32
 
-	RaidFileController &rcontroller(RaidFileController::GetController());
-	RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
-	// Get the filename for the write file
-	std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
-	// And the current name
-	std::string renameFrom(renameTo + 'X');
+		RaidFileController &rcontroller(RaidFileController::GetController());
+		RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
+		// Get the filename for the write file
+		std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
+		// And the current name
+		std::string renameFrom(renameTo + 'X');
 
 #ifdef WIN32
-	// need to delete the target first
-	if(::unlink(renameTo.c_str()) != 0 &&
-		GetLastError() != ERROR_FILE_NOT_FOUND)
-	{
-		BOX_LOG_WIN_ERROR("Failed to delete file: " << renameTo);
-		THROW_EXCEPTION(RaidFileException, OSError)
-	}
+		// need to delete the target first
+		if(::unlink(renameTo.c_str()) != 0 &&
+			GetLastError() != ERROR_FILE_NOT_FOUND)
+		{
+			BOX_LOG_WIN_ERROR("Failed to delete file: " << renameTo);
+			THROW_EXCEPTION(RaidFileException, OSError)
+		}
 #endif
 
-	if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
-	{
-		BOX_LOG_SYS_ERROR("Failed to rename file: " << renameFrom <<
-			" to " << renameTo);
-		THROW_EXCEPTION(RaidFileException, OSError)
+		if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
+		{
+			BOX_LOG_SYS_ERROR("Failed to rename file: " << renameFrom <<
+				" to " << renameTo);
+			THROW_EXCEPTION(RaidFileException, OSError)
+		}
 	}
 
 #ifndef WIN32

Modified: box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.h
===================================================================
--- box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.h	2010-09-23 00:10:41 UTC (rev 2755)
+++ box/invisnet/perfhack1/lib/raidfile/RaidFileWrite.h	2010-09-24 00:22:34 UTC (rev 2756)
@@ -44,17 +44,17 @@
 	virtual bool StreamClosed();
 
 	// Extra bits
-	void Open(bool AllowOverwrite = false);
+	void Open(bool AllowOverwrite = false, bool UpdateOnly = false);
 	void Commit(bool ConvertToRaidNow = false);
 	void Discard();
 	void TransformToRaidStorage();
 	void Delete();
 	pos_type GetFileSize();
 	pos_type GetDiscUsageInBlocks();
-	
+
 	static void CreateDirectory(int SetNumber, const std::string &rDirName, bool Recursive = false, int mode = 0777);
 	static void CreateDirectory(const RaidFileDiscSet &rSet, const std::string &rDirName, bool Recursive = false, int mode = 0777);
-	
+
 private:
 
 private:
@@ -62,6 +62,7 @@
 	std::string mFilename;
 	int mOSFileHandle;
 	int mRefCount;
+	bool mUpdateOnly;
 };
 
 #endif // RAIDFILEWRITE__H




More information about the Boxbackup-commit mailing list