1/*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef TRANSACTION_H
6#define TRANSACTION_H
7
8
9#include <fs_cache.h>
10
11#include <util/DoublyLinkedList.h>
12#include <util/OpenHashTable.h>
13
14#include "CheckSum.h"
15#include "driver/checksum_device.h"
16#include "Node.h"
17
18
19class PostCommitNotification;
20class Volume;
21
22
23enum {
24	TRANSACTION_DELETE_NODE				= 0x01,
25	TRANSACTION_NODE_ALREADY_LOCKED		= 0x02,
26	TRANSACTION_KEEP_NODE_LOCKED		= 0x04,
27	TRANSACTION_REMOVE_NODE_ON_ERROR	= 0x08,
28	TRANSACTION_UNREMOVE_NODE_ON_ERROR	= 0x10
29};
30
31
32class Transaction {
33public:
34	explicit					Transaction(Volume* volume);
35								~Transaction();
36
37			int32				ID() const	{ return fID; }
38
39			status_t			Start();
40			status_t			StartAndAddNode(Node* node, uint32 flags = 0);
41			status_t			Commit(
42									const PostCommitNotification* notification1
43										= NULL,
44									const PostCommitNotification* notification2
45										= NULL,
46									const PostCommitNotification* notification3
47										= NULL);
48	inline	status_t			Commit(
49									const PostCommitNotification& notification);
50			void				Abort();
51
52	inline	bool				IsActive() const	{ return fID >= 0; }
53
54			status_t			AddNode(Node* node, uint32 flags = 0);
55			status_t			AddNodes(Node* node1, Node* node2,
56									Node* node3 = NULL);
57			bool				RemoveNode(Node* node);
58			void				UpdateNodeFlags(Node* node, uint32 flags);
59
60			void				KeepNode(Node* node);
61
62			bool				IsNodeLocked(Node* node) const
63									{ return _GetNodeInfo(node) != NULL; }
64
65			status_t			RegisterBlock(uint64 blockIndex);
66			void				PutBlock(uint64 blockIndex, const void* data);
67
68private:
69			struct NodeInfo : DoublyLinkedListLinkImpl<NodeInfo> {
70				Node*			node;
71				checksumfs_node	oldNodeData;
72				uint32			flags;
73			};
74
75			typedef DoublyLinkedList<NodeInfo> NodeInfoList;
76
77			struct BlockInfo {
78				checksum_device_ioctl_check_sum	indexAndCheckSum;
79				BlockInfo*						hashNext;
80				const void*						data;
81				int32							refCount;
82				bool							dirty;
83			};
84
85			struct BlockInfoHashDefinition {
86				typedef uint64		KeyType;
87				typedef	BlockInfo	ValueType;
88
89				size_t HashKey(uint64 key) const
90				{
91					return (size_t)key;
92				}
93
94				size_t Hash(const BlockInfo* value) const
95				{
96					return HashKey(value->indexAndCheckSum.blockIndex);
97				}
98
99				bool Compare(uint64 key, const BlockInfo* value) const
100				{
101					return value->indexAndCheckSum.blockIndex == key;
102				}
103
104				BlockInfo*& GetLink(BlockInfo* value) const
105				{
106					return value->hashNext;
107				}
108			};
109
110			typedef BOpenHashTable<BlockInfoHashDefinition> BlockInfoTable;
111
112private:
113			NodeInfo*			_GetNodeInfo(Node* node) const;
114			void				_DeleteNodeInfosAndUnlock(bool failed);
115			void				_DeleteNodeInfoAndUnlock(NodeInfo* info,
116									bool failed);
117
118			status_t			_UpdateBlockCheckSums();
119			status_t			_RevertBlockCheckSums();
120
121private:
122			Volume*				fVolume;
123			SHA256*				fSHA256;
124			checksum_device_ioctl_check_sum* fCheckSum;
125			int32				fID;
126			NodeInfoList		fNodeInfos;
127			BlockInfoTable		fBlockInfos;
128			uint64				fOldFreeBlockCount;
129};
130
131
132status_t
133Transaction::Commit(const PostCommitNotification& notification)
134{
135	return Commit(&notification);
136}
137
138
139// #pragma mark -
140
141
142class PostCommitNotification {
143public:
144	virtual						~PostCommitNotification();
145
146	virtual	void				NotifyPostCommit() const = 0;
147};
148
149
150#endif	// TRANSACTION_H
151