xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
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 	private:
54 		bool _HasSubTransaction() { return fHasSubtransaction; }
55 		uint32 _TransactionSize() const;
56 		status_t _WriteTransactionToLog();
57 		status_t _CheckRunArray(const run_array *array);
58 		status_t _ReplayRunArray(int32 *start);
59 		status_t _TransactionDone(bool success);
60 		static void _TransactionNotify(int32 transactionID, int32 event,
61 			void *_logEntry);
62 
63 		Volume			*fVolume;
64 		RecursiveLock	fLock;
65 		Transaction 	*fOwner;
66 		uint32			fLogSize, fMaxTransactionSize, fUsed;
67 		int32			fUnwrittenTransactions;
68 		SimpleLock		fEntriesLock;
69 		LogEntryList	fEntries;
70 		bigtime_t		fTimestamp;
71 		int32			fTransactionID;
72 		bool			fHasSubtransaction;
73 };
74 
75 
76 inline uint32
77 Journal::FreeLogBlocks() const
78 {
79 	return fVolume->LogStart() <= fVolume->LogEnd()
80 		? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
81 		: fVolume->LogStart() - fVolume->LogEnd();
82 }
83 
84 
85 // For now, that's only a dumb class that does more or less nothing
86 // else than writing the blocks directly to the real location.
87 // It doesn't yet use logging.
88 
89 class Transaction {
90 	public:
91 		Transaction(Volume *volume, off_t refBlock)
92 			:
93 			fJournal(NULL)
94 		{
95 			Start(volume, refBlock);
96 		}
97 
98 		Transaction(Volume *volume, block_run refRun)
99 			:
100 			fJournal(NULL)
101 		{
102 			Start(volume, volume->ToBlock(refRun));
103 		}
104 
105 		Transaction()
106 			:
107 			fJournal(NULL)
108 		{
109 		}
110 
111 		~Transaction()
112 		{
113 			if (fJournal)
114 				fJournal->Unlock(this, false);
115 		}
116 
117 		status_t Start(Volume *volume, off_t refBlock);
118 		bool IsStarted() const { return fJournal != NULL; }
119 
120 		void
121 		Done()
122 		{
123 			if (fJournal != NULL)
124 				fJournal->Unlock(this, true);
125 			fJournal = NULL;
126 		}
127 
128 		bool
129 		HasParent()
130 		{
131 			if (fJournal != NULL)
132 				return fJournal->CurrentTransaction() == this;
133 
134 			return false;
135 		}
136 
137 		status_t
138 		WriteBlocks(off_t blockNumber, const uint8 *buffer,
139 			size_t numBlocks = 1)
140 		{
141 			if (fJournal == NULL)
142 				return B_NO_INIT;
143 
144 			void *cache = GetVolume()->BlockCache();
145 			size_t blockSize = GetVolume()->BlockSize();
146 
147 			for (size_t i = 0; i < numBlocks; i++) {
148 				void *block = block_cache_get_empty(cache, blockNumber + i,
149 					ID());
150 				if (block == NULL)
151 					return B_ERROR;
152 
153 				memcpy(block, buffer, blockSize);
154 				buffer += blockSize;
155 
156 				block_cache_put(cache, blockNumber + i);
157 			}
158 
159 			return B_OK;
160 		}
161 
162 		Volume	*GetVolume()
163 			{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
164 		int32 ID() const
165 			{ return fJournal->TransactionID(); }
166 
167 	private:
168 		Transaction(const Transaction &);
169 		Transaction &operator=(const Transaction &);
170 			// no implementation
171 
172 		Journal	*fJournal;
173 };
174 
175 #endif	/* JOURNAL_H */
176