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