1 /* 2 * Copyright 2001-2008, 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 #ifdef BFS_DEBUGGER_COMMANDS 54 void Dump(); 55 #endif 56 57 private: 58 bool _HasSubTransaction() { return fHasSubtransaction; } 59 status_t _FlushLog(bool canWait, bool flushBlocks); 60 uint32 _TransactionSize() const; 61 status_t _WriteTransactionToLog(); 62 status_t _CheckRunArray(const run_array *array); 63 status_t _ReplayRunArray(int32 *start); 64 status_t _TransactionDone(bool success); 65 66 static void _TransactionWritten(int32 transactionID, int32 event, 67 void *_logEntry); 68 static void _TransactionIdle(int32 transactionID, int32 event, 69 void *_journal); 70 71 Volume *fVolume; 72 RecursiveLock fLock; 73 Transaction *fOwner; 74 uint32 fLogSize, fMaxTransactionSize, fUsed; 75 int32 fUnwrittenTransactions; 76 SimpleLock fEntriesLock; 77 LogEntryList fEntries; 78 bigtime_t fTimestamp; 79 int32 fTransactionID; 80 bool fHasSubtransaction; 81 }; 82 83 84 inline uint32 85 Journal::FreeLogBlocks() const 86 { 87 return fVolume->LogStart() <= fVolume->LogEnd() 88 ? fLogSize - fVolume->LogEnd() + fVolume->LogStart() 89 : fVolume->LogStart() - fVolume->LogEnd(); 90 } 91 92 93 // For now, that's only a dumb class that does more or less nothing 94 // else than writing the blocks directly to the real location. 95 // It doesn't yet use logging. 96 97 class Transaction { 98 public: 99 Transaction(Volume *volume, off_t refBlock) 100 : 101 fJournal(NULL) 102 { 103 Start(volume, refBlock); 104 } 105 106 Transaction(Volume *volume, block_run refRun) 107 : 108 fJournal(NULL) 109 { 110 Start(volume, volume->ToBlock(refRun)); 111 } 112 113 Transaction() 114 : 115 fJournal(NULL) 116 { 117 } 118 119 ~Transaction() 120 { 121 if (fJournal) 122 fJournal->Unlock(this, false); 123 } 124 125 status_t Start(Volume *volume, off_t refBlock); 126 bool IsStarted() const { return fJournal != NULL; } 127 128 void 129 Done() 130 { 131 if (fJournal != NULL) 132 fJournal->Unlock(this, true); 133 fJournal = NULL; 134 } 135 136 bool 137 HasParent() 138 { 139 if (fJournal != NULL) 140 return fJournal->CurrentTransaction() == this; 141 142 return false; 143 } 144 145 status_t 146 WriteBlocks(off_t blockNumber, const uint8 *buffer, 147 size_t numBlocks = 1) 148 { 149 if (fJournal == NULL) 150 return B_NO_INIT; 151 152 void *cache = GetVolume()->BlockCache(); 153 size_t blockSize = GetVolume()->BlockSize(); 154 155 for (size_t i = 0; i < numBlocks; i++) { 156 void *block = block_cache_get_empty(cache, blockNumber + i, 157 ID()); 158 if (block == NULL) 159 return B_ERROR; 160 161 memcpy(block, buffer, blockSize); 162 buffer += blockSize; 163 164 block_cache_put(cache, blockNumber + i); 165 } 166 167 return B_OK; 168 } 169 170 Volume *GetVolume() 171 { return fJournal != NULL ? fJournal->GetVolume() : NULL; } 172 int32 ID() const 173 { return fJournal->TransactionID(); } 174 175 private: 176 Transaction(const Transaction &); 177 Transaction &operator=(const Transaction &); 178 // no implementation 179 180 Journal *fJournal; 181 }; 182 183 #ifdef BFS_DEBUGGER_COMMANDS 184 int dump_journal(int argc, char **argv); 185 #endif 186 187 #endif /* JOURNAL_H */ 188