1 /* 2 * Copyright 2010, Haiku Inc. All rights reserved. 3 * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de. 4 * This file may be used under the terms of the MIT License. 5 * 6 * Authors: 7 * Janito V. Ferreira Filho 8 */ 9 10 11 #include "Transaction.h" 12 13 #include <string.h> 14 15 #include <fs_cache.h> 16 17 #include "Journal.h" 18 19 20 //#define TRACE_EXT2 21 #ifdef TRACE_EXT2 22 # define TRACE(x...) dprintf("\33[34mext2:\33[0m " x) 23 #else 24 # define TRACE(x...) ; 25 #endif 26 27 28 TransactionListener::TransactionListener() 29 { 30 } 31 32 33 TransactionListener::~TransactionListener() 34 { 35 } 36 37 38 Transaction::Transaction() 39 : 40 fJournal(NULL), 41 fParent(NULL) 42 { 43 } 44 45 46 Transaction::Transaction(Journal* journal) 47 : 48 fJournal(NULL), 49 fParent(NULL) 50 { 51 Start(journal); 52 } 53 54 55 Transaction::~Transaction() 56 { 57 if (IsStarted()) 58 fJournal->Unlock(this, false); 59 } 60 61 status_t 62 Transaction::Start(Journal* journal) 63 { 64 if (IsStarted()) 65 return B_OK; 66 67 fJournal = journal; 68 if (fJournal == NULL) 69 return B_ERROR; 70 71 status_t status = fJournal->Lock(this, false); 72 if (status != B_OK) 73 fJournal = NULL; 74 75 return status; 76 } 77 78 79 status_t 80 Transaction::Done(bool success) 81 { 82 if (!IsStarted()) 83 return B_OK; 84 85 status_t status = fJournal->Unlock(this, success); 86 87 if (status == B_OK) 88 fJournal = NULL; 89 90 return status; 91 } 92 93 94 int32 95 Transaction::ID() const 96 { 97 if (!IsStarted()) 98 return -1; 99 100 return fJournal->TransactionID(); 101 } 102 103 104 bool 105 Transaction::IsStarted() const 106 { 107 return fJournal != NULL; 108 } 109 110 111 bool 112 Transaction::HasParent() const 113 { 114 return fParent != NULL; 115 } 116 117 118 status_t 119 Transaction::WriteBlocks(off_t blockNumber, const uint8* buffer, 120 size_t numBlocks) 121 { 122 if (!IsStarted()) 123 return B_NO_INIT; 124 125 void* cache = GetVolume()->BlockCache(); 126 size_t blockSize = GetVolume()->BlockSize(); 127 128 for (size_t i = 0; i < numBlocks; ++i) { 129 void* block = block_cache_get_empty(cache, blockNumber + i, ID()); 130 if (block == NULL) 131 return B_ERROR; 132 133 memcpy(block, buffer, blockSize); 134 buffer += blockSize; 135 136 block_cache_put(cache, blockNumber + i); 137 } 138 139 return B_OK; 140 } 141 142 143 void 144 Transaction::Split() 145 { 146 cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(), 147 ID()); 148 } 149 150 151 Volume* 152 Transaction::GetVolume() const 153 { 154 if (!IsStarted()) 155 return NULL; 156 157 return fJournal->GetFilesystemVolume(); 158 } 159 160 161 void 162 Transaction::AddListener(TransactionListener* listener) 163 { 164 TRACE("Transaction::AddListener()\n"); 165 if (!IsStarted()) 166 panic("Transaction is not running!"); 167 168 fListeners.Add(listener); 169 } 170 171 172 void 173 Transaction::RemoveListener(TransactionListener* listener) 174 { 175 TRACE("Transaction::RemoveListener()\n"); 176 if (!IsStarted()) 177 panic("Transaction is not running!"); 178 179 fListeners.Remove(listener); 180 listener->RemovedFromTransaction(); 181 } 182 183 184 void 185 Transaction::NotifyListeners(bool success) 186 { 187 TRACE("Transaction::NotifyListeners(): fListeners.First(): %p\n", 188 fListeners.First()); 189 if (success) { 190 TRACE("Transaction::NotifyListeners(true): Number of listeners: %" 191 B_PRId32 "\n", fListeners.Count()); 192 } else { 193 TRACE("Transaction::NotifyListeners(false): Number of listeners: %" 194 B_PRId32 "\n", fListeners.Count()); 195 } 196 TRACE("Transaction::NotifyListeners(): Finished counting\n"); 197 198 while (TransactionListener* listener = fListeners.RemoveHead()) { 199 listener->TransactionDone(success); 200 listener->RemovedFromTransaction(); 201 } 202 } 203 204 205 void 206 Transaction::MoveListenersTo(Transaction* transaction) 207 { 208 TRACE("Transaction::MoveListenersTo()\n"); 209 while (TransactionListener* listener = fListeners.RemoveHead()) 210 transaction->fListeners.Add(listener); 211 } 212 213 214 void 215 Transaction::SetParent(Transaction* transaction) 216 { 217 fParent = transaction; 218 } 219 220 221 Transaction* 222 Transaction::Parent() const 223 { 224 return fParent; 225 } 226