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
23HashRevokeManager::HashRevokeManager()
24	:
25	fHash(NULL),
26	kInitialHashSize(128)
27		// TODO: Benchmark and find an optimal value
28{
29}
30
31
32HashRevokeManager::~HashRevokeManager()
33{
34	if (fHash != NULL) {
35		if (fRevokeCount != 0) {
36			RevokeElement *element =
37				(RevokeElement*)hash_remove_first(fHash, NULL);
38
39			while (element != NULL) {
40				delete element;
41				element = (RevokeElement*)hash_remove_first(fHash, NULL);
42			}
43		}
44
45		hash_uninit(fHash);
46	}
47}
48
49
50status_t
51HashRevokeManager::Init()
52{
53	RevokeElement dummyElement;
54
55	fHash = hash_init(kInitialHashSize, offset_of_member(dummyElement, next),
56		&HashRevokeManager::Compare,
57		&HashRevokeManager::Hash);
58
59	if (fHash == NULL)
60		return B_NO_MEMORY;
61
62	return B_OK;
63}
64
65
66status_t
67HashRevokeManager::Insert(uint32 block, uint32 commitID)
68{
69	RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
70
71	if (element != NULL) {
72		TRACE("HashRevokeManager::Insert(): Already has an element\n");
73		if (element->commitID < commitID) {
74			TRACE("HashRevokeManager::Insert(): Deleting previous element\n");
75			status_t retValue = hash_remove(fHash, element);
76
77			if (retValue != B_OK)
78				return retValue;
79
80			delete element;
81		}
82		else {
83			return B_OK;
84				// We already have a newer version of the block
85		}
86	}
87
88	return _ForceInsert(block, commitID);
89}
90
91
92status_t
93HashRevokeManager::Remove(uint32 block)
94{
95	RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
96
97	if (element == NULL)
98		return B_ERROR; // TODO: Perhaps we should just ignore?
99
100	status_t retValue = hash_remove(fHash, element);
101
102	if (retValue == B_OK)
103		delete element;
104
105	return retValue;
106}
107
108
109bool
110HashRevokeManager::Lookup(uint32 block, uint32 commitID)
111{
112	RevokeElement* element = (RevokeElement*)hash_lookup(fHash, &block);
113
114	if (element == NULL)
115		return false;
116
117	return element->commitID >= commitID;
118}
119
120
121/*static*/ int
122HashRevokeManager::Compare(void* _revoked, const void *_block)
123{
124	RevokeElement* revoked = (RevokeElement*)_revoked;
125	uint32 block = *(uint32*)_block;
126
127	if (revoked->block == block)
128		return 0;
129
130	return (revoked->block > block) ? 1 : -1;
131}
132
133
134/*static*/ uint32
135HashRevokeManager::Hash(void* _revoked, const void* _block, uint32 range)
136{
137	TRACE("HashRevokeManager::Hash(): revoked: %p, block: %p, range: %lu\n",
138		_revoked, _block, range);
139	RevokeElement* revoked = (RevokeElement*)_revoked;
140
141	if (revoked != NULL)
142		return revoked->block % range;
143
144	uint32 block = *(uint32*)_block;
145	return block % range;
146}
147
148
149status_t
150HashRevokeManager::_ForceInsert(uint32 block, uint32 commitID)
151{
152	RevokeElement* element = new(std::nothrow) RevokeElement;
153
154	if (element == NULL)
155		return B_NO_MEMORY;
156
157	element->block = block;
158	element->commitID = commitID;
159
160	status_t retValue = hash_insert_grow(fHash, element);
161
162	if (retValue == B_OK) {
163		fRevokeCount++;
164		TRACE("HashRevokeManager::_ForceInsert(): revoke count: %lu\n",
165			fRevokeCount);
166	}
167
168	return retValue;
169}
170
171