xref: /haiku/src/add-ons/kernel/file_systems/ext2/HashRevokeManager.cpp (revision e95068dfa81542f83a748c6839f8f833e8c71a50)
1 /*
2  * Copyright 2001-2010, Haiku Inc. All rights reserved.
3  * This file may be used under the terms of the MIT License.
4  *
5  * Authors:
6  *		Janito V. Ferreira Filho
7  */
8 
9 
10 #include "HashRevokeManager.h"
11 
12 #include <new>
13 
14 
15 //#define TRACE_EXT2
16 #ifdef TRACE_EXT2
17 #	define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
18 #else
19 #	define TRACE(x...) ;
20 #endif
21 
22 
23 HashRevokeManager::HashRevokeManager()
24 	:
25 	fHash(NULL),
26 	kInitialHashSize(128)
27 		// TODO: Benchmark and find an optimal value
28 {
29 }
30 
31 
32 HashRevokeManager::~HashRevokeManager()
33 {
34 	if (fHash != NULL) {
35 		if (fRevokeCount != 0) {
36 			RevokeElement *element = fHash->Clear(true);
37 
38 			while (element != NULL) {
39 				RevokeElement* next = element->next;
40 				delete element;
41 				element = next;
42 			}
43 		}
44 
45 		delete fHash;
46 	}
47 }
48 
49 
50 status_t
51 HashRevokeManager::Init()
52 {
53 	fHash = new(std::nothrow) RevokeTable();
54 
55 	if (fHash == NULL || fHash->Init(kInitialHashSize) != B_OK)
56 		return B_NO_MEMORY;
57 
58 	return B_OK;
59 }
60 
61 
62 status_t
63 HashRevokeManager::Insert(uint32 block, uint32 commitID)
64 {
65 	RevokeElement* element = fHash->Lookup(block);
66 
67 	if (element != NULL) {
68 		TRACE("HashRevokeManager::Insert(): Already has an element\n");
69 		if (element->commitID < commitID) {
70 			TRACE("HashRevokeManager::Insert(): Deleting previous element\n");
71 			bool retValue = fHash->Remove(element);
72 
73 			if (!retValue)
74 				return B_ERROR;
75 
76 			delete element;
77 		} else {
78 			return B_OK;
79 				// We already have a newer version of the block
80 		}
81 	}
82 
83 	return _ForceInsert(block, commitID);
84 }
85 
86 
87 status_t
88 HashRevokeManager::Remove(uint32 block)
89 {
90 	RevokeElement* element = fHash->Lookup(block);
91 
92 	if (element == NULL)
93 		return B_ERROR; // TODO: Perhaps we should just ignore?
94 
95 	fHash->Remove(element);
96 		// Can't fail as we just did a sucessful Lookup()
97 
98 	delete element;
99 	return B_OK;
100 }
101 
102 
103 bool
104 HashRevokeManager::Lookup(uint32 block, uint32 commitID)
105 {
106 	RevokeElement* element = fHash->Lookup(block);
107 
108 	if (element == NULL)
109 		return false;
110 
111 	return element->commitID >= commitID;
112 }
113 
114 
115 /*static*/ int
116 HashRevokeManager::Compare(void* _revoked, const void *_block)
117 {
118 	RevokeElement* revoked = (RevokeElement*)_revoked;
119 	uint32 block = *(uint32*)_block;
120 
121 	if (revoked->block == block)
122 		return 0;
123 
124 	return (revoked->block > block) ? 1 : -1;
125 }
126 
127 
128 /*static*/ uint32
129 HashRevokeManager::Hash(void* _revoked, const void* _block, uint32 range)
130 {
131 	TRACE("HashRevokeManager::Hash(): revoked: %p, block: %p, range: %"
132 		B_PRIu32 "\n", _revoked, _block, range);
133 	RevokeElement* revoked = (RevokeElement*)_revoked;
134 
135 	if (revoked != NULL)
136 		return revoked->block % range;
137 
138 	uint32 block = *(uint32*)_block;
139 	return block % range;
140 }
141 
142 
143 status_t
144 HashRevokeManager::_ForceInsert(uint32 block, uint32 commitID)
145 {
146 	RevokeElement* element = new(std::nothrow) RevokeElement;
147 
148 	if (element == NULL)
149 		return B_NO_MEMORY;
150 
151 	element->block = block;
152 	element->commitID = commitID;
153 
154 	status_t retValue = fHash->Insert(element);
155 
156 	if (retValue == B_OK) {
157 		fRevokeCount++;
158 		TRACE("HashRevokeManager::_ForceInsert(): revoke count: %" B_PRIu32
159 			"\n", fRevokeCount);
160 	}
161 
162 	return retValue;
163 }
164 
165