source: box/trunk/lib/backupstore/BackupStoreRefCountDatabase.cpp @ 2968

Revision 2968, 9.1 KB checked in by chris, 11 months ago (diff)

Improve error logging for store info and refcount database errors.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreRefCountDatabase.cpp
5//              Purpose: Backup store object reference count database storage
6//              Created: 2009/06/01
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <algorithm>
13
14#include "BackupStoreRefCountDatabase.h"
15#include "BackupStoreException.h"
16#include "BackupStoreAccountDatabase.h"
17#include "BackupStoreAccounts.h"
18#include "RaidFileController.h"
19#include "RaidFileUtil.h"
20#include "RaidFileException.h"
21#include "Utils.h"
22
23#include "MemLeakFindOn.h"
24
25#define REFCOUNT_MAGIC_VALUE    0x52656643 // RefC
26#define REFCOUNT_FILENAME       "refcount"
27
28// --------------------------------------------------------------------------
29//
30// Function
31//              Name:    BackupStoreRefCountDatabase::BackupStoreRefCountDatabase()
32//              Purpose: Default constructor
33//              Created: 2003/08/28
34//
35// --------------------------------------------------------------------------
36BackupStoreRefCountDatabase::BackupStoreRefCountDatabase(const
37        BackupStoreAccountDatabase::Entry& rAccount)
38: mAccount(rAccount),
39  mFilename(GetFilename(rAccount)),
40  mReadOnly(true),
41  mIsModified(false)
42{
43}
44
45// --------------------------------------------------------------------------
46//
47// Function
48//              Name:    BackupStoreRefCountDatabase::~BackupStoreRefCountDatabase
49//              Purpose: Destructor
50//              Created: 2003/08/28
51//
52// --------------------------------------------------------------------------
53BackupStoreRefCountDatabase::~BackupStoreRefCountDatabase()
54{
55}
56
57std::string BackupStoreRefCountDatabase::GetFilename(const
58        BackupStoreAccountDatabase::Entry& rAccount)
59{
60        std::string RootDir = BackupStoreAccounts::GetAccountRoot(rAccount);
61        ASSERT(RootDir[RootDir.size() - 1] == '/' ||
62                RootDir[RootDir.size() - 1] == DIRECTORY_SEPARATOR_ASCHAR);
63
64        std::string fn(RootDir + REFCOUNT_FILENAME ".db");
65        RaidFileController &rcontroller(RaidFileController::GetController());
66        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(rAccount.GetDiscSet()));
67        return RaidFileUtil::MakeWriteFileName(rdiscSet, fn);
68}
69
70// --------------------------------------------------------------------------
71//
72// Function
73//              Name:    BackupStoreRefCountDatabase::Create(int32_t,
74//                       const std::string &, int, bool)
75//              Purpose: Create a new database, overwriting an existing
76//                       one only if AllowOverwrite is true.
77//              Created: 2003/08/28
78//
79// --------------------------------------------------------------------------
80void BackupStoreRefCountDatabase::Create(const
81        BackupStoreAccountDatabase::Entry& rAccount, bool AllowOverwrite)
82{
83        // Initial header
84        refcount_StreamFormat hdr;
85        hdr.mMagicValue = htonl(REFCOUNT_MAGIC_VALUE);
86        hdr.mAccountID = htonl(rAccount.GetID());
87       
88        // Generate the filename
89        std::string Filename = GetFilename(rAccount);
90
91        // Open the file for writing
92        if (FileExists(Filename) && !AllowOverwrite)
93        {
94                THROW_FILE_ERROR("Failed to overwrite refcount database: "
95                        "not allowed here", Filename, RaidFileException,
96                        CannotOverwriteExistingFile);
97        }
98
99        int flags = O_CREAT | O_BINARY | O_RDWR;
100        if (!AllowOverwrite)
101        {
102                flags |= O_EXCL;
103        }
104
105        std::auto_ptr<FileStream> DatabaseFile(new FileStream(Filename, flags));
106       
107        // Write header
108        DatabaseFile->Write(&hdr, sizeof(hdr));
109}
110
111// --------------------------------------------------------------------------
112//
113// Function
114//              Name:    BackupStoreRefCountDatabase::Load(int32_t AccountID,
115//                       BackupStoreAccountDatabase& rAccountDatabase,
116//                       bool ReadOnly);
117//              Purpose: Loads the info from disc, given the root
118//                       information. Can be marked as read only.
119//              Created: 2003/08/28
120//
121// --------------------------------------------------------------------------
122std::auto_ptr<BackupStoreRefCountDatabase> BackupStoreRefCountDatabase::Load(
123        const BackupStoreAccountDatabase::Entry& rAccount, bool ReadOnly)
124{
125        // Generate the filename
126        std::string filename = GetFilename(rAccount);
127        int flags = ReadOnly ? O_RDONLY : O_RDWR;
128
129        // Open the file for read/write
130        std::auto_ptr<FileStream> dbfile(new FileStream(filename,
131                flags | O_BINARY));
132       
133        // Read in a header
134        refcount_StreamFormat hdr;
135        if(!dbfile->ReadFullBuffer(&hdr, sizeof(hdr), 0 /* not interested in bytes read if this fails */))
136        {
137                THROW_FILE_ERROR("Failed to read refcount database: "
138                        "short read", filename, BackupStoreException,
139                        CouldNotLoadStoreInfo);
140        }
141       
142        // Check it
143        if(ntohl(hdr.mMagicValue) != REFCOUNT_MAGIC_VALUE ||
144                (int32_t)ntohl(hdr.mAccountID) != rAccount.GetID())
145        {
146                THROW_FILE_ERROR("Failed to read refcount database: "
147                        "bad magic number", filename, BackupStoreException,
148                        BadStoreInfoOnLoad);
149        }
150       
151        // Make new object
152        std::auto_ptr<BackupStoreRefCountDatabase> refcount(new BackupStoreRefCountDatabase(rAccount));
153       
154        // Put in basic location info
155        refcount->mReadOnly = ReadOnly;
156        refcount->mapDatabaseFile = dbfile;
157       
158        // return it to caller
159        return refcount;
160}
161
162// --------------------------------------------------------------------------
163//
164// Function
165//              Name:    BackupStoreRefCountDatabase::Save()
166//              Purpose: Save modified info back to disc
167//              Created: 2003/08/28
168//
169// --------------------------------------------------------------------------
170/*
171void BackupStoreRefCountDatabase::Save()
172{
173        // Make sure we're initialised (although should never come to this)
174        if(mFilename.empty() || mAccount.GetID() == 0)
175        {
176                THROW_EXCEPTION(BackupStoreException, Internal)
177        }
178
179        // Can we do this?
180        if(mReadOnly)
181        {
182                THROW_EXCEPTION(BackupStoreException, StoreInfoIsReadOnly)
183        }
184       
185        // Then... open a write file
186        RaidFileWrite rf(mAccount.GetDiscSet(), mFilename);
187        rf.Open(true);          // allow overwriting
188       
189        // Make header
190        info_StreamFormat hdr;
191        hdr.mMagicValue                         = htonl(INFO_MAGIC_VALUE);
192        hdr.mAccountID                          = htonl(mAccountID);
193        hdr.mClientStoreMarker                  = box_hton64(mClientStoreMarker);
194        hdr.mLastObjectIDUsed                   = box_hton64(mLastObjectIDUsed);
195        hdr.mBlocksUsed                                 = box_hton64(mBlocksUsed);
196        hdr.mBlocksInOldFiles                   = box_hton64(mBlocksInOldFiles);
197        hdr.mBlocksInDeletedFiles               = box_hton64(mBlocksInDeletedFiles);
198        hdr.mBlocksInDirectories                = box_hton64(mBlocksInDirectories);
199        hdr.mBlocksSoftLimit                    = box_hton64(mBlocksSoftLimit);
200        hdr.mBlocksHardLimit                    = box_hton64(mBlocksHardLimit);
201        hdr.mCurrentMarkNumber                  = 0;
202        hdr.mOptionsPresent                             = 0;
203        hdr.mNumberDeletedDirectories   = box_hton64(mDeletedDirectories.size());
204       
205        // Write header
206        rf.Write(&hdr, sizeof(hdr));
207       
208        // Write the deleted object list
209        if(mDeletedDirectories.size() > 0)
210        {
211                int64_t objs[NUM_DELETED_DIRS_BLOCK];
212               
213                int tosave = mDeletedDirectories.size();
214                std::vector<int64_t>::iterator i(mDeletedDirectories.begin());
215                while(tosave > 0)
216                {
217                        // How many in this one?
218                        int b = (tosave > NUM_DELETED_DIRS_BLOCK)?NUM_DELETED_DIRS_BLOCK:((int)(tosave));
219                       
220                        // Add them
221                        for(int t = 0; t < b; ++t)
222                        {
223                                ASSERT(i != mDeletedDirectories.end());
224                                objs[t] = box_hton64((*i));
225                                i++;
226                        }
227
228                        // Write                       
229                        rf.Write(objs, b * sizeof(int64_t));
230                       
231                        // Number saved
232                        tosave -= b;
233                }
234        }
235
236        // Commit it to disc, converting it to RAID now
237        rf.Commit(true);
238       
239        // Mark is as not modified
240        mIsModified = false;
241}
242*/
243
244
245// --------------------------------------------------------------------------
246//
247// Function
248//              Name:    BackupStoreRefCountDatabase::GetRefCount(int64_t
249//                       ObjectID)
250//              Purpose: Get the number of references to the specified object
251//                       out of the database
252//              Created: 2009/06/01
253//
254// --------------------------------------------------------------------------
255BackupStoreRefCountDatabase::refcount_t
256BackupStoreRefCountDatabase::GetRefCount(int64_t ObjectID) const
257{
258        IOStream::pos_type offset = GetOffset(ObjectID);
259
260        if (GetSize() < offset + GetEntrySize())
261        {
262                THROW_FILE_ERROR("Failed to read refcount database: "
263                        "attempted read of unknown refcount for object " <<
264                        BOX_FORMAT_OBJECTID(ObjectID), mFilename,
265                        BackupStoreException, UnknownObjectRefCountRequested);
266        }
267
268        mapDatabaseFile->Seek(offset, SEEK_SET);
269
270        refcount_t refcount;
271        if (mapDatabaseFile->Read(&refcount, sizeof(refcount)) !=
272                sizeof(refcount))
273        {
274                THROW_FILE_ERROR("Failed to read refcount database: "
275                        "short read at offset " << offset, mFilename,
276                        BackupStoreException, CouldNotLoadStoreInfo);
277        }
278
279        return ntohl(refcount);
280}
281
282int64_t BackupStoreRefCountDatabase::GetLastObjectIDUsed() const
283{
284        return (GetSize() - sizeof(refcount_StreamFormat)) /
285                sizeof(refcount_t);
286}
287
288void BackupStoreRefCountDatabase::AddReference(int64_t ObjectID)
289{
290        refcount_t refcount;
291
292        if (ObjectID > GetLastObjectIDUsed())
293        {
294                // new object, assume no previous references
295                refcount = 0;
296        }
297        else
298        {
299                // read previous value from database
300                refcount = GetRefCount(ObjectID);
301        }
302
303        refcount++;
304
305        SetRefCount(ObjectID, refcount);
306}
307
308void BackupStoreRefCountDatabase::SetRefCount(int64_t ObjectID,
309        refcount_t NewRefCount)
310{
311        IOStream::pos_type offset = GetOffset(ObjectID);
312        mapDatabaseFile->Seek(offset, SEEK_SET);
313        refcount_t RefCountNetOrder = htonl(NewRefCount);
314        mapDatabaseFile->Write(&RefCountNetOrder, sizeof(RefCountNetOrder));
315}
316
317bool BackupStoreRefCountDatabase::RemoveReference(int64_t ObjectID)
318{
319        refcount_t refcount = GetRefCount(ObjectID); // must exist in database
320        ASSERT(refcount > 0);
321        refcount--;
322        SetRefCount(ObjectID, refcount);
323        return (refcount > 0);
324}
325
Note: See TracBrowser for help on using the repository browser.