1 /* 2 * Copyright 2001-2007, Axel Dörfler, axeld@pinc-software.de. 3 * This file may be used under the terms of the MIT License. 4 */ 5 #ifndef JOURNAL_H 6 #define JOURNAL_H 7 8 9 #include "system_dependencies.h" 10 11 #ifndef _IMPEXP_KERNEL 12 # define _IMPEXP_KERNEL 13 #endif 14 15 #include "Volume.h" 16 #include "Chain.h" 17 #include "Utility.h" 18 19 20 struct run_array; 21 class LogEntry; 22 typedef DoublyLinkedList<LogEntry> LogEntryList; 23 24 25 // Locking policy in BFS: if you need both, the volume lock and the 26 // journal lock, you must lock the volume first - or else you will 27 // end up in a deadlock. 28 // That is, if you start a transaction, and will need to lock the 29 // volume while the transaction is in progress (for the unsafe 30 // get_vnode() call, for example), you must lock the volume before 31 // starting the transaction. 32 33 class Journal { 34 public: 35 Journal(Volume *); 36 ~Journal(); 37 38 status_t InitCheck(); 39 40 status_t Lock(Transaction *owner); 41 void Unlock(Transaction *owner, bool success); 42 43 status_t ReplayLog(); 44 45 Transaction *CurrentTransaction() const { return fOwner; } 46 47 status_t FlushLogAndBlocks(); 48 Volume *GetVolume() const { return fVolume; } 49 int32 TransactionID() const { return fTransactionID; } 50 51 inline uint32 FreeLogBlocks() const; 52 53 private: 54 bool _HasSubTransaction() { return fHasSubtransaction; } 55 uint32 _TransactionSize() const; 56 status_t _WriteTransactionToLog(); 57 status_t _CheckRunArray(const run_array *array); 58 status_t _ReplayRunArray(int32 *start); 59 status_t _TransactionDone(bool success); 60 static void _BlockNotify(int32 transactionID, int32 event, void *arg); 61 62 Volume *fVolume; 63 RecursiveLock fLock; 64 Transaction *fOwner; 65 uint32 fLogSize, fMaxTransactionSize, fUsed; 66 int32 fUnwrittenTransactions; 67 SimpleLock fEntriesLock; 68 LogEntryList fEntries; 69 bigtime_t fTimestamp; 70 int32 fTransactionID; 71 bool fHasSubtransaction; 72 }; 73 74 75 inline uint32 76 Journal::FreeLogBlocks() const 77 { 78 return fVolume->LogStart() <= fVolume->LogEnd() ? 79 fLogSize - fVolume->LogEnd() + fVolume->LogStart() 80 : fVolume->LogStart() - fVolume->LogEnd(); 81 } 82 83 84 // For now, that's only a dumb class that does more or less nothing 85 // else than writing the blocks directly to the real location. 86 // It doesn't yet use logging. 87 88 class Transaction { 89 public: 90 Transaction(Volume *volume, off_t refBlock) 91 : 92 fJournal(NULL) 93 { 94 Start(volume, refBlock); 95 } 96 97 Transaction(Volume *volume, block_run refRun) 98 : 99 fJournal(NULL) 100 { 101 Start(volume, volume->ToBlock(refRun)); 102 } 103 104 Transaction() 105 : 106 fJournal(NULL) 107 { 108 } 109 110 ~Transaction() 111 { 112 if (fJournal) 113 fJournal->Unlock(this, false); 114 } 115 116 status_t Start(Volume *volume, off_t refBlock); 117 bool IsStarted() const { return fJournal != NULL; } 118 119 void 120 Done() 121 { 122 if (fJournal != NULL) 123 fJournal->Unlock(this, true); 124 fJournal = NULL; 125 } 126 127 bool 128 HasParent() 129 { 130 if (fJournal != NULL) 131 return fJournal->CurrentTransaction() == this; 132 133 return false; 134 } 135 136 status_t 137 WriteBlocks(off_t blockNumber, const uint8 *buffer, 138 size_t numBlocks = 1) 139 { 140 if (fJournal == NULL) 141 return B_NO_INIT; 142 143 void *cache = GetVolume()->BlockCache(); 144 size_t blockSize = GetVolume()->BlockSize(); 145 146 for (size_t i = 0; i < numBlocks; i++) { 147 void *block = block_cache_get_empty(cache, blockNumber + i, 148 ID()); 149 if (block == NULL) 150 return B_ERROR; 151 152 memcpy(block, buffer, blockSize); 153 buffer += blockSize; 154 155 block_cache_put(cache, blockNumber + i); 156 } 157 158 return B_OK; 159 } 160 161 Volume *GetVolume() 162 { return fJournal != NULL ? fJournal->GetVolume() : NULL; } 163 int32 ID() const 164 { return fJournal->TransactionID(); } 165 166 private: 167 Transaction(const Transaction &); 168 Transaction &operator=(const Transaction &); 169 // no implementation 170 171 Journal *fJournal; 172 }; 173 174 #endif /* JOURNAL_H */ 175