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 64 Volume* fVolume; 65 recursive_lock fLock; 66 Transaction* fOwner; 67 uint32 fLogSize; 68 uint32 fMaxTransactionSize; 69 uint32 fUsed; 70 int32 fUnwrittenTransactions; 71 mutex fEntriesLock; 72 LogEntryList fEntries; 73 bigtime_t fTimestamp; 74 int32 fTransactionID; 75 bool fHasSubtransaction; 76 bool fSeparateSubTransactions; 77 }; 78 79 80 inline uint32 81 Journal::FreeLogBlocks() const 82 { 83 return fVolume->LogStart() <= fVolume->LogEnd() 84 ? fLogSize - fVolume->LogEnd() + fVolume->LogStart() 85 : fVolume->LogStart() - fVolume->LogEnd(); 86 } 87 88 89 class TransactionListener 90 : public DoublyLinkedListLinkImpl<TransactionListener> { 91 public: 92 TransactionListener(); 93 virtual ~TransactionListener(); 94 95 virtual void TransactionDone(bool success) = 0; 96 virtual void RemovedFromTransaction() = 0; 97 }; 98 99 typedef DoublyLinkedList<TransactionListener> TransactionListeners; 100 101 102 class Transaction { 103 public: 104 Transaction(Volume* volume, off_t refBlock) 105 : 106 fJournal(NULL), 107 fParent(NULL) 108 { 109 Start(volume, refBlock); 110 } 111 112 Transaction(Volume* volume, block_run refRun) 113 : 114 fJournal(NULL), 115 fParent(NULL) 116 { 117 Start(volume, volume->ToBlock(refRun)); 118 } 119 120 Transaction() 121 : 122 fJournal(NULL), 123 fParent(NULL) 124 { 125 } 126 127 ~Transaction() 128 { 129 if (fJournal != NULL) 130 fJournal->Unlock(this, false); 131 } 132 133 status_t Start(Volume* volume, off_t refBlock); 134 bool IsStarted() const { return fJournal != NULL; } 135 136 status_t Done() 137 { 138 status_t status = B_OK; 139 if (fJournal != NULL) { 140 status = fJournal->Unlock(this, true); 141 if (status == B_OK) 142 fJournal = NULL; 143 } 144 return status; 145 } 146 147 bool HasParent() const 148 { 149 return fParent != NULL; 150 } 151 152 bool IsTooLarge() const 153 { 154 return fJournal->CurrentTransactionTooLarge(); 155 } 156 157 status_t WriteBlocks(off_t blockNumber, const uint8* buffer, 158 size_t numBlocks = 1) 159 { 160 if (fJournal == NULL) 161 return B_NO_INIT; 162 163 void* cache = GetVolume()->BlockCache(); 164 size_t blockSize = GetVolume()->BlockSize(); 165 166 for (size_t i = 0; i < numBlocks; i++) { 167 void* block = block_cache_get_empty(cache, blockNumber + i, 168 ID()); 169 if (block == NULL) 170 return B_ERROR; 171 172 memcpy(block, buffer, blockSize); 173 buffer += blockSize; 174 175 block_cache_put(cache, blockNumber + i); 176 } 177 178 return B_OK; 179 } 180 181 Volume* GetVolume() const 182 { return fJournal != NULL ? fJournal->GetVolume() : NULL; } 183 int32 ID() const 184 { return fJournal->TransactionID(); } 185 186 void AddListener(TransactionListener* listener); 187 void RemoveListener(TransactionListener* listener); 188 189 void NotifyListeners(bool success); 190 void MoveListenersTo(Transaction* transaction); 191 192 void SetParent(Transaction* parent) 193 { fParent = parent; } 194 Transaction* Parent() const 195 { return fParent; } 196 197 private: 198 Transaction(const Transaction& other); 199 Transaction& operator=(const Transaction& other); 200 // no implementation 201 202 Journal* fJournal; 203 TransactionListeners fListeners; 204 Transaction* fParent; 205 }; 206 207 208 #ifdef BFS_DEBUGGER_COMMANDS 209 int dump_journal(int argc, char** argv); 210 #endif 211 212 213 #endif // JOURNAL_H 214