source: box/trunk/test/backupstorepatch/testbackupstorepatch.cpp @ 2983

Revision 2983, 19.1 KB checked in by chris, 9 months ago (diff)

Combine client and server protocols to make way for an offline/local protocol.

Rename ProtocolObject? to Message.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    testbackupstorepatch.cpp
5//              Purpose: Test storage of patches on the backup store server
6//              Created: 13/7/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <stdlib.h>
13#include <string.h>
14#include <signal.h>
15
16#include "autogen_BackupProtocol.h"
17#include "BackupClientCryptoKeys.h"
18#include "BackupClientFileAttributes.h"
19#include "BackupStoreAccountDatabase.h"
20#include "BackupStoreAccounts.h"
21#include "BackupStoreConstants.h"
22#include "BackupStoreDirectory.h"
23#include "BackupStoreException.h"
24#include "BackupStoreFile.h"
25#include "BackupStoreFilenameClear.h"
26#include "BackupStoreInfo.h"
27#include "BoxPortsAndFiles.h"
28#include "CollectInBufferStream.h"
29#include "FileStream.h"
30#include "MemBlockStream.h"
31#include "RaidFileController.h"
32#include "RaidFileException.h"
33#include "RaidFileRead.h"
34#include "RaidFileUtil.h"
35#include "RaidFileWrite.h"
36#include "SSLLib.h"
37#include "ServerControl.h"
38#include "Socket.h"
39#include "SocketStreamTLS.h"
40#include "StoreStructure.h"
41#include "TLSContext.h"
42#include "Test.h"
43
44#include "MemLeakFindOn.h"
45
46typedef struct
47{
48        int ChangePoint, InsertBytes, DeleteBytes;
49        int64_t IDOnServer;
50        bool IsCompletelyDifferent;
51        bool HasBeenDeleted;
52        int64_t DepNewer, DepOlder;
53} file_info;
54
55file_info test_files[] =
56{
57//   ChPnt,     Insert, Delete, ID, IsCDf,      BeenDel
58        {0,     0,              0,              0,      false,  false}, // 0 dummy first entry
59        {32000, 2087,   0,              0,      false,  false}, // 1
60        {1000,  1998,   2976,   0,      false,  false}, // 2
61        {27800, 0,              288,    0,      false,  false}, // 3
62        {3208,  1087,   98,             0,      false,  false}, // 4
63        {56000, 23087,  98,             0,      false,  false}, // 5
64        {0,             98765,  9999999,0,      false,  false}, // 6 completely different, make a break in the storage
65        {9899,  9887,   2,              0,      false,  false}, // 7
66        {12984, 12345,  1234,   0,      false,  false}, // 8
67        {1209,  29885,  3498,   0,      false,  false}  // 9
68};
69
70// Order in which the files will be removed from the server
71int test_file_remove_order[] = {0, 2, 3, 5, 8, 1, 4, -1};
72
73#define NUMBER_FILES    ((sizeof(test_files) / sizeof(test_files[0])))
74#define FIRST_FILE_SIZE (64*1024+3)
75#define BUFFER_SIZE             (256*1024)
76
77// Chunk of memory to use for copying files, etc
78static void *buffer = 0;
79
80int64_t ModificationTime = 7766333330000LL;
81#define MODIFICATION_TIME_INC   10000000;
82
83// Nice random data for testing written files
84class R250 {
85public:
86        // Set up internal state table with 32-bit random numbers. 
87        // The bizarre bit-twiddling is because rand() returns 16 bits of which
88        // the bottom bit is always zero!  Hence, I use only some of the bits.
89        // You might want to do something better than this....
90
91        R250(int seed) : posn1(0), posn2(103)
92        {
93                // populate the state and incr tables
94                srand(seed);
95
96                for (int i = 0; i != stateLen; ++i)     {
97                        state[i] = ((rand() >> 2) << 19) ^ ((rand() >> 2) << 11) ^ (rand() >> 2);
98                        incrTable[i] = i == stateLen - 1 ? 0 : i + 1;
99                }
100
101                // stir up the numbers to ensure they're random
102
103                for (int j = 0; j != stateLen * 4; ++j)                 
104                        (void) next();
105        }
106
107        // Returns the next random number.  Xor together two elements separated
108        // by 103 mod 250, replacing the first element with the result.  Then
109        // increment the two indices mod 250.
110        inline int next()
111        {
112                int ret = (state[posn1] ^= state[posn2]);       // xor and replace element
113
114                posn1 = incrTable[posn1];               // increment indices using lookup table
115                posn2 = incrTable[posn2];
116
117                return ret;
118        }
119private:
120        enum { stateLen = 250 };        // length of the state table
121        int state[stateLen];            // holds the random number state
122        int incrTable[stateLen];        // lookup table: maps i to (i+1) % stateLen
123        int posn1, posn2;                       // indices into the state table
124};
125
126// will overrun the buffer!
127void make_random_data(void *buffer, int size, int seed)
128{
129        R250 rand(seed);
130
131        int n = (size / sizeof(int)) + 1;
132        int *b = (int*)buffer;
133        for(int l = 0; l < n; ++l)
134        {
135                b[l] = rand.next();
136        }
137}
138
139bool files_identical(const char *file1, const char *file2)
140{
141        FileStream f1(file1);
142        FileStream f2(file2);
143       
144        if(f1.BytesLeftToRead() != f2.BytesLeftToRead())
145        {
146                return false;
147        }
148       
149        while(f1.StreamDataLeft())
150        {
151                char buffer1[2048];
152                char buffer2[2048];
153                int s = f1.Read(buffer1, sizeof(buffer1));
154                if(f2.Read(buffer2, s) != s)
155                {
156                        return false;
157                }
158                if(::memcmp(buffer1, buffer2, s) != 0)
159                {
160                        return false;
161                }
162        }
163       
164        if(f2.StreamDataLeft())
165        {
166                return false;
167        }
168       
169        return true;
170}
171
172
173
174void create_test_files()
175{
176        // Create first file
177        {
178                make_random_data(buffer, FIRST_FILE_SIZE, 98);
179                FileStream out("testfiles/0.test", O_WRONLY | O_CREAT);
180                out.Write(buffer, FIRST_FILE_SIZE);
181        }
182       
183        // Create other files
184        int seed = 987;
185        for(unsigned int f = 1; f < NUMBER_FILES; ++f)
186        {
187                // Open files
188                char fnp[64];
189                sprintf(fnp, "testfiles/%d.test", f - 1);
190                FileStream previous(fnp);
191                char fnt[64];
192                sprintf(fnt, "testfiles/%d.test", f);
193                FileStream out(fnt, O_WRONLY | O_CREAT);
194               
195                // Copy up to the change point
196                int b = previous.Read(buffer, test_files[f].ChangePoint, IOStream::TimeOutInfinite);
197                out.Write(buffer, b);
198               
199                // Add new bytes?
200                if(test_files[f].InsertBytes > 0)
201                {
202                        make_random_data(buffer, test_files[f].InsertBytes, ++seed);
203                        out.Write(buffer, test_files[f].InsertBytes);
204                }
205                // Delete bytes?
206                if(test_files[f].DeleteBytes > 0)
207                {
208                        previous.Seek(test_files[f].DeleteBytes, IOStream::SeekType_Relative);
209                }
210                // Copy rest of data
211                b = previous.Read(buffer, BUFFER_SIZE, IOStream::TimeOutInfinite);
212                out.Write(buffer, b);
213        }
214}
215
216void test_depends_in_dirs()
217{
218        BackupStoreFilenameClear storeFilename("test");
219
220        {
221                // Save directory with no dependency info
222                BackupStoreDirectory dir(1000, 1001); // some random ids
223                dir.AddEntry(storeFilename, 1, 2, 3, BackupStoreDirectory::Entry::Flags_File, 4);
224                dir.AddEntry(storeFilename, 1, 3, 3, BackupStoreDirectory::Entry::Flags_File, 4);
225                dir.AddEntry(storeFilename, 1, 4, 3, BackupStoreDirectory::Entry::Flags_File, 4);
226                dir.AddEntry(storeFilename, 1, 5, 3, BackupStoreDirectory::Entry::Flags_File, 4);
227                {
228                        FileStream out("testfiles/dir.0", O_WRONLY | O_CREAT);
229                        dir.WriteToStream(out);
230                }
231                // Add some dependency info to one of them
232                BackupStoreDirectory::Entry *en = dir.FindEntryByID(3);
233                TEST_THAT(en != 0);
234                en->SetDependsNewer(4);
235                // Save again
236                {
237                        FileStream out("testfiles/dir.1", O_WRONLY | O_CREAT);
238                        dir.WriteToStream(out);
239                }
240                // Check that the file size increases as expected.
241                TEST_THAT(TestGetFileSize("testfiles/dir.1") == (TestGetFileSize("testfiles/dir.0") + (4*16)));
242        }
243        {
244                // Load the directory back in
245                BackupStoreDirectory dir2;
246                FileStream in("testfiles/dir.1");
247                dir2.ReadFromStream(in, IOStream::TimeOutInfinite);
248                // Check entries
249                TEST_THAT(dir2.GetNumberOfEntries() == 4);
250                for(int i = 2; i <= 5; ++i)
251                {
252                        BackupStoreDirectory::Entry *en = dir2.FindEntryByID(i);
253                        TEST_THAT(en != 0);
254                        TEST_THAT(en->GetDependsNewer() == ((i == 3)?4:0));
255                        TEST_THAT(en->GetDependsOlder() == 0);
256                }
257                dir2.Dump(0, true);
258                // Test that numbers go in and out as required
259                for(int i = 2; i <= 5; ++i)
260                {
261                        BackupStoreDirectory::Entry *en = dir2.FindEntryByID(i);
262                        TEST_THAT(en != 0);
263                        en->SetDependsNewer(i + 1);
264                        en->SetDependsOlder(i - 1);
265                }
266                // Save
267                {
268                        FileStream out("testfiles/dir.2", O_WRONLY | O_CREAT);
269                        dir2.WriteToStream(out);
270                }
271                // Load and check
272                {
273                        BackupStoreDirectory dir3;
274                        FileStream in("testfiles/dir.2");
275                        dir3.ReadFromStream(in, IOStream::TimeOutInfinite);
276                        dir3.Dump(0, true);
277                        for(int i = 2; i <= 5; ++i)
278                        {
279                                BackupStoreDirectory::Entry *en = dir2.FindEntryByID(i);
280                                TEST_THAT(en != 0);
281                                TEST_THAT(en->GetDependsNewer() == (i + 1));
282                                TEST_THAT(en->GetDependsOlder() == (i - 1));
283                        }
284                }
285        }
286}
287
288
289int test(int argc, const char *argv[])
290{
291        // Allocate a buffer
292        buffer = ::malloc(BUFFER_SIZE);
293        TEST_THAT(buffer != 0);
294
295        // SSL library
296        SSLLib::Initialise();
297       
298        // Use the setup crypto command to set up all these keys, so that the bbackupquery command can be used
299        // for seeing what's going on.
300        BackupClientCryptoKeys_Setup("testfiles/bbackupd.keys");       
301
302        // Trace errors out
303        SET_DEBUG_SSLLIB_TRACE_ERRORS
304
305        // Initialise the raid file controller
306        RaidFileController &rcontroller = RaidFileController::GetController();
307        rcontroller.Initialise("testfiles/raidfile.conf");
308
309        // Context
310        TLSContext context;
311        context.Initialise(false /* client */,
312                        "testfiles/clientCerts.pem",
313                        "testfiles/clientPrivKey.pem",
314                        "testfiles/clientTrustedCAs.pem");
315
316        // Create an account
317        TEST_THAT_ABORTONFAIL(::system(BBSTOREACCOUNTS
318                " -c testfiles/bbstored.conf "
319                "create 01234567 0 30000B 40000B") == 0);
320        TestRemoteProcessMemLeaks("bbstoreaccounts.memleaks");
321
322        // Create test files
323        create_test_files();
324       
325        // Check the basic directory stuff works
326        test_depends_in_dirs();
327       
328        std::string storeRootDir;
329        int discSet = 0;
330        {
331                std::auto_ptr<BackupStoreAccountDatabase> apDatabase(
332                        BackupStoreAccountDatabase::Read("testfiles/accounts.txt"));
333                BackupStoreAccounts accounts(*apDatabase);
334                accounts.GetAccountRoot(0x1234567, storeRootDir, discSet);
335        }
336        RaidFileDiscSet rfd(rcontroller.GetDiscSet(discSet));
337
338        int pid = LaunchServer(BBSTORED " testfiles/bbstored.conf", 
339                "testfiles/bbstored.pid");
340        TEST_THAT(pid != -1 && pid != 0);
341        if(pid > 0)
342        {
343                TEST_THAT(ServerIsAlive(pid));
344
345                {
346                        // Open a connection to the server
347                        SocketStreamTLS conn;
348                        conn.Open(context, Socket::TypeINET, "localhost",
349                                BOX_PORT_BBSTORED_TEST);
350       
351                        // Make a protocol
352                        BackupProtocolClient protocol(conn);
353       
354                        // Login
355                        {
356                                // Check the version
357                                std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
358                                TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
359       
360                                // Login
361                                protocol.QueryLogin(0x01234567, 0);
362                        }
363       
364                        // Filename for server
365                        BackupStoreFilenameClear storeFilename("test");
366       
367                        // Upload the first file
368                        {
369                                std::auto_ptr<IOStream> upload(BackupStoreFile::EncodeFile("testfiles/0.test",
370                                                BackupProtocolListDirectory::RootDirectory, storeFilename));
371                                std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
372                                                BackupProtocolListDirectory::RootDirectory, ModificationTime,
373                                                ModificationTime, 0 /* no diff from file ID */, storeFilename, *upload));
374                                test_files[0].IDOnServer = stored->GetObjectID();
375                                test_files[0].IsCompletelyDifferent = true;
376                                ModificationTime += MODIFICATION_TIME_INC;
377                        }
378                       
379                        // Upload the other files, using the diffing process
380                        for(unsigned int f = 1; f < NUMBER_FILES; ++f)
381                        {
382                                // Get an index for the previous version
383                                std::auto_ptr<BackupProtocolSuccess> getBlockIndex(protocol.QueryGetBlockIndexByName(
384                                                BackupProtocolListDirectory::RootDirectory, storeFilename));
385                                int64_t diffFromID = getBlockIndex->GetObjectID();
386                                TEST_THAT(diffFromID != 0);
387                               
388                                if(diffFromID != 0)
389                                {
390                                        // Found an old version -- get the index
391                                        std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
392                               
393                                        // Diff the file
394                                        char filename[64];
395                                        ::sprintf(filename, "testfiles/%d.test", f);
396                                        bool isCompletelyDifferent = false;
397                                        std::auto_ptr<IOStream> patchStream(
398                                                BackupStoreFile::EncodeFileDiff(
399                                                        filename,
400                                                        BackupProtocolListDirectory::RootDirectory,     /* containing directory */
401                                                        storeFilename, 
402                                                        diffFromID, 
403                                                        *blockIndexStream,
404                                                        protocol.GetTimeout(), 
405                                                        NULL, // DiffTimer impl
406                                                        0 /* not interested in the modification time */, 
407                                                        &isCompletelyDifferent));
408               
409                                        // Upload the patch to the store
410                                        std::auto_ptr<BackupProtocolSuccess> stored(protocol.QueryStoreFile(
411                                                        BackupProtocolListDirectory::RootDirectory, ModificationTime,
412                                                        ModificationTime, isCompletelyDifferent?(0):(diffFromID), storeFilename, *patchStream));
413                                        ModificationTime += MODIFICATION_TIME_INC;
414                                       
415                                        // Store details
416                                        test_files[f].IDOnServer = stored->GetObjectID();
417                                        test_files[f].IsCompletelyDifferent = isCompletelyDifferent;
418
419#ifdef WIN32
420                                        printf("ID %I64d, completely different: %s\n",
421#else
422                                        printf("ID %lld, completely different: %s\n", 
423#endif
424                                                test_files[f].IDOnServer,
425                                                test_files[f].IsCompletelyDifferent?"yes":"no");                       
426                                }
427                                else
428                                {
429                                        ::printf("WARNING: Block index not obtained when diffing file %d!\n", f);
430                                }
431                        }
432                       
433                        // List the directory from the server, and check that no dependency info is sent -- waste of bytes
434                        {
435                                std::auto_ptr<BackupProtocolSuccess> dirreply(protocol.QueryListDirectory(
436                                                BackupProtocolListDirectory::RootDirectory,
437                                                BackupProtocolListDirectory::Flags_INCLUDE_EVERYTHING,
438                                                BackupProtocolListDirectory::Flags_EXCLUDE_NOTHING, false /* no attributes */));
439                                // Stream
440                                BackupStoreDirectory dir;
441                                std::auto_ptr<IOStream> dirstream(protocol.ReceiveStream());
442                                dir.ReadFromStream(*dirstream, IOStream::TimeOutInfinite);
443                               
444                                BackupStoreDirectory::Iterator i(dir);
445                                BackupStoreDirectory::Entry *en = 0;
446                                while((en = i.Next()) != 0)
447                                {
448                                        TEST_THAT(en->GetDependsNewer() == 0);
449                                        TEST_THAT(en->GetDependsOlder() == 0);
450                                }
451                        }
452
453                        // Finish the connection
454                        protocol.QueryFinished();
455                        conn.Close();
456                }
457
458                // Fill in initial dependency information
459                for(unsigned int f = 0; f < NUMBER_FILES; ++f)
460                {
461                        int64_t newer = (f < (NUMBER_FILES - 1))?test_files[f + 1].IDOnServer:0;
462                        int64_t older = (f > 0)?test_files[f - 1].IDOnServer:0;
463                        if(test_files[f].IsCompletelyDifferent)
464                        {
465                                older = 0;
466                        }
467                        if(f < (NUMBER_FILES - 1) && test_files[f + 1].IsCompletelyDifferent)
468                        {
469                                newer = 0;
470                        }
471                        test_files[f].DepNewer = newer;
472                        test_files[f].DepOlder = older;
473                }
474
475                // Check the stuff on the server
476                int deleteIndex = 0;
477                while(true)
478                {
479                        // Load up the root directory
480                        BackupStoreDirectory dir;
481                        {
482                                std::auto_ptr<RaidFileRead> dirStream(RaidFileRead::Open(0, "backup/01234567/o01"));
483                                dir.ReadFromStream(*dirStream, IOStream::TimeOutInfinite);
484                                dir.Dump(0, true);
485                               
486                                // Check that dependency info is correct
487                                for(unsigned int f = 0; f < NUMBER_FILES; ++f)
488                                {
489                                        //TRACE1("t f = %d\n", f);
490                                        BackupStoreDirectory::Entry *en = dir.FindEntryByID(test_files[f].IDOnServer);
491                                        if(en == 0)
492                                        {
493                                                TEST_THAT(test_files[f].HasBeenDeleted);
494                                                // check that unreferenced
495                                                // object was removed by
496                                                // housekeeping
497                                                std::string filenameOut;
498                                                int startDisc = 0;
499                                                StoreStructure::MakeObjectFilename(
500                                                        test_files[f].IDOnServer,
501                                                        storeRootDir, discSet,
502                                                        filenameOut,
503                                                        false /* don't bother ensuring the directory exists */);
504                                                TEST_EQUAL(RaidFileUtil::NoFile,
505                                                        RaidFileUtil::RaidFileExists(
506                                                                rfd, filenameOut));
507                                        }
508                                        else
509                                        {
510                                                TEST_THAT(!test_files[f].HasBeenDeleted);
511                                                TEST_THAT(en->GetDependsNewer() == test_files[f].DepNewer);
512                                                TEST_THAT(en->GetDependsOlder() == test_files[f].DepOlder);
513                                                // Test that size is plausible
514                                                if(en->GetDependsNewer() == 0)
515                                                {
516                                                        // Should be a full file
517                                                        TEST_THAT(en->GetSizeInBlocks() > 40);
518                                                }
519                                                else
520                                                {
521                                                        // Should be a patch
522                                                        TEST_THAT(en->GetSizeInBlocks() < 40);
523                                                }
524                                        }
525                                }
526                        }
527                       
528                        // Open a connection to the server (need to do this each time, otherwise housekeeping won't delete files)
529                        SocketStreamTLS conn;
530                        conn.Open(context, Socket::TypeINET, "localhost",
531                                BOX_PORT_BBSTORED_TEST);
532                        BackupProtocolClient protocol(conn);
533                        {
534                                std::auto_ptr<BackupProtocolVersion> serverVersion(protocol.QueryVersion(BACKUP_STORE_SERVER_VERSION));
535                                TEST_THAT(serverVersion->GetVersion() == BACKUP_STORE_SERVER_VERSION);
536                                protocol.QueryLogin(0x01234567, 0);
537                        }
538
539                        // Pull all the files down, and check that they match the files on disc
540                        for(unsigned int f = 0; f < NUMBER_FILES; ++f)
541                        {
542                                ::printf("r=%d, f=%d\n", deleteIndex, f);
543                               
544                                // Might have been deleted
545                                if(test_files[f].HasBeenDeleted)
546                                {
547                                        continue;
548                                }
549                       
550                                // Filenames
551                                char filename[64], filename_fetched[64];
552                                ::sprintf(filename, "testfiles/%d.test", f);
553                                ::sprintf(filename_fetched, "testfiles/%d.test.fetched", f);
554                                ::unlink(filename_fetched);
555       
556                                // Fetch the file
557                                {
558                                        std::auto_ptr<BackupProtocolSuccess> getobj(protocol.QueryGetFile(
559                                                BackupProtocolListDirectory::RootDirectory,
560                                                test_files[f].IDOnServer));
561                                        TEST_THAT(getobj->GetObjectID() == test_files[f].IDOnServer);
562                                        // BLOCK
563                                        {
564                                                // Get stream
565                                                std::auto_ptr<IOStream> filestream(protocol.ReceiveStream());
566                                                // Get and decode
567                                                BackupStoreFile::DecodeFile(*filestream, filename_fetched, IOStream::TimeOutInfinite);
568                                        }
569                                }
570                                // Test for identicalness
571                                TEST_THAT(files_identical(filename_fetched, filename));
572                               
573                                // Download the index, and check it looks OK
574                                {
575                                        std::auto_ptr<BackupProtocolSuccess> getblockindex(protocol.QueryGetBlockIndexByID(test_files[f].IDOnServer));
576                                        TEST_THAT(getblockindex->GetObjectID() == test_files[f].IDOnServer);
577                                        std::auto_ptr<IOStream> blockIndexStream(protocol.ReceiveStream());
578                                        TEST_THAT(BackupStoreFile::CompareFileContentsAgainstBlockIndex(filename, *blockIndexStream, IOStream::TimeOutInfinite));
579                                }
580                        }
581
582                        // Close the connection                 
583                        protocol.QueryFinished();
584                        conn.Close();
585
586                        // Mark one of the elements as deleted
587                        if(test_file_remove_order[deleteIndex] == -1)
588                        {
589                                // Nothing left to do
590                                break;
591                        }
592                        int todel = test_file_remove_order[deleteIndex++];
593                       
594                        // Modify the entry
595                        BackupStoreDirectory::Entry *pentry = dir.FindEntryByID(test_files[todel].IDOnServer);
596                        TEST_THAT(pentry != 0);
597                        pentry->AddFlags(BackupStoreDirectory::Entry::Flags_RemoveASAP);
598                        // Save it back
599                        {
600                                RaidFileWrite writedir(0, "backup/01234567/o01");
601                                writedir.Open(true /* overwrite */);
602                                dir.WriteToStream(writedir);
603                                writedir.Commit(true);
604                        }
605
606#ifdef WIN32
607                        // Cannot signal bbstored to do housekeeping now,
608                        // so just wait until we're sure it's done
609                        wait_for_operation(12, "housekeeping to run");
610#else
611                        // Send the server a restart signal, so it does
612                        // housekeeping immediately, and wait for it to happen
613                        // Wait for old connections to terminate
614                        ::sleep(1);     
615                        ::kill(pid, SIGHUP);
616#endif
617
618                        // Get the revision number of the info file
619                        int64_t first_revision = 0;
620                        RaidFileRead::FileExists(0, "backup/01234567/o01", &first_revision);
621                        for(int l = 0; l < 32; ++l)
622                        {
623                                // Sleep a while, and print a dot
624                                ::sleep(1);
625                                ::printf(".");
626                                ::fflush(stdout);
627                               
628                                // Early end?
629                                if(l > 2)
630                                {
631                                        int64_t revid = 0;
632                                        RaidFileRead::FileExists(0, "backup/01234567/o01", &revid);
633                                        if(revid != first_revision)
634                                        {
635                                                break;
636                                        }
637                                }
638                        }
639                        ::printf("\n");
640                       
641                        // Flag for test
642                        test_files[todel].HasBeenDeleted = true;
643                        // Update dependency info
644                        int z = todel;
645                        while(z > 0 && test_files[z].HasBeenDeleted && test_files[z].DepOlder != 0)
646                        {
647                                --z;
648                        }
649                        if(z >= 0) test_files[z].DepNewer = test_files[todel].DepNewer;
650                        z = todel;
651                        while(z < (int)NUMBER_FILES && test_files[z].HasBeenDeleted && test_files[z].DepNewer != 0)
652                        {
653                                ++z;
654                        }
655                        if(z < (int)NUMBER_FILES) test_files[z].DepOlder = test_files[todel].DepOlder;
656                }
657               
658                // Kill store server
659                TEST_THAT(KillServer(pid));
660                TEST_THAT(!ServerIsAlive(pid));
661
662                #ifndef WIN32
663                TestRemoteProcessMemLeaks("bbstored.memleaks");
664                #endif
665        }
666       
667        ::free(buffer);
668       
669        return 0;
670}
Note: See TracBrowser for help on using the repository browser.