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