xref: /haiku/src/add-ons/kernel/file_systems/bfs/Journal.h (revision 3be9edf8da228afd9fec0390f408c964766122aa)
1 /*
2  * Copyright 2001-2009, 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 
64 			Volume*			fVolume;
65 			recursive_lock	fLock;
66 			Transaction*	fOwner;
67 			uint32			fLogSize;
68 			uint32			fMaxTransactionSize;
69 			uint32			fUsed;
70 			int32			fUnwrittenTransactions;
71 			mutex			fEntriesLock;
72 			LogEntryList	fEntries;
73 			bigtime_t		fTimestamp;
74 			int32			fTransactionID;
75 			bool			fHasSubtransaction;
76 			bool			fSeparateSubTransactions;
77 };
78 
79 
80 inline uint32
81 Journal::FreeLogBlocks() const
82 {
83 	return fVolume->LogStart() <= fVolume->LogEnd()
84 		? fLogSize - fVolume->LogEnd() + fVolume->LogStart()
85 		: fVolume->LogStart() - fVolume->LogEnd();
86 }
87 
88 
89 class Transaction {
90 public:
91 	Transaction(Volume* volume, off_t refBlock)
92 		:
93 		fJournal(NULL),
94 		fParent(NULL)
95 	{
96 		Start(volume, refBlock);
97 	}
98 
99 	Transaction(Volume* volume, block_run refRun)
100 		:
101 		fJournal(NULL),
102 		fParent(NULL)
103 	{
104 		Start(volume, volume->ToBlock(refRun));
105 	}
106 
107 	Transaction()
108 		:
109 		fJournal(NULL),
110 		fParent(NULL)
111 	{
112 	}
113 
114 	~Transaction()
115 	{
116 		if (fJournal != NULL)
117 			fJournal->Unlock(this, false);
118 	}
119 
120 	status_t Start(Volume* volume, off_t refBlock);
121 	bool IsStarted() const { return fJournal != NULL; }
122 
123 	status_t Done()
124 	{
125 		status_t status = B_OK;
126 		if (fJournal != NULL) {
127 			status = fJournal->Unlock(this, true);
128 			if (status == B_OK)
129 				fJournal = NULL;
130 		}
131 		return status;
132 	}
133 
134 	bool HasParent() const
135 	{
136 		return fParent != NULL;
137 	}
138 
139 	bool IsTooLarge() const
140 	{
141 		return fJournal->CurrentTransactionTooLarge();
142 	}
143 
144 	status_t WriteBlocks(off_t blockNumber, const uint8* buffer,
145 		size_t numBlocks = 1)
146 	{
147 		if (fJournal == NULL)
148 			return B_NO_INIT;
149 
150 		void* cache = GetVolume()->BlockCache();
151 		size_t blockSize = GetVolume()->BlockSize();
152 
153 		for (size_t i = 0; i < numBlocks; i++) {
154 			void* block = block_cache_get_empty(cache, blockNumber + i,
155 				ID());
156 			if (block == NULL)
157 				return B_ERROR;
158 
159 			memcpy(block, buffer, blockSize);
160 			buffer += blockSize;
161 
162 			block_cache_put(cache, blockNumber + i);
163 		}
164 
165 		return B_OK;
166 	}
167 
168 	void Split()
169 	{
170 		cache_start_sub_transaction(fJournal->GetVolume()->BlockCache(),
171 			fJournal->TransactionID());
172 	}
173 
174 	Volume* GetVolume() const
175 		{ return fJournal != NULL ? fJournal->GetVolume() : NULL; }
176 	int32 ID() const
177 		{ return fJournal->TransactionID(); }
178 
179 	void AddInode(Inode* inode);
180 	void RemoveInode(Inode* inode);
181 
182 	void UnlockInodes(bool success);
183 	void MoveInodesTo(Transaction* transaction);
184 
185 	void SetParent(Transaction* parent)
186 		{ fParent = parent; }
187 	Transaction* Parent() const
188 		{ return fParent; }
189 
190 private:
191 	Transaction(const Transaction& other);
192 	Transaction& operator=(const Transaction& other);
193 		// no implementation
194 
195 	Journal*		fJournal;
196 	InodeList		fLockedInodes;
197 	Transaction*	fParent;
198 };
199 
200 #ifdef BFS_DEBUGGER_COMMANDS
201 int dump_journal(int argc, char** argv);
202 #endif
203 
204 #endif	// JOURNAL_H
205