xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2001-2012, 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 	static	status_t		_FlushLog(void* _journal);
64 
65 private:
66 			Volume*			fVolume;
67 			recursive_lock	fLock;
68 			Transaction*	fOwner;
69 			uint32			fLogSize;
70 			uint32			fMaxTransactionSize;
71 			uint32			fUsed;
72 			int32			fUnwrittenTransactions;
73 			mutex			fEntriesLock;
74 			LogEntryList	fEntries;
75 			bigtime_t		fTimestamp;
76 			int32			fTransactionID;
77 			bool			fHasSubtransaction;
78 			bool			fSeparateSubTransactions;
79 };
80 
81 
82 inline uint32
83 Journal::FreeLogBlocks() const
84 {
85 	return fVolume->LogStart() <= fVolume->LogEnd()
86 		? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
87 		: fVolume->LogStart() - fVolume->LogEnd();
88 }
89 
90 
91 class TransactionListener
92 	: public DoublyLinkedListLinkImpl<TransactionListener> {
93 public:
94 								TransactionListener();
95 	virtual						~TransactionListener();
96 
97 	virtual void				TransactionDone(bool success) = 0;
98 	virtual void				RemovedFromTransaction() = 0;
99 };
100 
101 typedef DoublyLinkedList<TransactionListener> TransactionListeners;
102 
103 
104 class Transaction {
105 public:
106 	Transaction(Volume* volume, off_t refBlock)
107 		:
108 		fJournal(NULL),
109 		fParent(NULL)
110 	{
111 		Start(volume, refBlock);
112 	}
113 
114 	Transaction(Volume* volume, block_run refRun)
115 		:
116 		fJournal(NULL),
117 		fParent(NULL)
118 	{
119 		Start(volume, volume->ToBlock(refRun));
120 	}
121 
122 	Transaction()
123 		:
124 		fJournal(NULL),
125 		fParent(NULL)
126 	{
127 	}
128 
129 	~Transaction()
130 	{
131 		if (fJournal != NULL)
132 			fJournal->Unlock(this, false);
133 	}
134 
135 	status_t Start(Volume* volume, off_t refBlock);
136 	bool IsStarted() const { return fJournal != NULL; }
137 
138 	status_t Done()
139 	{
140 		status_t status = B_OK;
141 		if (fJournal != NULL) {
142 			status = fJournal->Unlock(this, true);
143 			if (status == B_OK)
144 				fJournal = NULL;
145 		}
146 		return status;
147 	}
148 
149 	bool HasParent() const
150 	{
151 		return fParent != NULL;
152 	}
153 
154 	bool IsTooLarge() const
155 	{
156 		return fJournal->CurrentTransactionTooLarge();
157 	}
158 
159 	status_t WriteBlocks(off_t blockNumber, const uint8* buffer,
160 		size_t numBlocks = 1)
161 	{
162 		if (fJournal == NULL)
163 			return B_NO_INIT;
164 
165 		void* cache = GetVolume()->BlockCache();
166 		size_t blockSize = GetVolume()->BlockSize();
167 
168 		for (size_t i = 0; i < numBlocks; i++) {
169 			void* block = block_cache_get_empty(cache, blockNumber + i,
170 				ID());
171 			if (block == NULL)
172 				return B_ERROR;
173 
174 			memcpy(block, buffer, blockSize);
175 			buffer += blockSize;
176 
177 			block_cache_put(cache, blockNumber + i);
178 		}
179 
180 		return B_OK;
181 	}
182 
183 	Volume* GetVolume() const
184 		{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
185 	int32 ID() const
186 		{ return fJournal->TransactionID(); }
187 
188 	void AddListener(TransactionListener* listener);
189 	void RemoveListener(TransactionListener* listener);
190 
191 	void NotifyListeners(bool success);
192 	void MoveListenersTo(Transaction* transaction);
193 
194 	void SetParent(Transaction* parent)
195 		{ fParent = parent; }
196 	Transaction* Parent() const
197 		{ return fParent; }
198 
199 private:
200 	Transaction(const Transaction& other);
201 	Transaction& operator=(const Transaction& other);
202 		// no implementation
203 
204 	Journal*				fJournal;
205 	TransactionListeners	fListeners;
206 	Transaction*			fParent;
207 };
208 
209 
210 #ifdef BFS_DEBUGGER_COMMANDS
211 int dump_journal(int argc, char** argv);
212 #endif
213 
214 
215 #endif	// JOURNAL_H
216