1 /* 2 * Copyright 2001-2012, 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 #include "Volume.h" 12 #include "Utility.h" 13 14 15 struct run_array; 16 class Inode; 17 class LogEntry; 18 typedef DoublyLinkedList<LogEntry> LogEntryList; 19 20 21 class Journal { 22 public: 23 Journal(Volume* volume); 24 ~Journal(); 25 26 status_t InitCheck(); 27 28 status_t Lock(Transaction* owner, 29 bool separateSubTransactions); 30 status_t Unlock(Transaction* owner, bool success); 31 32 status_t ReplayLog(); 33 34 Transaction* CurrentTransaction() const { return fOwner; } 35 size_t CurrentTransactionSize() const; 36 bool CurrentTransactionTooLarge() const; 37 38 status_t FlushLogAndBlocks(); 39 Volume* GetVolume() const { return fVolume; } 40 int32 TransactionID() const { return fTransactionID; } 41 42 inline uint32 FreeLogBlocks() const; 43 44 #ifdef BFS_DEBUGGER_COMMANDS 45 void Dump(); 46 #endif 47 48 private: 49 bool _HasSubTransaction() const 50 { return fHasSubtransaction; } 51 52 status_t _FlushLog(bool canWait, bool flushBlocks); 53 uint32 _TransactionSize() const; 54 status_t _WriteTransactionToLog(); 55 status_t _CheckRunArray(const run_array* array); 56 status_t _ReplayRunArray(int32* start); 57 status_t _TransactionDone(bool success); 58 59 static void _TransactionWritten(int32 transactionID, 60 int32 event, void* _logEntry); 61 static void _TransactionIdle(int32 transactionID, int32 event, 62 void* _journal); 63 static status_t _FlushLog(void* _journal); 64 65 private: 66 Volume* fVolume; 67 recursive_lock fLock; 68 Transaction* fOwner; 69 uint32 fLogSize; 70 uint32 fMaxTransactionSize; 71 uint32 fUsed; 72 int32 fUnwrittenTransactions; 73 mutex fEntriesLock; 74 LogEntryList fEntries; 75 bigtime_t fTimestamp; 76 int32 fTransactionID; 77 bool fHasSubtransaction; 78 bool fSeparateSubTransactions; 79 }; 80 81 82 inline uint32 83 Journal::FreeLogBlocks() const 84 { 85 return fVolume->LogStart() <= fVolume->LogEnd() 86 ? fLogSize - fVolume->LogEnd() + fVolume->LogStart() 87 : fVolume->LogStart() - fVolume->LogEnd(); 88 } 89 90 91 class TransactionListener 92 : public DoublyLinkedListLinkImpl<TransactionListener> { 93 public: 94 TransactionListener(); 95 virtual ~TransactionListener(); 96 97 virtual void TransactionDone(bool success) = 0; 98 virtual void RemovedFromTransaction() = 0; 99 }; 100 101 typedef DoublyLinkedList<TransactionListener> TransactionListeners; 102 103 104 class Transaction { 105 public: 106 Transaction(Volume* volume, off_t refBlock) 107 : 108 fJournal(NULL), 109 fParent(NULL) 110 { 111 Start(volume, refBlock); 112 } 113 114 Transaction(Volume* volume, block_run refRun) 115 : 116 fJournal(NULL), 117 fParent(NULL) 118 { 119 Start(volume, volume->ToBlock(refRun)); 120 } 121 122 Transaction() 123 : 124 fJournal(NULL), 125 fParent(NULL) 126 { 127 } 128 129 ~Transaction() 130 { 131 if (fJournal != NULL) 132 fJournal->Unlock(this, false); 133 } 134 135 status_t Start(Volume* volume, off_t refBlock); 136 bool IsStarted() const { return fJournal != NULL; } 137 138 status_t Done() 139 { 140 status_t status = B_OK; 141 if (fJournal != NULL) { 142 status = fJournal->Unlock(this, true); 143 if (status == B_OK) 144 fJournal = NULL; 145 } 146 return status; 147 } 148 149 bool HasParent() const 150 { 151 return fParent != NULL; 152 } 153 154 bool IsTooLarge() const 155 { 156 return fJournal->CurrentTransactionTooLarge(); 157 } 158 159 status_t WriteBlocks(off_t blockNumber, const uint8* buffer, 160 size_t numBlocks = 1) 161 { 162 if (fJournal == NULL) 163 return B_NO_INIT; 164 165 void* cache = GetVolume()->BlockCache(); 166 size_t blockSize = GetVolume()->BlockSize(); 167 168 for (size_t i = 0; i < numBlocks; i++) { 169 void* block = block_cache_get_empty(cache, blockNumber + i, 170 ID()); 171 if (block == NULL) 172 return B_ERROR; 173 174 memcpy(block, buffer, blockSize); 175 buffer += blockSize; 176 177 block_cache_put(cache, blockNumber + i); 178 } 179 180 return B_OK; 181 } 182 183 Volume* GetVolume() const 184 { return fJournal != NULL ? fJournal->GetVolume() : NULL; } 185 int32 ID() const 186 { return fJournal->TransactionID(); } 187 188 void AddListener(TransactionListener* listener); 189 void RemoveListener(TransactionListener* listener); 190 191 void NotifyListeners(bool success); 192 void MoveListenersTo(Transaction* transaction); 193 194 void SetParent(Transaction* parent) 195 { fParent = parent; } 196 Transaction* Parent() const 197 { return fParent; } 198 199 private: 200 Transaction(const Transaction& other); 201 Transaction& operator=(const Transaction& other); 202 // no implementation 203 204 Journal* fJournal; 205 TransactionListeners fListeners; 206 Transaction* fParent; 207 }; 208 209 210 #ifdef BFS_DEBUGGER_COMMANDS 211 int dump_journal(int argc, char** argv); 212 #endif 213 214 215 #endif // JOURNAL_H 216