source: box/trunk/lib/raidfile/RaidFileWrite.cpp @ 2896

Revision 2896, 26.2 KB checked in by chris, 14 months ago (diff)

Improve RaidFile? error logging.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    RaidFileWrite.cpp
5//              Purpose: Writing RAID like files
6//              Created: 2003/07/10
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <errno.h>
13#include <fcntl.h>
14
15#ifdef HAVE_UNISTD_H
16#       include <unistd.h>
17#endif
18
19#include <sys/types.h>
20#include <sys/stat.h>
21
22#ifdef HAVE_SYS_FILE_H
23#       include <sys/file.h>
24#endif
25
26#include <stdio.h>
27#include <string.h>
28
29#include "Guards.h"
30#include "RaidFileWrite.h"
31#include "RaidFileController.h"
32#include "RaidFileException.h"
33#include "RaidFileUtil.h"
34#include "Utils.h"
35// For DirectoryExists fn
36#include "RaidFileRead.h"
37
38#include "MemLeakFindOn.h"
39
40// should be a multiple of 2
41#define TRANSFORM_BLOCKS_TO_LOAD                4
42// Must have this number of discs in the set
43#define TRANSFORM_NUMBER_DISCS_REQUIRED 3
44
45// we want to use POSIX fstat() for now, not the emulated one
46#undef fstat
47
48// --------------------------------------------------------------------------
49//
50// Function
51//              Name:    RaidFileWrite::RaidFileWrite(int, const std::string &)
52//              Purpose: Simple constructor, just stores required details
53//              Created: 2003/07/10
54//
55// --------------------------------------------------------------------------
56RaidFileWrite::RaidFileWrite(int SetNumber, const std::string &Filename)
57        : mSetNumber(SetNumber),
58          mFilename(Filename),
59          mOSFileHandle(-1), // not valid file handle
60          mRefCount(-1) // unknown refcount
61{
62}
63
64// --------------------------------------------------------------------------
65//
66// Function
67//              Name:    RaidFileWrite::RaidFileWrite(int,
68//                       const std::string &, int refcount)
69//              Purpose: Constructor with check for overwriting file
70//                       with multiple references
71//              Created: 2009/07/05
72//
73// --------------------------------------------------------------------------
74RaidFileWrite::RaidFileWrite(int SetNumber, const std::string &Filename,
75        int refcount)
76        : mSetNumber(SetNumber),
77          mFilename(Filename),
78          mOSFileHandle(-1),            // not valid file handle
79          mRefCount(refcount)
80{
81        // Can't check for zero refcount here, because it's legal
82        // to create a RaidFileWrite to delete an object with zero refcount.
83        // Check in Commit() and Delete() instead.
84        if (refcount > 1)
85        {
86                BOX_ERROR("Attempted to modify object " << mFilename <<
87                        ", which has " << refcount << " references");
88                THROW_EXCEPTION(RaidFileException,
89                        RequestedModifyMultiplyReferencedFile);
90        }
91}
92
93// --------------------------------------------------------------------------
94//
95// Function
96//              Name:    RaidFileWrite::~RaidFileWrite()
97//              Purpose: Destructor (will discard written file if not commited)
98//              Created: 2003/07/10
99//
100// --------------------------------------------------------------------------
101RaidFileWrite::~RaidFileWrite()
102{
103        if(mOSFileHandle != -1)
104        {
105                Discard();
106        }
107}
108
109
110// --------------------------------------------------------------------------
111//
112// Function
113//              Name:    RaidFileWrite::Open()
114//              Purpose: Opens the file for writing
115//              Created: 2003/07/10
116//
117// --------------------------------------------------------------------------
118void RaidFileWrite::Open(bool AllowOverwrite)
119{
120        if(mOSFileHandle != -1)
121        {
122                THROW_EXCEPTION(RaidFileException, AlreadyOpen)
123        }
124       
125        // Get disc set
126        RaidFileController &rcontroller(RaidFileController::GetController());
127        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
128
129        // Check for overwriting? (step 1)
130        if(!AllowOverwrite)
131        {
132                // See if the file exists already -- can't overwrite existing files
133                RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
134                if(existance != RaidFileUtil::NoFile)
135                {
136                        THROW_FILE_ERROR("Attempted to overwrite raidfile " <<
137                                mSetNumber, mFilename, RaidFileException,
138                                CannotOverwriteExistingFile);
139                }
140        }
141
142        // Get the filename for the write file
143        std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
144        // Add on a temporary extension
145        writeFilename += 'X';
146
147        // Attempt to open
148        mOSFileHandle = ::open(writeFilename.c_str(), 
149                O_WRONLY | O_CREAT | O_BINARY,
150                S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
151        if(mOSFileHandle == -1)
152        {
153                THROW_SYS_FILE_ERROR("Failed to open RaidFile", writeFilename,
154                        RaidFileException, ErrorOpeningWriteFile);
155        }
156       
157        // Get a lock on the write file
158#ifdef HAVE_FLOCK
159        int errnoBlock = EWOULDBLOCK;
160        if(::flock(mOSFileHandle, LOCK_EX | LOCK_NB) != 0)
161#elif HAVE_DECL_F_SETLK
162        int errnoBlock = EAGAIN;
163        struct flock desc;
164        desc.l_type = F_WRLCK;
165        desc.l_whence = SEEK_SET;
166        desc.l_start = 0;
167        desc.l_len = 0;
168        if(::fcntl(mOSFileHandle, F_SETLK, &desc) != 0)
169#else
170        int errnoBlock = ENOSYS;
171        if (0)
172#endif
173        {
174                // Lock was not obtained.
175                bool wasLocked = (errno == errnoBlock);
176                // Close the file
177                ::close(mOSFileHandle);
178                mOSFileHandle = -1;
179                // Report an exception?
180                if(wasLocked)
181                {
182                        THROW_EXCEPTION(RaidFileException, FileIsCurrentlyOpenForWriting)
183                }
184                else
185                {
186                        // Random error occured
187                        THROW_EXCEPTION(RaidFileException, OSError)
188                }
189        }
190       
191        // Truncate it to size zero
192        if(::ftruncate(mOSFileHandle, 0) != 0)
193        {
194                THROW_EXCEPTION(RaidFileException, ErrorOpeningWriteFileOnTruncate)
195        }
196       
197        // Done!
198}
199
200// --------------------------------------------------------------------------
201//
202// Function
203//              Name:    RaidFileWrite::Write(const void *, int)
204//              Purpose: Writes a block of data
205//              Created: 2003/07/10
206//
207// --------------------------------------------------------------------------
208void RaidFileWrite::Write(const void *pBuffer, int Length)
209{
210        // open?
211        if(mOSFileHandle == -1)
212        {
213                THROW_EXCEPTION(RaidFileException, NotOpen)
214        }
215       
216        // Write data
217        int written = ::write(mOSFileHandle, pBuffer, Length);
218        if(written != Length)
219        {
220                BOX_LOG_SYS_ERROR("RaidFileWrite failed, Length = " <<
221                        Length << ", written = " << written);
222                THROW_EXCEPTION(RaidFileException, OSError)
223        }
224}
225
226// --------------------------------------------------------------------------
227//
228// Function
229//              Name:    RaidFileWrite::GetPosition()
230//              Purpose: Returns current position in file
231//              Created: 2003/07/10
232//
233// --------------------------------------------------------------------------
234IOStream::pos_type RaidFileWrite::GetPosition() const
235{
236        // open?
237        if(mOSFileHandle == -1)
238        {
239                THROW_EXCEPTION(RaidFileException, NotOpen)
240        }
241       
242        // Use lseek to find the current file position
243        off_t p = ::lseek(mOSFileHandle, 0, SEEK_CUR);
244        if(p == -1)
245        {
246                THROW_EXCEPTION(RaidFileException, OSError)
247        }
248
249        return p;
250}
251
252// --------------------------------------------------------------------------
253//
254// Function
255//              Name:    RaidFileWrite::Seek(RaidFileWrite::pos_type, bool)
256//              Purpose: Seeks in the file, relative to current position if Relative is true.
257//              Created: 2003/07/10
258//
259// --------------------------------------------------------------------------
260void RaidFileWrite::Seek(IOStream::pos_type SeekTo, int SeekType)
261{
262        // open?
263        if(mOSFileHandle == -1)
264        {
265                THROW_EXCEPTION(RaidFileException, NotOpen)
266        }
267       
268        // Seek...
269        if(::lseek(mOSFileHandle, SeekTo, ConvertSeekTypeToOSWhence(SeekType)) == -1)
270        {
271                THROW_EXCEPTION(RaidFileException, OSError)
272        }
273}
274
275// --------------------------------------------------------------------------
276//
277// Function
278//              Name:    RaidFileWrite::Commit(bool)
279//              Purpose: Closes, and commits the written file
280//              Created: 2003/07/10
281//
282// --------------------------------------------------------------------------
283void RaidFileWrite::Commit(bool ConvertToRaidNow)
284{
285        // open?
286        if(mOSFileHandle == -1)
287        {
288                THROW_EXCEPTION(RaidFileException, NotOpen)
289        }
290
291        if (mRefCount == 0)
292        {
293                BOX_ERROR("Attempted to modify object " << mFilename << 
294                        ", which has no references");
295                THROW_EXCEPTION(RaidFileException,
296                        RequestedModifyUnreferencedFile);
297        }
298
299        // Rename it into place -- BEFORE it's closed so lock remains
300
301#ifdef WIN32
302        // Except on Win32 which doesn't allow renaming open files
303        // Close file...
304        if(::close(mOSFileHandle) != 0)
305        {
306                THROW_EXCEPTION(RaidFileException, OSError)
307        }
308        mOSFileHandle = -1;
309#endif // WIN32
310
311        RaidFileController &rcontroller(RaidFileController::GetController());
312        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
313        // Get the filename for the write file
314        std::string renameTo(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
315        // And the current name
316        std::string renameFrom(renameTo + 'X');
317
318#ifdef WIN32
319        // need to delete the target first
320        if(::unlink(renameTo.c_str()) != 0)
321        {
322                DWORD errorNumber = GetLastError();
323                if (errorNumber != ERROR_FILE_NOT_FOUND)
324                {
325                        THROW_WIN_FILE_ERRNO("Failed to delete file", renameTo,
326                                errorNumber, RaidFileException, OSError);
327                }
328        }
329#endif
330
331        if(::rename(renameFrom.c_str(), renameTo.c_str()) != 0)
332        {
333                THROW_SYS_ERROR("Failed to rename file: " << renameFrom <<
334                        " to " << renameTo, RaidFileException, OSError);
335        }
336       
337#ifndef WIN32   
338        // Close file...
339        if(::close(mOSFileHandle) != 0)
340        {
341                THROW_EXCEPTION(RaidFileException, OSError)
342        }
343        mOSFileHandle = -1;
344#endif // !WIN32
345       
346        // Raid it?
347        if(ConvertToRaidNow)
348        {
349                TransformToRaidStorage();
350        }
351}
352
353// --------------------------------------------------------------------------
354//
355// Function
356//              Name:    RaidFileWrite::Discard()
357//              Purpose: Closes, discarding the data written.
358//              Created: 2003/07/10
359//
360// --------------------------------------------------------------------------
361void RaidFileWrite::Discard()
362{
363        // open?
364        if(mOSFileHandle == -1)
365        {
366                THROW_EXCEPTION(RaidFileException, NotOpen)
367        }
368
369        // Get disc set
370        RaidFileController &rcontroller(RaidFileController::GetController());
371        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
372
373        // Get the filename for the write file (temporary)
374        std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
375        writeFilename += 'X';
376       
377        // Unlink and close it
378
379#ifdef WIN32
380        // On Win32 we must close it first
381        if (::close(mOSFileHandle) != 0 ||
382                ::unlink(writeFilename.c_str()) != 0)
383#else // !WIN32
384        if (::unlink(writeFilename.c_str()) != 0 ||
385                ::close(mOSFileHandle) != 0)
386#endif // !WIN32
387        {
388                BOX_LOG_SYS_ERROR("Failed to delete file: " << writeFilename);
389                THROW_EXCEPTION(RaidFileException, OSError)
390        }
391       
392        // reset file handle
393        mOSFileHandle = -1;
394}
395
396
397// --------------------------------------------------------------------------
398//
399// Function
400//              Name:    RaidFileWrite::TransformToRaidStorage()
401//              Purpose: Turns the file into the RAID storage form
402//              Created: 2003/07/11
403//
404// --------------------------------------------------------------------------
405void RaidFileWrite::TransformToRaidStorage()
406{
407        // open?
408        if(mOSFileHandle != -1)
409        {
410                THROW_EXCEPTION(RaidFileException, WriteFileOpenOnTransform)
411        }
412
413        // Get disc set
414        RaidFileController &rcontroller(RaidFileController::GetController());
415        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
416        if(rdiscSet.IsNonRaidSet())
417        {
418                // Not in RAID mode -- do nothing
419                return;
420        }
421        // Otherwise check that it's the right sized set
422        if(TRANSFORM_NUMBER_DISCS_REQUIRED != rdiscSet.size())
423        {
424                THROW_EXCEPTION(RaidFileException, WrongNumberOfDiscsInSet)
425        }
426        unsigned int blockSize = rdiscSet.GetBlockSize();
427
428        // Get the filename for the write file (and get the disc set name for the start disc)
429        int startDisc = 0;
430        std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename, &startDisc));
431       
432        // Open it
433        FileHandleGuard<> writeFile(writeFilename.c_str());
434
435        // Get file information for write file 
436        struct stat writeFileStat;
437        if(::fstat(writeFile, &writeFileStat) != 0)
438        {
439                THROW_EXCEPTION(RaidFileException, OSError)
440        }
441//      // DEBUG MODE -- check file system size block size is same as block size for files
442//      // doesn't really apply, as space benefits of using fragment size are worth efficiency,
443//      // and anyway, it'll be buffered eventually so it won't matter.
444//      #ifndef BOX_RELEASE_BUILD
445//      {
446//              if(writeFileStat.st_blksize != blockSize)
447//              {
448//                      TRACE2("TransformToRaidStorage: optimal block size of file = %d, of set = %d, MISMATCH\n",
449//                                      writeFileStat.st_blksize, blockSize);
450//              }
451//      }
452//      #endif
453       
454        // How many blocks is the file? (rounding up)
455        int writeFileSizeInBlocks = (writeFileStat.st_size + (blockSize - 1)) / blockSize;
456        // And how big should the buffer be? (round up to multiple of 2, and no bigger than the preset limit)
457        int bufferSizeBlocks = (writeFileSizeInBlocks + 1) & ~1;
458        if(bufferSizeBlocks > TRANSFORM_BLOCKS_TO_LOAD) bufferSizeBlocks = TRANSFORM_BLOCKS_TO_LOAD;
459        // How big should the buffer be?
460        int bufferSize = (TRANSFORM_BLOCKS_TO_LOAD * blockSize);
461       
462        // Allocate buffer...
463        MemoryBlockGuard<char*> buffer(bufferSize);
464       
465        // Allocate buffer for parity file
466        MemoryBlockGuard<char*> parityBuffer(blockSize);
467       
468        // Get filenames of eventual files
469        std::string stripe1Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 0) % TRANSFORM_NUMBER_DISCS_REQUIRED));
470        std::string stripe2Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 1) % TRANSFORM_NUMBER_DISCS_REQUIRED));
471        std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, (startDisc + 2) % TRANSFORM_NUMBER_DISCS_REQUIRED));
472        // Make write equivalents
473        std::string stripe1FilenameW(stripe1Filename + 'P');
474        std::string stripe2FilenameW(stripe2Filename + 'P');
475        std::string parityFilenameW(parityFilename + 'P');
476       
477       
478        // Then open them all for writing (in strict order)
479        try
480        {
481#if HAVE_DECL_O_EXLOCK
482                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe1(stripe1FilenameW.c_str());
483                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> stripe2(stripe2FilenameW.c_str());
484                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_EXLOCK | O_BINARY)> parity(parityFilenameW.c_str());
485#else
486                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe1(stripe1FilenameW.c_str());
487                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> stripe2(stripe2FilenameW.c_str());
488                FileHandleGuard<(O_WRONLY | O_CREAT | O_EXCL | O_BINARY)> parity(parityFilenameW.c_str());
489#endif
490
491                // Then... read in data...
492                int bytesRead = -1;
493                bool sizeRecordRequired = false;
494                int blocksDone = 0;
495                while((bytesRead = ::read(writeFile, buffer, bufferSize)) > 0)
496                {
497                        // Blocks to do...
498                        int blocksToDo = (bytesRead + (blockSize - 1)) / blockSize;
499
500                        // Need to add zeros to end?
501                        int blocksRoundUp = (blocksToDo + 1) & ~1;
502                        int zerosEnd = (blocksRoundUp * blockSize);
503                        if(bytesRead != zerosEnd)
504                        {
505                                // Set the end of the blocks to zero
506                                ::memset(buffer + bytesRead, 0, zerosEnd - bytesRead);
507                        }
508
509                        // number of int's to XOR
510                        unsigned int num = blockSize / sizeof(unsigned int);
511
512                        // Then... calculate and write parity data
513                        for(int b = 0; b < blocksToDo; b += 2)
514                        {
515                                // Calculate int pointers
516                                unsigned int *pstripe1 = (unsigned int *)(buffer + (b * blockSize));
517                                unsigned int *pstripe2 = (unsigned int *)(buffer + ((b+1) * blockSize));
518                                unsigned int *pparity = (unsigned int *)((char*)parityBuffer);
519
520                                // Do XOR
521                                for(unsigned int n = 0; n < num; ++n)
522                                {
523                                        pparity[n] = pstripe1[n] ^ pstripe2[n];
524                                }
525                               
526                                // Size of parity to write...
527                                int parityWriteSize = blockSize;
528                               
529                                // Adjust if it's the last block
530                                if((blocksDone + (b + 2)) >= writeFileSizeInBlocks)
531                                {
532                                        // Yes...
533                                        unsigned int bytesInLastTwoBlocks = bytesRead - (b * blockSize);
534                                       
535                                        // Some special cases...
536                                        // Zero will never happen... but in the (imaginary) case it does, the file size will be appended
537                                        // by the test at the end.
538                                        if(bytesInLastTwoBlocks == sizeof(RaidFileRead::FileSizeType)
539                                                || bytesInLastTwoBlocks == blockSize)
540                                        {
541                                                // Write the entire block, and put the file size at end
542                                                sizeRecordRequired = true;
543                                        }
544                                        else if(bytesInLastTwoBlocks < blockSize)
545                                        {
546                                                // write only these bits
547                                                parityWriteSize = bytesInLastTwoBlocks;
548                                        }
549                                        else if(bytesInLastTwoBlocks < ((blockSize * 2) - sizeof(RaidFileRead::FileSizeType)))
550                                        {
551                                                // XOR in the size at the end of the parity block
552                                                ASSERT(sizeof(RaidFileRead::FileSizeType) == (2*sizeof(unsigned int)));
553                                                ASSERT(sizeof(RaidFileRead::FileSizeType) >= sizeof(off_t));
554                                                int sizePos = (blockSize/sizeof(unsigned int)) - 2;
555                                                union { RaidFileRead::FileSizeType l; unsigned int i[2]; } sw;
556
557                                                sw.l = box_hton64(writeFileStat.st_size);
558                                                pparity[sizePos+0] = pstripe1[sizePos+0] ^ sw.i[0];
559                                                pparity[sizePos+1] = pstripe1[sizePos+1] ^ sw.i[1];
560                                        }
561                                        else
562                                        {
563                                                // Write the entire block, and put the file size at end
564                                                sizeRecordRequired = true;
565                                        }
566                                }
567
568                                // Write block
569                                if(::write(parity, parityBuffer, parityWriteSize) != parityWriteSize)
570                                {
571                                        THROW_EXCEPTION(RaidFileException, OSError)
572                                }
573                        }
574
575                        // Write stripes
576                        char *writeFrom = buffer;
577                        for(int l = 0; l < blocksToDo; ++l)
578                        {
579                                // Write the block
580                                int toWrite = (l == (blocksToDo - 1))
581                                                                ?(bytesRead - ((blocksToDo-1)*blockSize))
582                                                                :blockSize;
583                                if(::write(((l&1)==0)?stripe1:stripe2, writeFrom, toWrite) != toWrite)
584                                {
585                                        THROW_EXCEPTION(RaidFileException, OSError)
586                                }                       
587
588                                // Next block
589                                writeFrom += blockSize;
590                        }
591                       
592                        // Count of blocks done
593                        blocksDone += blocksToDo;
594                }
595                // Error on read?
596                if(bytesRead == -1)
597                {
598                        THROW_EXCEPTION(RaidFileException, OSError)
599                }
600               
601                // Special case for zero length files
602                if(writeFileStat.st_size == 0)
603                {
604                        sizeRecordRequired = true;
605                }
606
607                // Might need to write the file size to the end of the parity file
608                // if it can't be worked out some other means -- size is required to rebuild the file if one of the stripe files is missing
609                if(sizeRecordRequired)
610                {
611                        ASSERT(sizeof(writeFileStat.st_size) <= sizeof(RaidFileRead::FileSizeType));
612                        RaidFileRead::FileSizeType sw = box_hton64(writeFileStat.st_size);
613                        ASSERT((::lseek(parity, 0, SEEK_CUR) % blockSize) == 0);
614                        if(::write(parity, &sw, sizeof(sw)) != sizeof(sw))
615                        {
616                                BOX_LOG_SYS_ERROR("Failed to write to file: " <<
617                                        writeFilename);
618                                THROW_EXCEPTION(RaidFileException, OSError)
619                        }
620                }
621
622                // Then close the written files (note in reverse order of opening)
623                parity.Close();
624                stripe2.Close();
625                stripe1.Close();
626
627#ifdef WIN32
628                // Must delete before renaming
629                #define CHECK_UNLINK(file) \
630                { \
631                        if (::unlink(file) != 0 && errno != ENOENT) \
632                        { \
633                                THROW_EXCEPTION(RaidFileException, OSError); \
634                        } \
635                }
636                CHECK_UNLINK(stripe1Filename.c_str());
637                CHECK_UNLINK(stripe2Filename.c_str());
638                CHECK_UNLINK(parityFilename.c_str());
639                #undef CHECK_UNLINK
640#endif
641               
642                // Rename them into place
643                if(::rename(stripe1FilenameW.c_str(), stripe1Filename.c_str()) != 0
644                        || ::rename(stripe2FilenameW.c_str(), stripe2Filename.c_str()) != 0
645                        || ::rename(parityFilenameW.c_str(), parityFilename.c_str()) != 0)
646                {
647                        THROW_EXCEPTION(RaidFileException, OSError)
648                }
649
650                // Close the write file
651                writeFile.Close();
652
653                // Finally delete the write file
654                if(::unlink(writeFilename.c_str()) != 0)
655                {
656                        BOX_LOG_SYS_ERROR("Failed to delete file: " <<
657                                writeFilename);
658                        THROW_EXCEPTION(RaidFileException, OSError)
659                }
660        }
661        catch(...)
662        {
663                // Unlink all the dodgy files
664                ::unlink(stripe1Filename.c_str());
665                ::unlink(stripe2Filename.c_str());
666                ::unlink(parityFilename.c_str());
667                ::unlink(stripe1FilenameW.c_str());
668                ::unlink(stripe2FilenameW.c_str());
669                ::unlink(parityFilenameW.c_str());
670               
671                // and send the error on its way
672                throw;
673        }
674}
675
676
677
678// --------------------------------------------------------------------------
679//
680// Function
681//              Name:    RaidFileWrite::Delete()
682//              Purpose: Deletes a RAID file
683//              Created: 2003/07/13
684//
685// --------------------------------------------------------------------------
686void RaidFileWrite::Delete()
687{
688        if (mRefCount != 0 && mRefCount != -1)
689        {
690                BOX_ERROR("Attempted to delete object " << mFilename <<
691                        " which has " << mRefCount << " references");
692                THROW_EXCEPTION(RaidFileException,
693                        RequestedDeleteReferencedFile);
694        }
695
696        // Get disc set
697        RaidFileController &rcontroller(RaidFileController::GetController());
698        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
699
700        // See if the file exists already -- can't delete files which don't exist
701        RaidFileUtil::ExistType existance = RaidFileUtil::RaidFileExists(rdiscSet, mFilename);
702        if(existance == RaidFileUtil::NoFile)
703        {
704                THROW_EXCEPTION(RaidFileException, RaidFileDoesntExist)
705        }
706
707        // Get the filename for the write file
708        std::string writeFilename(RaidFileUtil::MakeWriteFileName(rdiscSet, mFilename));
709
710        // Attempt to delete it
711        bool deletedSomething = false;
712        if(::unlink(writeFilename.c_str()) == 0)
713        {
714                deletedSomething = true;
715        }
716       
717        // If we're not running in RAID mode, stop now
718        if(rdiscSet.size() == 1)
719        {
720                return;
721        }
722       
723        // Now the other files
724        std::string stripe1Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 0 % TRANSFORM_NUMBER_DISCS_REQUIRED));
725        std::string stripe2Filename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 1 % TRANSFORM_NUMBER_DISCS_REQUIRED));
726        std::string parityFilename(RaidFileUtil::MakeRaidComponentName(rdiscSet, mFilename, 2 % TRANSFORM_NUMBER_DISCS_REQUIRED));
727        if(::unlink(stripe1Filename.c_str()) == 0)
728        {
729                deletedSomething = true;
730        }
731        if(::unlink(stripe2Filename.c_str()) == 0)
732        {
733                deletedSomething = true;
734        }
735        if(::unlink(parityFilename.c_str()) == 0)
736        {
737                deletedSomething = true;
738        }
739       
740        // Check something happened
741        if(!deletedSomething)
742        {
743                THROW_EXCEPTION(RaidFileException, OSError)
744        }
745}
746
747
748// --------------------------------------------------------------------------
749//
750// Function
751//              Name:    RaidFileWrite::CreateDirectory(int, const std::string &, bool, int)
752//              Purpose: Creates a directory within the raid file directories with the given name.
753//              Created: 2003/08/20
754//
755// --------------------------------------------------------------------------
756void RaidFileWrite::CreateDirectory(int SetNumber, const std::string &rDirName, bool Recursive, int mode)
757{
758        // Get disc set
759        RaidFileController &rcontroller(RaidFileController::GetController());
760        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(SetNumber));
761        // Pass on...
762        CreateDirectory(rdiscSet, rDirName, Recursive, mode);
763}
764
765// --------------------------------------------------------------------------
766//
767// Function
768//              Name:    RaidFileWrite::CreateDirectory(const RaidFileDiscSet &, const std::string &, bool, int)
769//              Purpose: Creates a directory within the raid file directories with the given name.
770//              Created: 2003/08/20
771//
772// --------------------------------------------------------------------------
773void RaidFileWrite::CreateDirectory(const RaidFileDiscSet &rSet, const std::string &rDirName, bool Recursive, int mode)
774{
775        if(Recursive)
776        {
777                // split up string
778                std::vector<std::string> elements;
779                SplitString(rDirName, DIRECTORY_SEPARATOR_ASCHAR, elements);
780               
781                // Do each element in turn
782                std::string pn;
783                for(unsigned int e = 0; e < elements.size(); ++e)
784                {
785                        // Only do this if the element has some text in it
786                        if(elements[e].size() > 0)
787                        {
788                                pn += elements[e];
789                                if(!RaidFileRead::DirectoryExists(rSet, pn))
790                                {
791                                        CreateDirectory(rSet, pn, false, mode);
792                                }
793
794                                // add separator
795                                pn += DIRECTORY_SEPARATOR_ASCHAR;
796                        }
797                }
798       
799                return;
800        }
801       
802        // Create a directory in every disc of the set
803        for(unsigned int l = 0; l < rSet.size(); ++l)
804        {
805                // build name
806                std::string dn(rSet[l] + DIRECTORY_SEPARATOR + rDirName);
807       
808                // attempt to create
809                if(::mkdir(dn.c_str(), mode) != 0)
810                {
811                        if(errno == EEXIST)
812                        {
813                                // No. Bad things.
814                                THROW_FILE_ERROR("Failed to create RaidFile directory",
815                                        dn, RaidFileException, FileExistsInDirectoryCreation);
816                        }
817                        else
818                        {
819                                THROW_FILE_ERROR("Failed to create RaidFile directory",
820                                        dn, RaidFileException, OSError);
821                        }
822                }
823        }
824}
825
826
827// --------------------------------------------------------------------------
828//
829// Function
830//              Name:    RaidFileWrite::Read(void *, int, int)
831//              Purpose: Unsupported, will exception
832//              Created: 2003/08/21
833//
834// --------------------------------------------------------------------------
835int RaidFileWrite::Read(void *pBuffer, int NBytes, int Timeout)
836{
837        THROW_EXCEPTION(RaidFileException, UnsupportedReadWriteOrClose)
838}
839
840// --------------------------------------------------------------------------
841//
842// Function
843//              Name:    RaidFileWrite::Close()
844//              Purpose: Close, discarding file.
845//              Created: 2003/08/21
846//
847// --------------------------------------------------------------------------
848void RaidFileWrite::Close()
849{
850        if(mOSFileHandle != -1)
851        {
852                BOX_WARNING("RaidFileWrite::Close() called, discarding file");
853                Discard();
854        }
855}
856
857// --------------------------------------------------------------------------
858//
859// Function
860//              Name:    RaidFileWrite::StreamDataLeft()
861//              Purpose: Never any data left to read!
862//              Created: 2003/08/21
863//
864// --------------------------------------------------------------------------
865bool RaidFileWrite::StreamDataLeft()
866{
867        return false;
868}
869
870// --------------------------------------------------------------------------
871//
872// Function
873//              Name:    RaidFileWrite::StreamClosed()
874//              Purpose: Is stream closed for writing?
875//              Created: 2003/08/21
876//
877// --------------------------------------------------------------------------
878bool RaidFileWrite::StreamClosed()
879{
880        return mOSFileHandle == -1;
881}
882
883// --------------------------------------------------------------------------
884//
885// Function
886//              Name:    RaidFileWrite::GetFileSize()
887//              Purpose: Returns the size of the file written.
888//                               Can only be used before the file is commited.
889//              Created: 2003/09/03
890//
891// --------------------------------------------------------------------------
892IOStream::pos_type RaidFileWrite::GetFileSize()
893{
894        if(mOSFileHandle == -1)
895        {
896                THROW_EXCEPTION(RaidFileException, CanOnlyGetFileSizeBeforeCommit)
897        }
898       
899        // Stat to get size
900        struct stat st;
901        if(fstat(mOSFileHandle, &st) != 0)
902        {
903                THROW_EXCEPTION(RaidFileException, OSError)
904        }
905       
906        return st.st_size;
907}
908
909
910
911
912// --------------------------------------------------------------------------
913//
914// Function
915//              Name:    RaidFileWrite::GetDiscUsageInBlocks()
916//              Purpose: Returns the amount of disc space used, in blocks.
917//                               Can only be used before the file is commited.
918//              Created: 2003/09/03
919//
920// --------------------------------------------------------------------------
921IOStream::pos_type RaidFileWrite::GetDiscUsageInBlocks()
922{
923        if(mOSFileHandle == -1)
924        {
925                THROW_EXCEPTION(RaidFileException, CanOnlyGetUsageBeforeCommit)
926        }
927       
928        // Stat to get size
929        struct stat st;
930        if(fstat(mOSFileHandle, &st) != 0)
931        {
932                THROW_EXCEPTION(RaidFileException, OSError)
933        }
934       
935        // Then return calculation
936        RaidFileController &rcontroller(RaidFileController::GetController());
937        RaidFileDiscSet rdiscSet(rcontroller.GetDiscSet(mSetNumber));
938        return RaidFileUtil::DiscUsageInBlocks(st.st_size, rdiscSet);
939}
940
941
Note: See TracBrowser for help on using the repository browser.