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 28TransactionListener::TransactionListener() 29{ 30} 31 32 33TransactionListener::~TransactionListener() 34{ 35} 36 37 38Transaction::Transaction() 39 : 40 fJournal(NULL), 41 fParent(NULL) 42{ 43} 44 45 46Transaction::Transaction(Journal* journal) 47 : 48 fJournal(NULL), 49 fParent(NULL) 50{ 51 Start(journal); 52} 53 54 55Transaction::~Transaction() 56{ 57 if (IsStarted()) 58 fJournal->Unlock(this, false); 59} 60 61status_t 62Transaction::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 79status_t 80Transaction::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 94int32 95Transaction::ID() const 96{ 97 if (!IsStarted()) 98 return -1; 99 100 return fJournal->TransactionID(); 101} 102 103 104bool 105Transaction::IsStarted() const 106{ 107 return fJournal != NULL; 108} 109 110 111bool 112Transaction::HasParent() const 113{ 114 return fParent != NULL; 115} 116 117 118status_t 119Transaction::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 143void 144Transaction::Split() 145{ 146 cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(), 147 ID()); 148} 149 150 151Volume* 152Transaction::GetVolume() const 153{ 154 if (!IsStarted()) 155 return NULL; 156 157 return fJournal->GetFilesystemVolume(); 158} 159 160 161void 162Transaction::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 172void 173Transaction::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 184void 185Transaction::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 205void 206Transaction::MoveListenersTo(Transaction* transaction) 207{ 208 TRACE("Transaction::MoveListenersTo()\n"); 209 while (TransactionListener* listener = fListeners.RemoveHead()) 210 transaction->fListeners.Add(listener); 211} 212 213 214void 215Transaction::SetParent(Transaction* transaction) 216{ 217 fParent = transaction; 218} 219 220 221Transaction* 222Transaction::Parent() const 223{ 224 return fParent; 225} 226