xref: /haiku/src/add-ons/kernel/file_systems/ext2/Transaction.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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