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
TransactionListener()28 TransactionListener::TransactionListener()
29 {
30 }
31
32
~TransactionListener()33 TransactionListener::~TransactionListener()
34 {
35 }
36
37
Transaction()38 Transaction::Transaction()
39 :
40 fJournal(NULL),
41 fParent(NULL)
42 {
43 }
44
45
Transaction(Journal * journal)46 Transaction::Transaction(Journal* journal)
47 :
48 fJournal(NULL),
49 fParent(NULL)
50 {
51 Start(journal);
52 }
53
54
~Transaction()55 Transaction::~Transaction()
56 {
57 if (IsStarted())
58 fJournal->Unlock(this, false);
59 }
60
61 status_t
Start(Journal * journal)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
Done(bool success)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
ID() const95 Transaction::ID() const
96 {
97 if (!IsStarted())
98 return -1;
99
100 return fJournal->TransactionID();
101 }
102
103
104 bool
IsStarted() const105 Transaction::IsStarted() const
106 {
107 return fJournal != NULL;
108 }
109
110
111 bool
HasParent() const112 Transaction::HasParent() const
113 {
114 return fParent != NULL;
115 }
116
117
118 status_t
WriteBlocks(off_t blockNumber,const uint8 * buffer,size_t numBlocks)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
Split()144 Transaction::Split()
145 {
146 cache_start_sub_transaction(fJournal->GetFilesystemVolume()->BlockCache(),
147 ID());
148 }
149
150
151 Volume*
GetVolume() const152 Transaction::GetVolume() const
153 {
154 if (!IsStarted())
155 return NULL;
156
157 return fJournal->GetFilesystemVolume();
158 }
159
160
161 void
AddListener(TransactionListener * listener)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
RemoveListener(TransactionListener * listener)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
NotifyListeners(bool success)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
MoveListenersTo(Transaction * transaction)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
SetParent(Transaction * transaction)215 Transaction::SetParent(Transaction* transaction)
216 {
217 fParent = transaction;
218 }
219
220
221 Transaction*
Parent() const222 Transaction::Parent() const
223 {
224 return fParent;
225 }
226