xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision 481f986b59e7782458dcc5fe98ad59a57480e5db)
1 /*
2  * Copyright 2001-2010, Axel Dörfler, axeld@pinc-software.de.
3  * This file may be used under the terms of the MIT License.
4  */
5 #ifndef JOURNAL_H
6 #define JOURNAL_H
7 
8 
9 #include "system_dependencies.h"
10 
11 #include "Volume.h"
12 #include "Utility.h"
13 
14 
15 struct run_array;
16 class Inode;
17 class LogEntry;
18 typedef DoublyLinkedList<LogEntry> LogEntryList;
19 
20 
21 class Journal {
22 public:
23 							Journal(Volume* volume);
24 							~Journal();
25 
26 			status_t		InitCheck();
27 
28 			status_t		Lock(Transaction* owner,
29 								bool separateSubTransactions);
30 			status_t		Unlock(Transaction* owner, bool success);
31 
32 			status_t		ReplayLog();
33 
34 			Transaction*	CurrentTransaction() const { return fOwner; }
35 			size_t			CurrentTransactionSize() const;
36 			bool			CurrentTransactionTooLarge() const;
37 
38 			status_t		FlushLogAndBlocks();
39 			Volume*			GetVolume() const { return fVolume; }
40 			int32			TransactionID() const { return fTransactionID; }
41 
42 	inline	uint32			FreeLogBlocks() const;
43 
44 #ifdef BFS_DEBUGGER_COMMANDS
45 			void			Dump();
46 #endif
47 
48 private:
49 			bool			_HasSubTransaction() const
50 								{ return fHasSubtransaction; }
51 
52 			status_t		_FlushLog(bool canWait, bool flushBlocks);
53 			uint32			_TransactionSize() const;
54 			status_t		_WriteTransactionToLog();
55 			status_t		_CheckRunArray(const run_array* array);
56 			status_t		_ReplayRunArray(int32* start);
57 			status_t		_TransactionDone(bool success);
58 
59 	static	void			_TransactionWritten(int32 transactionID,
60 								int32 event, void* _logEntry);
61 	static	void			_TransactionIdle(int32 transactionID, int32 event,
62 								void* _journal);
63 
64 			Volume*			fVolume;
65 			recursive_lock	fLock;
66 			Transaction*	fOwner;
67 			uint32			fLogSize;
68 			uint32			fMaxTransactionSize;
69 			uint32			fUsed;
70 			int32			fUnwrittenTransactions;
71 			mutex			fEntriesLock;
72 			LogEntryList	fEntries;
73 			bigtime_t		fTimestamp;
74 			int32			fTransactionID;
75 			bool			fHasSubtransaction;
76 			bool			fSeparateSubTransactions;
77 };
78 
79 
80 inline uint32
81 Journal::FreeLogBlocks() const
82 {
83 	return fVolume->LogStart() <= fVolume->LogEnd()
84 		? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
85 		: fVolume->LogStart() - fVolume->LogEnd();
86 }
87 
88 
89 class TransactionListener
90 	: public DoublyLinkedListLinkImpl<TransactionListener> {
91 public:
92 								TransactionListener();
93 	virtual						~TransactionListener();
94 
95 	virtual void				TransactionDone(bool success) = 0;
96 	virtual void				RemovedFromTransaction() = 0;
97 };
98 
99 typedef DoublyLinkedList<TransactionListener> TransactionListeners;
100 
101 
102 class Transaction {
103 public:
104 	Transaction(Volume* volume, off_t refBlock)
105 		:
106 		fJournal(NULL),
107 		fParent(NULL)
108 	{
109 		Start(volume, refBlock);
110 	}
111 
112 	Transaction(Volume* volume, block_run refRun)
113 		:
114 		fJournal(NULL),
115 		fParent(NULL)
116 	{
117 		Start(volume, volume->ToBlock(refRun));
118 	}
119 
120 	Transaction()
121 		:
122 		fJournal(NULL),
123 		fParent(NULL)
124 	{
125 	}
126 
127 	~Transaction()
128 	{
129 		if (fJournal != NULL)
130 			fJournal->Unlock(this, false);
131 	}
132 
133 	status_t Start(Volume* volume, off_t refBlock);
134 	bool IsStarted() const { return fJournal != NULL; }
135 
136 	status_t Done()
137 	{
138 		status_t status = B_OK;
139 		if (fJournal != NULL) {
140 			status = fJournal->Unlock(this, true);
141 			if (status == B_OK)
142 				fJournal = NULL;
143 		}
144 		return status;
145 	}
146 
147 	bool HasParent() const
148 	{
149 		return fParent != NULL;
150 	}
151 
152 	bool IsTooLarge() const
153 	{
154 		return fJournal->CurrentTransactionTooLarge();
155 	}
156 
157 	status_t WriteBlocks(off_t blockNumber, const uint8* buffer,
158 		size_t numBlocks = 1)
159 	{
160 		if (fJournal == NULL)
161 			return B_NO_INIT;
162 
163 		void* cache = GetVolume()->BlockCache();
164 		size_t blockSize = GetVolume()->BlockSize();
165 
166 		for (size_t i = 0; i < numBlocks; i++) {
167 			void* block = block_cache_get_empty(cache, blockNumber + i,
168 				ID());
169 			if (block == NULL)
170 				return B_ERROR;
171 
172 			memcpy(block, buffer, blockSize);
173 			buffer += blockSize;
174 
175 			block_cache_put(cache, blockNumber + i);
176 		}
177 
178 		return B_OK;
179 	}
180 
181 	void Split()
182 	{
183 		cache_start_sub_transaction(fJournal->GetVolume()->BlockCache(),
184 			fJournal->TransactionID());
185 	}
186 
187 	Volume* GetVolume() const
188 		{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
189 	int32 ID() const
190 		{ return fJournal->TransactionID(); }
191 
192 	void AddListener(TransactionListener* listener);
193 	void RemoveListener(TransactionListener* listener);
194 
195 	void NotifyListeners(bool success);
196 	void MoveListenersTo(Transaction* transaction);
197 
198 	void SetParent(Transaction* parent)
199 		{ fParent = parent; }
200 	Transaction* Parent() const
201 		{ return fParent; }
202 
203 private:
204 	Transaction(const Transaction& other);
205 	Transaction& operator=(const Transaction& other);
206 		// no implementation
207 
208 	Journal*				fJournal;
209 	TransactionListeners	fListeners;
210 	Transaction*			fParent;
211 };
212 
213 
214 #ifdef BFS_DEBUGGER_COMMANDS
215 int dump_journal(int argc, char** argv);
216 #endif
217 
218 
219 #endif	// JOURNAL_H
220