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