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 #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 typedef SinglyLinkedList<Inode> InodeList; 20 21 22 class Journal { 23 public: 24 Journal(Volume* volume); 25 ~Journal(); 26 27 status_t InitCheck(); 28 29 status_t Lock(Transaction* owner); 30 void Unlock(Transaction* owner, bool success); 31 32 status_t ReplayLog(); 33 34 Transaction* CurrentTransaction() const { return fOwner; } 35 36 status_t FlushLogAndBlocks(); 37 Volume* GetVolume() const { return fVolume; } 38 int32 TransactionID() const { return fTransactionID; } 39 40 inline uint32 FreeLogBlocks() const; 41 42 #ifdef BFS_DEBUGGER_COMMANDS 43 void Dump(); 44 #endif 45 46 private: 47 bool _HasSubTransaction() { return fHasSubtransaction; } 48 status_t _FlushLog(bool canWait, bool flushBlocks); 49 uint32 _TransactionSize() const; 50 status_t _WriteTransactionToLog(); 51 status_t _CheckRunArray(const run_array* array); 52 status_t _ReplayRunArray(int32* start); 53 status_t _TransactionDone(bool success); 54 55 static void _TransactionWritten(int32 transactionID, 56 int32 event, void* _logEntry); 57 static void _TransactionIdle(int32 transactionID, int32 event, 58 void* _journal); 59 60 Volume* fVolume; 61 recursive_lock fLock; 62 Transaction* fOwner; 63 uint32 fLogSize; 64 uint32 fMaxTransactionSize; 65 uint32 fUsed; 66 int32 fUnwrittenTransactions; 67 mutex 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 != NULL) { 113 fJournal->Unlock(this, false); 114 _UnlockInodes(); 115 } 116 } 117 118 status_t Start(Volume* volume, off_t refBlock); 119 bool IsStarted() const { return fJournal != NULL; } 120 121 void Done() 122 { 123 if (fJournal != NULL) { 124 _UnlockInodes(); 125 fJournal->Unlock(this, true); 126 } 127 fJournal = NULL; 128 } 129 130 bool HasParent() 131 { 132 if (fJournal != NULL) 133 return fJournal->CurrentTransaction() == this; 134 135 return false; 136 } 137 138 status_t WriteBlocks(off_t blockNumber, const uint8* buffer, 139 size_t numBlocks = 1) 140 { 141 if (fJournal == NULL) 142 return B_NO_INIT; 143 144 void* cache = GetVolume()->BlockCache(); 145 size_t blockSize = GetVolume()->BlockSize(); 146 147 for (size_t i = 0; i < numBlocks; i++) { 148 void* block = block_cache_get_empty(cache, blockNumber + i, 149 ID()); 150 if (block == NULL) 151 return B_ERROR; 152 153 memcpy(block, buffer, blockSize); 154 buffer += blockSize; 155 156 block_cache_put(cache, blockNumber + i); 157 } 158 159 return B_OK; 160 } 161 162 Volume *GetVolume() 163 { return fJournal != NULL ? fJournal->GetVolume() : NULL; } 164 int32 ID() const 165 { return fJournal->TransactionID(); } 166 167 void AddInode(Inode* inode); 168 169 private: 170 Transaction(const Transaction& other); 171 Transaction& operator=(const Transaction& other); 172 // no implementation 173 174 void _UnlockInodes(); 175 176 Journal* fJournal; 177 InodeList fLockedInodes; 178 }; 179 180 #ifdef BFS_DEBUGGER_COMMANDS 181 int dump_journal(int argc, char** argv); 182 #endif 183 184 #endif // JOURNAL_H 185