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