source: box/trunk/lib/backupstore/BackupStoreFileCmbDiff.cpp @ 2963

Revision 2963, 9.4 KB checked in by chris, 12 months ago (diff)

Move remaining parts of BackupStoreFile? into lib/backupstore, and fix module
dependencies to fail if anything else required by bbstored is still in
lib/backupclient instead of lib/backupstore.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    BackupStoreFileCmbDiff.cpp
5//              Purpose: Combine two diffs together
6//              Created: 12/7/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <new>
13#include <stdlib.h>
14
15#include "BackupStoreFile.h"
16#include "BackupStoreFileWire.h"
17#include "BackupStoreObjectMagic.h"
18#include "BackupStoreException.h"
19#include "BackupStoreConstants.h"
20#include "BackupStoreFilename.h"
21
22#include "MemLeakFindOn.h"
23
24// --------------------------------------------------------------------------
25//
26// Function
27//              Name:    BackupStoreFile::CombineDiffs(IOStream &, IOStream &, IOStream &rOut)
28//              Purpose: Given two diffs, combine them into a single diff, to produce a diff
29//                               which, combined with the original file, creates the result of applying
30//                               rDiff, then rDiff2. Two opens of rDiff2 are required
31//              Created: 12/7/04
32//
33// --------------------------------------------------------------------------
34void BackupStoreFile::CombineDiffs(IOStream &rDiff1, IOStream &rDiff2, IOStream &rDiff2b, IOStream &rOut)
35{
36        // Skip header of first diff, record where the data starts, and skip to the index
37        int64_t diff1DataStarts = 0;
38        {
39                // Read the header for the From file
40                file_StreamFormat diff1Hdr;
41                if(!rDiff1.ReadFullBuffer(&diff1Hdr, sizeof(diff1Hdr), 0))
42                {
43                        THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
44                }
45                if(ntohl(diff1Hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
46                {
47                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
48                }
49                // Skip over the filename and attributes of the From file
50                // BLOCK
51                {
52                        BackupStoreFilename filename2;
53                        filename2.ReadFromStream(rDiff1, IOStream::TimeOutInfinite);
54                        int32_t size_s;
55                        if(!rDiff1.ReadFullBuffer(&size_s, sizeof(size_s), 0 /* not interested in bytes read if this fails */))
56                        {
57                                THROW_EXCEPTION(CommonException, StreamableMemBlockIncompleteRead)
58                        }
59                        int size = ntohl(size_s);
60                        // Skip forward the size
61                        rDiff1.Seek(size, IOStream::SeekType_Relative);         
62                }
63                // Record position
64                diff1DataStarts = rDiff1.GetPosition();
65                // Skip to index
66                rDiff1.Seek(0 - (((box_ntoh64(diff1Hdr.mNumBlocks)) * sizeof(file_BlockIndexEntry)) + sizeof(file_BlockIndexHeader)), IOStream::SeekType_End);
67        }
68
69        // Read the index of the first diff
70        // Header first
71        file_BlockIndexHeader diff1IdxHdr;
72        if(!rDiff1.ReadFullBuffer(&diff1IdxHdr, sizeof(diff1IdxHdr), 0))
73        {
74                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
75        }
76        if(ntohl(diff1IdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
77        {
78                THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
79        }
80        int64_t diff1NumBlocks = box_ntoh64(diff1IdxHdr.mNumBlocks);
81        // Allocate some memory
82        int64_t *diff1BlockStartPositions = (int64_t*)::malloc((diff1NumBlocks + 1) * sizeof(int64_t));
83        if(diff1BlockStartPositions == 0)
84        {
85                throw std::bad_alloc();
86        }
87
88        // Buffer data
89        void *buffer = 0;
90        int bufferSize = 0;     
91       
92        try
93        {
94                // Then the entries:
95                // For each entry, want to know if it's in the file, and if so, how big it is.
96                // We'll store this as an array of file positions in the file, with an additioal
97                // entry on the end so that we can work out the length of the last block.
98                // If an entry isn't in the file, then store 0 - (position in other file).
99                int64_t diff1Position = diff1DataStarts;
100                for(int64_t b = 0; b < diff1NumBlocks; ++b)
101                {
102                        file_BlockIndexEntry e;
103                        if(!rDiff1.ReadFullBuffer(&e, sizeof(e), 0))
104                        {
105                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
106                        }
107       
108                        // Where's the block?
109                        int64_t blockEn = box_ntoh64(e.mEncodedSize);
110                        if(blockEn <= 0)
111                        {
112                                // Just store the negated block number
113                                diff1BlockStartPositions[b] = blockEn;
114                        }
115                        else
116                        {
117                                // Block is present in this file
118                                diff1BlockStartPositions[b] = diff1Position;
119                                diff1Position += blockEn;
120                        }
121                }
122               
123                // Finish off the list, so the last entry can have it's size calcuated.
124                diff1BlockStartPositions[diff1NumBlocks] = diff1Position;
125
126                // Now read the second diff's header, copying it to the out file
127                file_StreamFormat diff2Hdr;
128                if(!rDiff2.ReadFullBuffer(&diff2Hdr, sizeof(diff2Hdr), 0))
129                {
130                        THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
131                }
132                if(ntohl(diff2Hdr.mMagicValue) != OBJECTMAGIC_FILE_MAGIC_VALUE_V1)
133                {
134                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
135                }
136                // Copy
137                rOut.Write(&diff2Hdr, sizeof(diff2Hdr));
138                // Copy over filename and attributes
139                // BLOCK
140                {
141                        BackupStoreFilename filename;
142                        filename.ReadFromStream(rDiff2, IOStream::TimeOutInfinite);
143                        filename.WriteToStream(rOut);
144                        StreamableMemBlock attr;
145                        attr.ReadFromStream(rDiff2, IOStream::TimeOutInfinite);
146                        attr.WriteToStream(rOut);
147                }
148               
149                // Get to the index of rDiff2b, and read the header
150                MoveStreamPositionToBlockIndex(rDiff2b);
151                file_BlockIndexHeader diff2IdxHdr;
152                if(!rDiff2b.ReadFullBuffer(&diff2IdxHdr, sizeof(diff2IdxHdr), 0))
153                {
154                        THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
155                }
156                if(ntohl(diff2IdxHdr.mMagicValue) != OBJECTMAGIC_FILE_BLOCKS_MAGIC_VALUE_V1)
157                {
158                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
159                }
160                int64_t diff2NumBlocks = box_ntoh64(diff2IdxHdr.mNumBlocks);
161                int64_t diff2IndexEntriesStart = rDiff2b.GetPosition();
162               
163                // Then read all the entries
164                int64_t diff2FilePosition = rDiff2.GetPosition();
165                for(int64_t b = 0; b < diff2NumBlocks; ++b)
166                {
167                        file_BlockIndexEntry e;
168                        if(!rDiff2b.ReadFullBuffer(&e, sizeof(e), 0))
169                        {
170                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
171                        }
172
173                        // What do to next about copying data
174                        bool copyBlock = false;
175                        int copySize = 0;
176                        int64_t copyFrom = 0;
177                        bool fromFileDiff1 = false;
178       
179                        // Where's the block?
180                        int64_t blockEn = box_ntoh64(e.mEncodedSize);
181                        if(blockEn > 0)
182                        {
183                                // Block is present in this file -- copy to out
184                                copyBlock = true;
185                                copyFrom = diff2FilePosition;
186                                copySize = (int)blockEn;
187                               
188                                // Move pointer onwards
189                                diff2FilePosition += blockEn;
190                        }
191                        else
192                        {
193                                // Block isn't present here -- is it present in the old one?
194                                int64_t blockIndex = 0 - blockEn;
195                                if(blockIndex < 0 || blockIndex > diff1NumBlocks)
196                                {
197                                        THROW_EXCEPTION(BackupStoreException, BadBackupStoreFile)
198                                }
199                                if(diff1BlockStartPositions[blockIndex] > 0)
200                                {
201                                        // Block is in the old diff file, copy it across
202                                        copyBlock = true;
203                                        copyFrom = diff1BlockStartPositions[blockIndex];
204                                        int nb = blockIndex + 1;
205                                        while(diff1BlockStartPositions[nb] <= 0)
206                                        {
207                                                // This is safe, because the last entry will terminate it properly!
208                                                ++nb;
209                                                ASSERT(nb <= diff1NumBlocks);
210                                        }
211                                        copySize = diff1BlockStartPositions[nb] - copyFrom;
212                                        fromFileDiff1 = true;
213                                }
214                        }
215                        //TRACE4("%d %d %lld %d\n", copyBlock, copySize, copyFrom, fromFileDiff1);
216                                               
217                        // Copy data to the output file?
218                        if(copyBlock)
219                        {
220                                // Allocate enough space
221                                if(bufferSize < copySize || buffer == 0)
222                                {
223                                        // Free old block
224                                        if(buffer != 0)
225                                        {
226                                                ::free(buffer);
227                                                buffer = 0;
228                                                bufferSize = 0;
229                                        }
230                                        // Allocate new block
231                                        buffer = ::malloc(copySize);
232                                        if(buffer == 0)
233                                        {
234                                                throw std::bad_alloc();
235                                        }
236                                        bufferSize = copySize;
237                                }
238                                ASSERT(bufferSize >= copySize);
239                               
240                                // Load in the data
241                                if(fromFileDiff1)
242                                {
243                                        rDiff1.Seek(copyFrom, IOStream::SeekType_Absolute);
244                                        if(!rDiff1.ReadFullBuffer(buffer, copySize, 0))
245                                        {
246                                                THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
247                                        }
248                                }
249                                else
250                                {
251                                        rDiff2.Seek(copyFrom, IOStream::SeekType_Absolute);
252                                        if(!rDiff2.ReadFullBuffer(buffer, copySize, 0))
253                                        {
254                                                THROW_EXCEPTION(BackupStoreException, FailedToReadBlockOnCombine)
255                                        }
256                                }
257                                // Write out data
258                                rOut.Write(buffer, copySize);
259                        }
260                }
261               
262                // Write the modified header
263                diff2IdxHdr.mOtherFileID = diff1IdxHdr.mOtherFileID;
264                rOut.Write(&diff2IdxHdr, sizeof(diff2IdxHdr));
265               
266                // Then we'll write out the index, reading the data again
267                rDiff2b.Seek(diff2IndexEntriesStart, IOStream::SeekType_Absolute);
268                for(int64_t b = 0; b < diff2NumBlocks; ++b)
269                {
270                        file_BlockIndexEntry e;
271                        if(!rDiff2b.ReadFullBuffer(&e, sizeof(e), 0))
272                        {
273                                THROW_EXCEPTION(BackupStoreException, CouldntReadEntireStructureFromStream)
274                        }
275       
276                        // Where's the block?
277                        int64_t blockEn = box_ntoh64(e.mEncodedSize);
278               
279                        // If it's not in this file, it needs modification...
280                        if(blockEn <= 0)
281                        {
282                                int64_t blockIndex = 0 - blockEn;
283                                // In another file. Need to translate this against the other diff
284                                if(diff1BlockStartPositions[blockIndex] > 0)
285                                {
286                                        // Block is in the first diff file, stick in size
287                                        int nb = blockIndex + 1;
288                                        while(diff1BlockStartPositions[nb] <= 0)
289                                        {
290                                                // This is safe, because the last entry will terminate it properly!
291                                                ++nb;
292                                                ASSERT(nb <= diff1NumBlocks);
293                                        }
294                                        int64_t size = diff1BlockStartPositions[nb] - diff1BlockStartPositions[blockIndex];
295                                        e.mEncodedSize = box_hton64(size);
296                                }
297                                else
298                                {
299                                        // Block in the original file, use translated value
300                                        e.mEncodedSize = box_hton64(diff1BlockStartPositions[blockIndex]);
301                                }
302                        }
303                       
304                        // Write entry
305                        rOut.Write(&e, sizeof(e));
306                }
307        }
308        catch(...)
309        {
310                // clean up
311                ::free(diff1BlockStartPositions);
312                if(buffer != 0)
313                {
314                        ::free(buffer);
315                }
316                throw;
317        }
318       
319        // Clean up allocated memory
320        ::free(diff1BlockStartPositions);
321        if(buffer != 0)
322        {
323                ::free(buffer);
324        }
325}
326
Note: See TracBrowser for help on using the repository browser.