xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /* Journal - transaction and logging
2  *
3  * Copyright 2001-2005, Axel Dörfler, axeld@pinc-software.de.
4  * This file may be used under the terms of the MIT License.
5  */
6 #ifndef JOURNAL_H
7 #define JOURNAL_H
8 
9 
10 #include <KernelExport.h>
11 #include <util/DoublyLinkedList.h>
12 
13 #ifdef USER
14 #	include "myfs.h"
15 #	include <stdio.h>
16 #endif
17 
18 #ifndef _IMPEXP_KERNEL
19 #	define _IMPEXP_KERNEL
20 #endif
21 
22 #include "Volume.h"
23 #include "Chain.h"
24 #include "Utility.h"
25 
26 
27 struct run_array;
28 class LogEntry;
29 typedef DoublyLinkedList<LogEntry> LogEntryList;
30 
31 
32 // Locking policy in BFS: if you need both, the volume lock and the
33 //	journal lock, you must lock the volume first - or else you will
34 //	end up in a deadlock.
35 //	That is, if you start a transaction, and will need to lock the
36 //	volume while the transaction is in progress (for the unsafe
37 //	get_vnode() call, for example), you must lock the volume before
38 //	starting the transaction.
39 
40 class Journal {
41 	public:
42 		Journal(Volume *);
43 		~Journal();
44 
45 		status_t InitCheck();
46 
47 		status_t Lock(Transaction *owner);
48 		void Unlock(Transaction *owner, bool success);
49 
50 		status_t ReplayLog();
51 
52 		status_t LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks);
53 
54 		Transaction *CurrentTransaction() const { return fOwner; }
55 
56 		status_t FlushLogAndBlocks();
57 		Volume *GetVolume() const { return fVolume; }
58 		int32 TransactionID() const { return fTransactionID; }
59 
60 		inline uint32 FreeLogBlocks() const;
61 
62 	private:
63 		bool _HasSubTransaction() { return fHasSubtransaction; }
64 		uint32 _TransactionSize() const;
65 		status_t _WriteTransactionToLog();
66 		status_t _CheckRunArray(const run_array *array);
67 		status_t _ReplayRunArray(int32 *start);
68 		status_t _TransactionDone(bool success);
69 		static void _blockNotify(int32 transactionID, void *arg);
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 Done()
129 		{
130 			if (fJournal != NULL)
131 				fJournal->Unlock(this, true);
132 			fJournal = NULL;
133 		}
134 
135 		bool HasParent()
136 		{
137 			if (fJournal != NULL)
138 				return fJournal->CurrentTransaction() == this;
139 
140 			return false;
141 		}
142 
143 		status_t WriteBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks = 1)
144 		{
145 			if (fJournal == NULL)
146 				return B_NO_INIT;
147 
148 			// ToDo: implement this properly!
149 			// Currently only used in BlockAllocator::StopChecking(),
150 			// so chkbfs won't work correctly
151 #if 0
152 			return fJournal->LogBlocks(blockNumber, buffer, numBlocks);
153 #endif
154 			return B_ERROR;
155 		}
156 
157 		Volume	*GetVolume() { return fJournal != NULL ? fJournal->GetVolume() : NULL; }
158 		int32 ID() const { return fJournal->TransactionID(); }
159 
160 	private:
161 		Transaction(const Transaction &);
162 		Transaction &operator=(const Transaction &);
163 			// no implementation
164 
165 		Journal	*fJournal;
166 };
167 
168 #endif	/* JOURNAL_H */
169