xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision cfc3fa87da824bdf593eb8b817a83b6376e77935)
1 /*
2  * Copyright 2001-2008, 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 #ifndef _IMPEXP_KERNEL
12 #	define _IMPEXP_KERNEL
13 #endif
14 
15 #include "Volume.h"
16 #include "Chain.h"
17 #include "Utility.h"
18 
19 
20 struct run_array;
21 class LogEntry;
22 typedef DoublyLinkedList<LogEntry> LogEntryList;
23 
24 
25 // Locking policy in BFS: if you need both, the volume lock and the
26 //	journal lock, you must lock the volume first - or else you will
27 //	end up in a deadlock.
28 //	That is, if you start a transaction, and will need to lock the
29 //	volume while the transaction is in progress (for the unsafe
30 //	get_vnode() call, for example), you must lock the volume before
31 //	starting the transaction.
32 
33 class Journal {
34 	public:
35 		Journal(Volume *);
36 		~Journal();
37 
38 		status_t InitCheck();
39 
40 		status_t Lock(Transaction *owner);
41 		void Unlock(Transaction *owner, bool success);
42 
43 		status_t ReplayLog();
44 
45 		Transaction *CurrentTransaction() const { return fOwner; }
46 
47 		status_t FlushLogAndBlocks();
48 		Volume *GetVolume() const { return fVolume; }
49 		int32 TransactionID() const { return fTransactionID; }
50 
51 		inline uint32 FreeLogBlocks() const;
52 
53 #ifdef BFS_DEBUGGER_COMMANDS
54 		void Dump();
55 #endif
56 
57 	private:
58 		bool _HasSubTransaction() { return fHasSubtransaction; }
59 		status_t _FlushLog(bool canWait, bool flushBlocks);
60 		uint32 _TransactionSize() const;
61 		status_t _WriteTransactionToLog();
62 		status_t _CheckRunArray(const run_array *array);
63 		status_t _ReplayRunArray(int32 *start);
64 		status_t _TransactionDone(bool success);
65 
66 		static void _TransactionWritten(int32 transactionID, int32 event,
67 			void *_logEntry);
68 		static void _TransactionIdle(int32 transactionID, int32 event,
69 			void *_journal);
70 
71 		Volume			*fVolume;
72 		RecursiveLock	fLock;
73 		Transaction 	*fOwner;
74 		uint32			fLogSize, fMaxTransactionSize, fUsed;
75 		int32			fUnwrittenTransactions;
76 		SimpleLock		fEntriesLock;
77 		LogEntryList	fEntries;
78 		bigtime_t		fTimestamp;
79 		int32			fTransactionID;
80 		bool			fHasSubtransaction;
81 };
82 
83 
84 inline uint32
85 Journal::FreeLogBlocks() const
86 {
87 	return fVolume->LogStart() <= fVolume->LogEnd()
88 		? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
89 		: fVolume->LogStart() - fVolume->LogEnd();
90 }
91 
92 
93 // For now, that's only a dumb class that does more or less nothing
94 // else than writing the blocks directly to the real location.
95 // It doesn't yet use logging.
96 
97 class Transaction {
98 	public:
99 		Transaction(Volume *volume, off_t refBlock)
100 			:
101 			fJournal(NULL)
102 		{
103 			Start(volume, refBlock);
104 		}
105 
106 		Transaction(Volume *volume, block_run refRun)
107 			:
108 			fJournal(NULL)
109 		{
110 			Start(volume, volume->ToBlock(refRun));
111 		}
112 
113 		Transaction()
114 			:
115 			fJournal(NULL)
116 		{
117 		}
118 
119 		~Transaction()
120 		{
121 			if (fJournal)
122 				fJournal->Unlock(this, false);
123 		}
124 
125 		status_t Start(Volume *volume, off_t refBlock);
126 		bool IsStarted() const { return fJournal != NULL; }
127 
128 		void
129 		Done()
130 		{
131 			if (fJournal != NULL)
132 				fJournal->Unlock(this, true);
133 			fJournal = NULL;
134 		}
135 
136 		bool
137 		HasParent()
138 		{
139 			if (fJournal != NULL)
140 				return fJournal->CurrentTransaction() == this;
141 
142 			return false;
143 		}
144 
145 		status_t
146 		WriteBlocks(off_t blockNumber, const uint8 *buffer,
147 			size_t numBlocks = 1)
148 		{
149 			if (fJournal == NULL)
150 				return B_NO_INIT;
151 
152 			void *cache = GetVolume()->BlockCache();
153 			size_t blockSize = GetVolume()->BlockSize();
154 
155 			for (size_t i = 0; i < numBlocks; i++) {
156 				void *block = block_cache_get_empty(cache, blockNumber + i,
157 					ID());
158 				if (block == NULL)
159 					return B_ERROR;
160 
161 				memcpy(block, buffer, blockSize);
162 				buffer += blockSize;
163 
164 				block_cache_put(cache, blockNumber + i);
165 			}
166 
167 			return B_OK;
168 		}
169 
170 		Volume	*GetVolume()
171 			{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
172 		int32 ID() const
173 			{ return fJournal->TransactionID(); }
174 
175 	private:
176 		Transaction(const Transaction &);
177 		Transaction &operator=(const Transaction &);
178 			// no implementation
179 
180 		Journal	*fJournal;
181 };
182 
183 #ifdef BFS_DEBUGGER_COMMANDS
184 int dump_journal(int argc, char **argv);
185 #endif
186 
187 #endif	/* JOURNAL_H */
188