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