source: box/trunk/test/raidfile/testraidfile.cpp @ 2543

Revision 2543, 30.9 KB checked in by chris, 3 years ago (diff)

Allow RaidFileWrite? to test that the reference count of an object is
correct before overwriting or deleting it.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    test/raidfile/test.cpp 
5//              Purpose: Test RaidFile system
6//              Created: 2003/07/08
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <fcntl.h>
13#include <unistd.h>
14#include <stdio.h>
15#include <errno.h>
16
17#ifdef HAVE_SYSCALL
18#include <sys/syscall.h>
19#endif
20
21#include <string.h>
22
23#include "Test.h"
24#include "RaidFileController.h"
25#include "RaidFileWrite.h"
26#include "RaidFileException.h"
27#include "RaidFileRead.h"
28#include "Guards.h"
29
30#include "MemLeakFindOn.h"
31
32#define RAID_BLOCK_SIZE 2048
33#define RAID_NUMBER_DISCS 3
34
35#define TEST_DATA_SIZE  (8*1024 + 173)
36
37#ifndef PLATFORM_CLIB_FNS_INTERCEPTION_IMPOSSIBLE
38        #define TRF_CAN_INTERCEPT
39#endif
40
41
42#ifdef TRF_CAN_INTERCEPT
43// function in intercept.cpp for setting up errors
44void intercept_setup_error(const char *filename, unsigned int errorafter, int errortoreturn, int syscalltoerror);
45bool intercept_triggered();
46void intercept_clear_setup();
47#endif
48
49// Nice random data for testing written files
50class R250 {
51public:
52        // Set up internal state table with 32-bit random numbers. 
53        // The bizarre bit-twiddling is because rand() returns 16 bits of which
54        // the bottom bit is always zero!  Hence, I use only some of the bits.
55        // You might want to do something better than this....
56
57        R250(int seed) : posn1(0), posn2(103)
58        {
59                // populate the state and incr tables
60                srand(seed);
61
62                for (int i = 0; i != stateLen; ++i)     {
63                        state[i] = ((rand() >> 2) << 19) ^ ((rand() >> 2) << 11) ^ (rand() >> 2);
64                        incrTable[i] = i == stateLen - 1 ? 0 : i + 1;
65                }
66
67                // stir up the numbers to ensure they're random
68
69                for (int j = 0; j != stateLen * 4; ++j)                 
70                        (void) next();
71        }
72
73        // Returns the next random number.  Xor together two elements separated
74        // by 103 mod 250, replacing the first element with the result.  Then
75        // increment the two indices mod 250.
76        inline int next()
77        {
78                int ret = (state[posn1] ^= state[posn2]);       // xor and replace element
79
80                posn1 = incrTable[posn1];               // increment indices using lookup table
81                posn2 = incrTable[posn2];
82
83                return ret;
84        }
85private:
86        enum { stateLen = 250 };        // length of the state table
87        int state[stateLen];            // holds the random number state
88        int incrTable[stateLen];        // lookup table: maps i to (i+1) % stateLen
89        int posn1, posn2;                       // indices into the state table
90};
91
92void testReadingFileContents(int set, const char *filename, void *data, int datasize, bool TestRAIDProperties, int UsageInBlocks = -1)
93{
94        // Work out which disc is the "start" disc.
95        int h = 0;
96        int n = 0;
97        while(filename[n] != 0)
98        {
99                h += filename[n];
100                n++;
101        }
102        int startDisc = h % RAID_NUMBER_DISCS;
103
104//printf("UsageInBlocks = %d\n", UsageInBlocks);
105
106        // sizes of data to read
107        static int readsizes[] = {2047, 1, 1, 2047, 12, 1, 1, RAID_BLOCK_SIZE - (12+1+1), RAID_BLOCK_SIZE, RAID_BLOCK_SIZE + 246, (RAID_BLOCK_SIZE * 3) + 3, 243};
108       
109        // read the data in to test it
110        char testbuff[(RAID_BLOCK_SIZE * 3) + 128];     // bigger than the max request above!
111        std::auto_ptr<RaidFileRead> pread = RaidFileRead::Open(set, filename);
112        if(UsageInBlocks != -1)
113        {
114                TEST_THAT(UsageInBlocks == pread->GetDiscUsageInBlocks());
115        }
116        //printf("%d, %d\n", pread->GetFileSize(), datasize);
117        TEST_THAT(pread->GetFileSize() == datasize);
118        IOStream &readstream1 = *(pread.get()); 
119        int dataread = 0;
120        int r;
121        int readsize = readsizes[0];
122        int bsc = 1;
123        while((r = readstream1.Read(testbuff, readsize)) > 0)
124        {
125                //printf("== read, asked: %d actual: %d\n", readsize, r);
126                TEST_THAT(((dataread+r) == datasize) || r == readsize);
127                TEST_THAT(r > 0);
128                TEST_THAT(readstream1.StreamDataLeft());                // check IOStream interface is correct
129                for(int z = 0; z < r; ++z)
130                {
131                        TEST_THAT(((char*)data)[dataread+z] == testbuff[z]);
132                        /*if(((char*)data)[dataread+z] != testbuff[z])
133                        {
134                                printf("z = %d\n", z);
135                        }*/
136                }
137                // Next size...
138                if(bsc <= (int)((sizeof(readsizes) / sizeof(readsizes[0])) - 1))
139                {
140                        readsize = readsizes[bsc++];
141                }
142                dataread += r;
143        }
144        TEST_THAT(dataread == datasize);
145        pread->Close();
146       
147        // open and close it...
148        pread.reset(RaidFileRead::Open(set, filename).release());
149        if(UsageInBlocks != -1)
150        {
151                TEST_THAT(UsageInBlocks == pread->GetDiscUsageInBlocks());
152        }
153        IOStream &readstream2 = *(pread.get());
154       
155        // positions to try seeking too..
156        static int seekpos[] = {0, 1, 2, 887, 887+256 /* no seek required */, RAID_BLOCK_SIZE, RAID_BLOCK_SIZE + 1, RAID_BLOCK_SIZE - 1, RAID_BLOCK_SIZE*3, RAID_BLOCK_SIZE + 23, RAID_BLOCK_SIZE * 4, RAID_BLOCK_SIZE * 4 + 1};
157       
158        for(unsigned int p = 0; p < (sizeof(seekpos) / sizeof(seekpos[0])); ++p)
159        {
160                //printf("== seekpos = %d\n", seekpos[p]);
161                // only try if test file size is big enough
162                if(seekpos[p]+256 > datasize) continue;
163               
164                readstream2.Seek(seekpos[p], IOStream::SeekType_Absolute);
165                TEST_THAT(readstream2.Read(testbuff, 256) == 256);
166                TEST_THAT(readstream2.GetPosition() == seekpos[p] + 256);
167                TEST_THAT(::memcmp(((char*)data) + seekpos[p], testbuff, 256) == 0);
168        }
169
170        // open and close it...
171        pread.reset(RaidFileRead::Open(set, filename).release());
172        if(UsageInBlocks != -1)
173        {
174                TEST_THAT(UsageInBlocks == pread->GetDiscUsageInBlocks());
175        }
176        IOStream &readstream3 = *(pread.get()); 
177       
178        int pos = 0;
179        for(unsigned int p = 0; p < (sizeof(seekpos) / sizeof(seekpos[0])); ++p)
180        {
181                // only try if test file size is big enough
182                if(seekpos[p]+256 > datasize) continue;
183               
184                //printf("pos %d, seekpos %d, p %d\n", pos, seekpos[p], p);
185               
186                readstream3.Seek(seekpos[p] - pos, IOStream::SeekType_Relative);
187                TEST_THAT(readstream3.Read(testbuff, 256) == 256);
188                pos = seekpos[p] + 256;
189                TEST_THAT(readstream3.GetPosition() == pos);
190                TEST_THAT(::memcmp(((char*)data) + seekpos[p], testbuff, 256) == 0);
191        }
192       
193        // Straight read of file
194        pread.reset(RaidFileRead::Open(set, filename).release());
195        if(UsageInBlocks != -1)
196        {
197                TEST_THAT(UsageInBlocks == pread->GetDiscUsageInBlocks());
198        }
199        IOStream &readstream4 = *(pread.get());
200        pos = 0;
201        int bytesread = 0;
202        while((r = readstream4.Read(testbuff, 988)) != 0)
203        {
204                TEST_THAT(readstream4.StreamDataLeft());                // check IOStream interface is behaving as expected
205               
206                // check contents
207                TEST_THAT(::memcmp(((char*)data) + pos, testbuff, r) == 0);
208               
209                // move on
210                pos += r;
211                bytesread += r;
212        }
213        TEST_THAT(!readstream4.StreamDataLeft());               // check IOStream interface is correct
214        pread.reset();
215
216        // Be nasty, and create some errors for the RAID stuff to recover from...
217        if(TestRAIDProperties)
218        {
219                char stripe1fn[256], stripe1fnRename[256];
220                sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
221                        DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
222                sprintf(stripe1fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
223                        DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, startDisc, 
224                        filename);
225                char stripe2fn[256], stripe2fnRename[256];
226                sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
227                        DIRECTORY_SEPARATOR "%s.rf", set, 
228                        (startDisc + 1) % RAID_NUMBER_DISCS, filename);
229                sprintf(stripe2fnRename, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
230                        DIRECTORY_SEPARATOR "%s.rf-REMOVED", set, 
231                        (startDisc + 1) % RAID_NUMBER_DISCS, filename);
232
233                // Read with stripe1 + parity           
234                TEST_THAT(::rename(stripe2fn, stripe2fnRename) == 0);
235                testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
236                TEST_THAT(::rename(stripe2fnRename, stripe2fn) == 0);
237
238                // Read with stripe2 + parity
239                TEST_THAT(::rename(stripe1fn, stripe1fnRename) == 0);
240                testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
241                TEST_THAT(::rename(stripe1fnRename, stripe1fn) == 0);
242
243                // Munged filename for avoidance
244                char mungefilename[256];
245                char filenamepart[256];
246                sprintf(filenamepart, "%s.rf", filename);
247                int m = 0, s = 0;
248                while(filenamepart[s] != '\0')
249                {
250                        if(filenamepart[s] == '/')
251                        {
252                                mungefilename[m++] = '_';
253                        }
254                        else if(filenamepart[s] == '_')
255                        {
256                                mungefilename[m++] = '_';
257                                mungefilename[m++] = '_';
258                        }
259                        else
260                        {
261                                mungefilename[m++] = filenamepart[s];
262                        }
263                        s++;
264                }
265                mungefilename[m++] = '\0';
266                char stripe1munge[256];
267                sprintf(stripe1munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
268                        DIRECTORY_SEPARATOR ".raidfile-unreadable"
269                        DIRECTORY_SEPARATOR "%s", set, startDisc, 
270                        mungefilename);
271                char stripe2munge[256];
272                sprintf(stripe2munge, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
273                        DIRECTORY_SEPARATOR ".raidfile-unreadable"
274                        DIRECTORY_SEPARATOR "%s", set, 
275                        (startDisc + 1) % RAID_NUMBER_DISCS, mungefilename);
276               
277
278#ifdef TRF_CAN_INTERCEPT
279                // Test I/O errors on opening
280                // stripe 1
281                intercept_setup_error(stripe1fn, 0, EIO, SYS_open);
282                testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
283                TEST_THAT(intercept_triggered());
284                intercept_clear_setup();
285
286                // Check that the file was moved correctly.
287                TEST_THAT(TestFileExists(stripe1munge));
288                TEST_THAT(::rename(stripe1munge, stripe1fn) == 0);
289                               
290                // Test error in reading stripe 2
291                intercept_setup_error(stripe2fn, 0, EIO, SYS_open);
292                testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
293                TEST_THAT(intercept_triggered());
294                intercept_clear_setup();
295
296                // Check that the file was moved correctly.
297                TEST_THAT(TestFileExists(stripe2munge));
298                TEST_THAT(::rename(stripe2munge, stripe2fn) == 0);
299
300                // Test I/O errors on seeking
301                // stripe 1, if the file is bigger than the minimum thing that it'll get seeked for
302                if(datasize > 257)
303                {
304                        intercept_setup_error(stripe1fn, 1, EIO, SYS_lseek);
305                        testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
306                        TEST_THAT(intercept_triggered());
307                        intercept_clear_setup();
308
309                        // Check that the file was moved correctly.
310                        TEST_THAT(TestFileExists(stripe1munge));
311                        TEST_THAT(::rename(stripe1munge, stripe1fn) == 0);
312                }
313
314                // Stripe 2, only if the file is big enough to merit this
315                if(datasize > (RAID_BLOCK_SIZE + 4))
316                {
317                        intercept_setup_error(stripe2fn, 1, EIO, SYS_lseek);
318                        testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
319                        TEST_THAT(intercept_triggered());
320                        intercept_clear_setup();
321
322                        // Check that the file was moved correctly.
323                        TEST_THAT(TestFileExists(stripe2munge));
324                        TEST_THAT(::rename(stripe2munge, stripe2fn) == 0);
325                }
326
327                // Test I/O errors on read, but only if the file is size greater than 0
328                if(datasize > 0)
329                {
330                        // Where shall we error after?
331                        int errafter = datasize / 4;
332
333                        // Test error in reading stripe 1
334                        intercept_setup_error(stripe1fn, errafter, EIO, SYS_readv);
335                        testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
336                        TEST_THAT(intercept_triggered());
337                        intercept_clear_setup();
338
339                        // Check that the file was moved correctly.
340                        TEST_THAT(TestFileExists(stripe1munge));
341                        TEST_THAT(::rename(stripe1munge, stripe1fn) == 0);
342
343                        // Can only test error if file size > RAID_BLOCK_SIZE, as otherwise stripe2 has nothing in it
344                        if(datasize > RAID_BLOCK_SIZE)
345                        {
346                                // Test error in reading stripe 2
347                                intercept_setup_error(stripe2fn, errafter, EIO, SYS_readv);
348                                testReadingFileContents(set, filename, data, datasize, false /* avoid recursion! */, UsageInBlocks);
349                                TEST_THAT(intercept_triggered());
350                                intercept_clear_setup();
351
352                                // Check that the file was moved correctly.
353                                TEST_THAT(TestFileExists(stripe2munge));
354                                TEST_THAT(::rename(stripe2munge, stripe2fn) == 0);
355                        }
356                }
357#endif // TRF_CAN_INTERCEPT
358        }
359}
360
361
362void testReadWriteFileDo(int set, const char *filename, void *data, int datasize, bool DoTransform)
363{
364        // Work out which disc is the "start" disc.
365        int h = 0;
366        int n = 0;
367        while(filename[n] != 0)
368        {
369                h += filename[n];
370                n++;
371        }
372        int startDisc = h % RAID_NUMBER_DISCS;
373
374        // Another to test the transform works OK...
375        RaidFileWrite write4(set, filename);
376        write4.Open();
377        write4.Write(data, datasize);
378        // This time, don't discard and transform it to a RAID File
379        char writefnPre[256];
380        sprintf(writefnPre, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
381                DIRECTORY_SEPARATOR "%s.rfwX", set, startDisc, filename);
382        TEST_THAT(TestFileExists(writefnPre));
383        char writefn[256];
384        sprintf(writefn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
385                DIRECTORY_SEPARATOR "%s.rfw", set, startDisc, filename);
386        int usageInBlocks = write4.GetDiscUsageInBlocks();
387        write4.Commit(DoTransform);
388        // Check that files are nicely done...
389        if(!DoTransform)
390        {
391                TEST_THAT(TestFileExists(writefn));
392                TEST_THAT(!TestFileExists(writefnPre));
393        }
394        else
395        {
396                TEST_THAT(!TestFileExists(writefn));
397                TEST_THAT(!TestFileExists(writefnPre));
398                // Stripe file sizes
399                int fullblocks = datasize / RAID_BLOCK_SIZE;
400                int leftover = datasize - (fullblocks * RAID_BLOCK_SIZE);
401                int fs1 = -2;
402                if((fullblocks & 1) == 0)
403                {
404                        // last block of data will be on the first stripe
405                        fs1 = ((fullblocks / 2) * RAID_BLOCK_SIZE) + leftover;
406                }
407                else
408                {
409                        // last block is on second stripe
410                        fs1 = ((fullblocks / 2)+1) * RAID_BLOCK_SIZE;
411                }
412                char stripe1fn[256];
413                sprintf(stripe1fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
414                        DIRECTORY_SEPARATOR "%s.rf", set, startDisc, filename);
415                TEST_THAT(TestGetFileSize(stripe1fn) == fs1);
416                char stripe2fn[256];
417                sprintf(stripe2fn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
418                        DIRECTORY_SEPARATOR "%s.rf", set, 
419                        (startDisc + 1) % RAID_NUMBER_DISCS, filename);
420                TEST_THAT(TestGetFileSize(stripe2fn) == (int)(datasize - fs1));
421                // Parity file size
422                char parityfn[256];
423                sprintf(parityfn, "testfiles" DIRECTORY_SEPARATOR "%d_%d"
424                        DIRECTORY_SEPARATOR "%s.rf", set, 
425                        (startDisc + 2) % RAID_NUMBER_DISCS, filename);
426                // Mildly complex calculation
427                unsigned int blocks = datasize / RAID_BLOCK_SIZE;
428                unsigned int bytesOver = datasize % RAID_BLOCK_SIZE;
429                int paritysize = (blocks / 2) * RAID_BLOCK_SIZE;
430                // Then add in stuff for the last couple of blocks
431                if((blocks & 1) == 0)
432                {
433                        if(bytesOver == 0)
434                        {
435                                paritysize += sizeof(RaidFileRead::FileSizeType);
436                        }
437                        else
438                        {
439                                paritysize += (bytesOver == sizeof(RaidFileRead::FileSizeType))?(RAID_BLOCK_SIZE+sizeof(RaidFileRead::FileSizeType)):bytesOver;
440                        }
441                }
442                else
443                {
444                        paritysize += RAID_BLOCK_SIZE;
445                        if(bytesOver == 0 || bytesOver >= (RAID_BLOCK_SIZE-sizeof(RaidFileRead::FileSizeType)))
446                        {
447                                paritysize += sizeof(RaidFileRead::FileSizeType);
448                        }
449                }
450                //printf("datasize = %d, calc paritysize = %d, actual size of file = %d\n", datasize, paritysize, TestGetFileSize(parityfn));
451                TEST_THAT(TestGetFileSize(parityfn) == paritysize);
452                //printf("stripe1 size = %d, stripe2 size = %d, parity size = %d\n", TestGetFileSize(stripe1fn), TestGetFileSize(stripe2fn), TestGetFileSize(parityfn));
453       
454                // Check that block calculation is correct
455                //printf("filesize = %d\n", datasize);
456                #define TO_BLOCKS_ROUND_UP(x) (((x) + (RAID_BLOCK_SIZE-1)) / RAID_BLOCK_SIZE)
457                TEST_THAT(usageInBlocks == (TO_BLOCKS_ROUND_UP(paritysize) + TO_BLOCKS_ROUND_UP(fs1) + TO_BLOCKS_ROUND_UP(datasize - fs1)));
458       
459                // See about whether or not the files look correct
460                char testblock[1024];   // compiler bug? This can't go in the block below without corrupting stripe2fn...
461                if(datasize > (3*1024))
462                {
463                        int f;
464                        TEST_THAT((f = ::open(stripe1fn, O_RDONLY | O_BINARY, 
465                                0)) != -1);
466                        TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
467                        for(unsigned int q = 0; q < sizeof(testblock); ++q)
468                        {
469                                TEST_THAT(testblock[q] == ((char*)data)[q]);
470                        }
471                        ::close(f);
472                        TEST_THAT((f = ::open(stripe2fn, O_RDONLY | O_BINARY, 
473                                0)) != -1);
474                        TEST_THAT(sizeof(testblock) == ::read(f, testblock, sizeof(testblock)));
475                        for(unsigned int q = 0; q < sizeof(testblock); ++q)
476                        {
477                                TEST_THAT(testblock[q] == ((char*)data)[q+RAID_BLOCK_SIZE]);
478                        }
479                        ::close(f);
480                }
481        }
482       
483        // See if the contents look right
484        testReadingFileContents(set, filename, data, datasize, DoTransform /* only test RAID stuff if it has been transformed to RAID */, usageInBlocks);
485}
486
487void testReadWriteFile(int set, const char *filename, void *data, int datasize)
488{
489        // Test once, transforming it...
490        testReadWriteFileDo(set, filename, data, datasize, true);
491       
492        // And then again, not transforming it
493        std::string fn(filename);
494        fn += "NT";
495        testReadWriteFileDo(set, fn.c_str(), data, datasize, false);   
496}
497
498bool list_matches(const std::vector<std::string> &rList, const char *compareto[])
499{
500        // count in compare to
501        int count = 0;
502        while(compareto[count] != 0)
503                count++;
504       
505        if((int)rList.size() != count)
506        {
507                return false;
508        }
509       
510        // Space for bools
511        bool *found = new bool[count];
512       
513        for(int c = 0; c < count; ++c)
514        {
515                found[c] = false;
516        }
517       
518        for(int c = 0; c < count; ++c)
519        {
520                bool f = false;
521                for(int l = 0; l < (int)rList.size(); ++l)
522                {
523                        if(rList[l] == compareto[c])
524                        {
525                                f = true;
526                                break;
527                        }
528                }
529                found[c] = f;
530        }
531
532        bool ret = true;
533        for(int c = 0; c < count; ++c)
534        {
535                if(found[c] == false)
536                {
537                        ret = false;
538                }
539        }
540
541        delete [] found;
542       
543        return ret;
544}
545
546void test_overwrites()
547{
548        // Opening twice is bad
549        {
550                RaidFileWrite writeA(0, "overwrite_A");
551                writeA.Open();
552                writeA.Write("TESTTEST", 8);
553       
554                {
555#if defined(HAVE_FLOCK) || HAVE_DECL_O_EXLOCK
556                        RaidFileWrite writeA2(0, "overwrite_A");
557                        TEST_CHECK_THROWS(writeA2.Open(), RaidFileException, FileIsCurrentlyOpenForWriting);
558#endif
559                }
560        }
561       
562        // But opening a file which has previously been open, but isn't now, is OK.
563       
564        // Generate a random pre-existing write file (and ensure that it doesn't exist already)
565        int f;
566        TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" 
567                DIRECTORY_SEPARATOR "overwrite_B.rfwX", 
568                O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0755)) != -1);
569        TEST_THAT(::write(f, "TESTTEST", 8) == 8);
570        ::close(f);
571
572        // Attempt to overwrite it, which should work nicely.
573        RaidFileWrite writeB(0, "overwrite_B");
574        writeB.Open();
575        writeB.Write("TEST", 4);
576        TEST_THAT(writeB.GetFileSize() == 4);
577        writeB.Commit();
578}
579
580
581int test(int argc, const char *argv[])
582{
583        #ifndef TRF_CAN_INTERCEPT
584                printf("NOTE: Skipping intercept based tests on this platform.\n\n");
585        #endif
586
587        // Initialise the controller
588        RaidFileController &rcontroller = RaidFileController::GetController();
589        rcontroller.Initialise("testfiles" DIRECTORY_SEPARATOR "raidfile.conf");
590
591        // some data
592        char data[TEST_DATA_SIZE];
593        R250 random(619);
594        for(unsigned int l = 0; l < sizeof(data); ++l)
595        {
596                data[l] = random.next() & 0xff;
597        }
598        char data2[57];
599        for(unsigned int l = 0; l < sizeof(data2); ++l)
600        {
601                data2[l] = l;
602        }
603       
604        // Try creating a directory
605        RaidFileWrite::CreateDirectory(0, "test-dir");
606        TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_0" 
607                DIRECTORY_SEPARATOR "test-dir"));
608        TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_1"
609                DIRECTORY_SEPARATOR "test-dir"));
610        TEST_THAT(TestDirExists("testfiles" DIRECTORY_SEPARATOR "0_2"
611                DIRECTORY_SEPARATOR "test-dir"));
612        TEST_THAT(RaidFileRead::DirectoryExists(0, "test-dir"));
613        TEST_THAT(!RaidFileRead::DirectoryExists(0, "test-dir-not"));
614
615
616        // Test converting to disc set names
617        {
618                std::string n1(RaidFileController::DiscSetPathToFileSystemPath(0, "testX", 0));
619                std::string n2(RaidFileController::DiscSetPathToFileSystemPath(0, "testX", 1));
620                std::string n3(RaidFileController::DiscSetPathToFileSystemPath(0, "testX", 2));
621                std::string n4(RaidFileController::DiscSetPathToFileSystemPath(0, "testX", 3));
622                TEST_THAT(n1 != n2);
623                TEST_THAT(n2 != n3);
624                TEST_THAT(n1 != n3);
625                TEST_THAT(n1 == n4);            // ie wraps around
626                BOX_TRACE("Gen paths = '" << n1 << "', '" << n2 << 
627                        "', '" << n3);
628        }
629
630        // Test that creating and deleting a RaidFile with the wrong
631        // reference counts throws the expected errors.
632        {
633                RaidFileWrite write1(0, "write1", 1);
634                write1.Open();
635                write1.Commit();
636                TEST_CHECK_THROWS(write1.Delete(), RaidFileException,
637                        RequestedDeleteReferencedFile);
638        }
639
640        {
641                RaidFileWrite write1(0, "write1", 0);
642                write1.Open(true);
643                TEST_CHECK_THROWS(write1.Commit(), RaidFileException,
644                        RequestedModifyUnreferencedFile);
645                write1.Delete();
646        }
647
648        {
649                TEST_CHECK_THROWS(RaidFileWrite write1(0, "write1", 2),
650                        RaidFileException,
651                        RequestedModifyMultiplyReferencedFile);
652        }
653
654        // Create a RaidFile
655        RaidFileWrite write1(0, "test1");
656        IOStream &write1stream = write1;        // use the stream interface where possible
657        write1.Open();
658        write1stream.Write(data, sizeof(data));
659        write1stream.Seek(1024, IOStream::SeekType_Absolute);
660        write1stream.Write(data2, sizeof(data2));
661        write1stream.Seek(1024, IOStream::SeekType_Relative);
662        write1stream.Write(data2, sizeof(data2));
663        write1stream.Seek(0, IOStream::SeekType_End);
664        write1stream.Write(data, sizeof(data));
665       
666        // Before it's deleted, check to see the contents are as expected
667        int f;
668        TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
669                DIRECTORY_SEPARATOR "test1.rfwX", O_RDONLY | O_BINARY, 0)) 
670                >= 0);
671        char buffer[sizeof(data)];
672        int bytes_read = ::read(f, buffer, sizeof(buffer));
673        TEST_THAT(bytes_read == sizeof(buffer));
674        for(unsigned int l = 0; l < 1024; ++l)
675        {
676                TEST_THAT(buffer[l] == data[l]);
677        }
678        for(unsigned int l = 0; l < sizeof(data2); ++l)
679        {
680                TEST_THAT(buffer[l+1024] == data2[l]);
681        }
682        for(unsigned int l = 0; l < sizeof(data2); ++l)
683        {
684                TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]);
685        }
686        TEST_THAT(::lseek(f, sizeof(data), SEEK_SET) == sizeof(buffer));
687        bytes_read = ::read(f, buffer, sizeof(buffer));
688        TEST_THAT(bytes_read == sizeof(buffer));
689        for(unsigned int l = 0; l < 1024; ++l)
690        {
691                TEST_THAT(buffer[l] == data[l]);
692        }
693        // make sure that's the end of the file
694        TEST_THAT(::read(f, buffer, sizeof(buffer)) == 0);
695        ::close(f);
696       
697        // Commit the data
698        write1.Commit();
699        TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
700                DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
701                >= 0);
702        ::close(f);
703
704        // Now try and read it
705        {
706                std::auto_ptr<RaidFileRead> pread = RaidFileRead::Open(0, "test1");
707                TEST_THAT(pread->GetFileSize() == sizeof(buffer)*2);
708               
709                char buffer[sizeof(data)];
710                TEST_THAT(pread->Read(buffer, sizeof(buffer)) == sizeof(buffer));
711                for(unsigned int l = 0; l < 1024; ++l)
712                {
713                        TEST_THAT(buffer[l] == data[l]);
714                }
715                for(unsigned int l = 0; l < sizeof(data2); ++l)
716                {
717                        TEST_THAT(buffer[l+1024] == data2[l]);
718                }
719                for(unsigned int l = 0; l < sizeof(data2); ++l)
720                {
721                        TEST_THAT(buffer[l+2048+sizeof(data2)] == data2[l]);
722                }
723                pread->Seek(sizeof(data), IOStream::SeekType_Absolute);
724                TEST_THAT(pread->Read(buffer, sizeof(buffer)) == sizeof(buffer));
725                for(unsigned int l = 0; l < 1024; ++l)
726                {
727                        TEST_THAT(buffer[l] == data[l]);
728                }
729                // make sure that's the end of the file
730                TEST_THAT(pread->Read(buffer, sizeof(buffer)) == 0);
731                // Seek backwards a bit
732                pread->Seek(-1024, IOStream::SeekType_Relative);
733                TEST_THAT(pread->Read(buffer, 1024) == 1024);
734                // make sure that's the end of the file
735                TEST_THAT(pread->Read(buffer, sizeof(buffer)) == 0);
736                // Test seeking to end works
737                pread->Seek(-1024, IOStream::SeekType_Relative);
738                TEST_THAT(pread->Read(buffer, 512) == 512);
739                pread->Seek(0, IOStream::SeekType_End);
740                TEST_THAT(pread->Read(buffer, sizeof(buffer)) == 0);
741        }
742       
743        // Delete it
744        RaidFileWrite writeDel(0, "test1");
745        writeDel.Delete();
746
747        // And again...
748        RaidFileWrite write2(0, "test1");
749        write2.Open();
750        write2.Write(data, sizeof(data));
751        // This time, discard it
752        write2.Discard();
753        TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2"
754                DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
755                == -1);
756       
757        // And leaving it there...
758        RaidFileWrite writeLeave(0, "test1");
759        writeLeave.Open();
760        writeLeave.Write(data, sizeof(data));
761        // This time, commit it
762        writeLeave.Commit();
763        TEST_THAT((f = ::open("testfiles" DIRECTORY_SEPARATOR "0_2" 
764                DIRECTORY_SEPARATOR "test1.rfw", O_RDONLY | O_BINARY, 0)) 
765                != -1);
766        ::close(f);
767       
768        // Then check that the thing will refuse to open it again.
769        RaidFileWrite write3(0, "test1");
770        TEST_CHECK_THROWS(write3.Open(), RaidFileException, CannotOverwriteExistingFile);
771       
772        // Test overwrite behaviour
773        test_overwrites();
774
775        // Then... open it again allowing overwrites
776        RaidFileWrite write3b(0, "test1");
777        write3b.Open(true);
778        // Write something
779        write3b.Write(data + 3, sizeof(data) - 3);
780        write3b.Commit();
781        // Test it
782        testReadingFileContents(0, "test1", data+3, sizeof(data) - 3, false 
783                /* TestRAIDProperties */);
784
785        // And once again, but this time making it a raid file
786        RaidFileWrite write3c(0, "test1");
787        write3c.Open(true);
788        // Write something
789        write3c.Write(data + 7, sizeof(data) - 7);
790        write3c.Commit(true);   // make RAID
791        // Test it
792        testReadingFileContents(0, "test1", data+7, sizeof(data) - 7, false 
793                /*TestRAIDProperties*/);
794
795        // Test opening a file which doesn't exist
796        TEST_CHECK_THROWS(
797                std::auto_ptr<RaidFileRead> preadnotexist = RaidFileRead::Open(1, "doesnt-exist"),
798                RaidFileException, RaidFileDoesntExist);
799
800        {
801                // Test unrecoverable damage
802                RaidFileWrite w(0, "damage");
803                w.Open();
804                w.Write(data, sizeof(data));
805                w.Commit(true);
806
807                // Try removing the parity file
808                TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0"
809                        DIRECTORY_SEPARATOR "damage.rf", 
810                        "testfiles" DIRECTORY_SEPARATOR "0_0"
811                        DIRECTORY_SEPARATOR "damage.rf-NT") == 0);
812                {
813                        std::auto_ptr<RaidFileRead> pr0 = RaidFileRead::Open(0, "damage");
814                        pr0->Read(buffer, sizeof(data));
815                }               
816                TEST_THAT(::rename("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf-NT", "testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0);
817       
818                // Delete one of the files
819                TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "damage.rf") == 0); // stripe 1
820               
821#ifdef TRF_CAN_INTERCEPT
822                // Open it and read...
823                {
824                        intercept_setup_error("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "damage.rf", 0, EIO, SYS_read); // stripe 2
825                        std::auto_ptr<RaidFileRead> pr1 = RaidFileRead::Open(0, "damage");
826                        TEST_CHECK_THROWS(
827                                pr1->Read(buffer, sizeof(data)),
828                                RaidFileException, OSError);
829
830                        TEST_THAT(intercept_triggered());
831                        intercept_clear_setup();
832                }
833#endif //TRF_CAN_INTERCEPT
834
835                // Delete another
836                TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "damage.rf") == 0); // parity
837               
838                TEST_CHECK_THROWS(
839                        std::auto_ptr<RaidFileRead> pread2 = RaidFileRead::Open(0, "damage"),
840                        RaidFileException, FileIsDamagedNotRecoverable);
841        }
842
843        // Test reading a directory
844        {
845                RaidFileWrite::CreateDirectory(0, "dirread");
846                // Make some contents
847                RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "dfsdf1");
848                RaidFileWrite::CreateDirectory(0, "dirread" DIRECTORY_SEPARATOR "ponwq2");
849                {
850                        RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "sdf9873241");
851                        w.Open();
852                        w.Write(data, sizeof(data));
853                        w.Commit(true);
854                }
855                {
856                        RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "fsdcxjni3242");
857                        w.Open();
858                        w.Write(data, sizeof(data));
859                        w.Commit(true);
860                }
861                {
862                        RaidFileWrite w(0, "dirread" DIRECTORY_SEPARATOR "cskjnds3");
863                        w.Open();
864                        w.Write(data, sizeof(data));
865                        w.Commit(false);
866                }
867               
868                const static char *dir_list1[] = {"dfsdf1", "ponwq2", 0};
869                const static char *file_list1[] = {"sdf9873241", "fsdcxjni3242", "cskjnds3", 0};
870                const static char *file_list2[] = {"fsdcxjni3242", "cskjnds3", 0};
871               
872                std::vector<std::string> names;
873                TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
874                TEST_THAT(list_matches(names, file_list1));
875                TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_DirsOnly, names));
876                TEST_THAT(list_matches(names, dir_list1));
877                // Delete things
878                TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_0" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
879                TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
880                TEST_THAT(list_matches(names, file_list1));
881                // Delete something else so that it's not recoverable
882                TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_1" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
883                TEST_THAT(false == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
884                TEST_THAT(list_matches(names, file_list1));
885                // And finally...
886                TEST_THAT(::unlink("testfiles" DIRECTORY_SEPARATOR "0_2" DIRECTORY_SEPARATOR "dirread" DIRECTORY_SEPARATOR "sdf9873241.rf") == 0);
887                TEST_THAT(true == RaidFileRead::ReadDirectoryContents(0, std::string("dirread"), RaidFileRead::DirReadType_FilesOnly, names));
888                TEST_THAT(list_matches(names, file_list2));
889        }
890
891        // Check that sizes are reported correctly for non-raid discs
892        {
893                int sizeInBlocks = (sizeof(data) + RAID_BLOCK_SIZE - 1) / RAID_BLOCK_SIZE;
894                // for writing
895                {
896                        RaidFileWrite write(2, "testS");
897                        write.Open();
898                        write.Write(data, sizeof(data));
899                        TEST_THAT(write.GetDiscUsageInBlocks() == sizeInBlocks);
900                        write.Commit();
901                }
902                // for reading
903                {
904                        std::auto_ptr<RaidFileRead> pread(RaidFileRead::Open(2, "testS"));
905                        TEST_THAT(pread->GetDiscUsageInBlocks() == sizeInBlocks);
906                }
907        }
908       
909//printf("SKIPPING tests ------------------\n");
910//return 0;
911
912        // Test a load of transformed things
913        #define BIG_BLOCK_SIZE (25*1024 + 19)
914        MemoryBlockGuard<void*> bigblock(BIG_BLOCK_SIZE);
915        R250 randomX2(2165);
916        for(unsigned int l = 0; l < BIG_BLOCK_SIZE; ++l)
917        {
918                ((char*)(void*)bigblock)[l] = randomX2.next() & 0xff;
919        }
920       
921        // First on one size of data, on different discs
922        testReadWriteFile(0, "testdd", data, sizeof(data));
923        testReadWriteFile(0, "test2", bigblock, BIG_BLOCK_SIZE);
924        testReadWriteFile(1, "testThree", bigblock, BIG_BLOCK_SIZE - 2048);
925        testReadWriteFile(1, "testX", bigblock, BIG_BLOCK_SIZE - 2289);
926        testReadWriteFile(1, "testSmall0", data, 0);
927        testReadWriteFile(1, "testSmall1", data, 1);
928        testReadWriteFile(1, "testSmall2", data, 2);
929        testReadWriteFile(1, "testSmall3", data, 3);
930        testReadWriteFile(1, "testSmall4", data, 4);
931        testReadWriteFile(0, "testSmall5", data, 5);
932        testReadWriteFile(0, "testSmall6", data, 6);
933        testReadWriteFile(1, "testSmall7", data, 7);
934        testReadWriteFile(1, "testSmall8", data, 8);
935        testReadWriteFile(1, "testSmall9", data, 9);
936        testReadWriteFile(1, "testSmall10", data, 10);
937        // See about a file which is one block bigger than the previous tests
938        {
939                char dataonemoreblock[TEST_DATA_SIZE + RAID_BLOCK_SIZE];
940                R250 random(715);
941                for(unsigned int l = 0; l < sizeof(dataonemoreblock); ++l)
942                {
943                        dataonemoreblock[l] = random.next() & 0xff;
944                }
945                testReadWriteFile(0, "testfour", dataonemoreblock, sizeof(dataonemoreblock));
946        }
947       
948        // Some more nasty sizes
949        static int nastysize[] = {0, 1, 2, 7, 8, 9, (RAID_BLOCK_SIZE/2)+3,
950                        RAID_BLOCK_SIZE-9, RAID_BLOCK_SIZE-8, RAID_BLOCK_SIZE-7, RAID_BLOCK_SIZE-6, RAID_BLOCK_SIZE-5,
951                        RAID_BLOCK_SIZE-4, RAID_BLOCK_SIZE-3, RAID_BLOCK_SIZE-2, RAID_BLOCK_SIZE-1};
952        for(int o = 0; o <= 5; ++o)
953        {
954                for(unsigned int n = 0; n < (sizeof(nastysize)/sizeof(nastysize[0])); ++n)
955                {
956                        int s = (o*RAID_BLOCK_SIZE)+nastysize[n];
957                        char fn[64];
958                        sprintf(fn, "testN%d", s);
959                        testReadWriteFile(n&1, fn, bigblock, s);
960                }
961        }
962       
963        // Finally, a mega test (not necessary for every run, I would have thought)
964/*      unsigned int megamax = (1024*128) + 9;
965        MemoryBlockGuard<void*> megablock(megamax);
966        R250 randomX3(183);
967        for(unsigned int l = 0; l < megamax; ++l)
968        {
969                ((char*)(void*)megablock)[l] = randomX3.next() & 0xff;
970        }
971        for(unsigned int s = 0; s < megamax; ++s)
972        {
973                testReadWriteFile(s & 1, "mega", megablock, s);
974                RaidFileWrite deleter(s & 1, "mega");
975                deleter.Delete();
976                RaidFileWrite deleter2(s & 1, "megaNT");
977                deleter2.Delete();
978        }*/
979       
980        return 0;
981}
Note: See TracBrowser for help on using the repository browser.