xref: /haiku/src/add-ons/kernel/file_systems/packagefs/indices/SizeIndex.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "SizeIndex.h"
8 
9 #include <new>
10 
11 #include <TypeConstants.h>
12 
13 #include <util/SinglyLinkedList.h>
14 
15 #include "DebugSupport.h"
16 #include "IndexImpl.h"
17 #include "Node.h"
18 #include "TwoKeyAVLTree.h"
19 #include "Volume.h"
20 
21 
22 // #pragma mark - SizeIndexPrimaryKey
23 
24 
25 class SizeIndexPrimaryKey {
26 public:
27 	SizeIndexPrimaryKey(Node* node, off_t size)
28 		:
29 		node(node),
30 		size(size)
31 	{
32 	}
33 
34 	SizeIndexPrimaryKey(Node* node)
35 		:
36 		node(node),
37 		size(node->FileSize())
38 	{
39 	}
40 
41 	SizeIndexPrimaryKey(off_t size)
42 		:
43 		node(NULL),
44 		size(size)
45 	{
46 	}
47 
48 	Node*	node;
49 	off_t	size;
50 };
51 
52 
53 // #pragma mark - SizeIndexGetPrimaryKey
54 
55 
56 class SizeIndexGetPrimaryKey {
57 public:
58 	inline SizeIndexPrimaryKey operator()(Node* a)
59 	{
60 		return SizeIndexPrimaryKey(a);
61 	}
62 
63 	inline SizeIndexPrimaryKey operator()(Node* a) const
64 	{
65 		return SizeIndexPrimaryKey(a);
66 	}
67 };
68 
69 
70 // #pragma mark - SizeIndexPrimaryKeyCompare
71 
72 
73 class SizeIndexPrimaryKeyCompare {
74 public:
75 	inline int operator()(const SizeIndexPrimaryKey &a,
76 		const SizeIndexPrimaryKey &b) const
77 	{
78 		if (a.node != NULL && a.node == b.node)
79 			return 0;
80 		if (a.size < b.size)
81 			return -1;
82 		if (a.size > b.size)
83 			return 1;
84 		return 0;
85 	}
86 };
87 
88 
89 // #pragma mark - NodeTree
90 
91 
92 typedef TwoKeyAVLTree<Node*, SizeIndexPrimaryKey, SizeIndexPrimaryKeyCompare,
93 	SizeIndexGetPrimaryKey> _NodeTree;
94 class SizeIndex::NodeTree : public _NodeTree {};
95 
96 
97 // #pragma mark - IteratorList
98 
99 
100 class SizeIndex::IteratorList : public SinglyLinkedList<Iterator> {};
101 
102 
103 // #pragma mark - Iterator
104 
105 
106 struct SizeIndex::IteratorPolicy {
107 	typedef SizeIndex										Index;
108 	typedef off_t											Value;
109 	typedef SizeIndex::NodeTree								NodeTree;
110 	typedef GenericIndexIteratorTreePolicy<IteratorPolicy>	TreePolicy;
111 
112 	static NodeTree* GetNodeTree(Index* index)
113 	{
114 		return index->fNodes;
115 	}
116 
117 	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
118 	{
119 		*(off_t*)buffer = node->FileSize();
120 		*_keyLength = sizeof(off_t);
121 	}
122 };
123 
124 
125 class SizeIndex::Iterator : public GenericIndexIterator<IteratorPolicy>,
126 	public SinglyLinkedListLinkImpl<Iterator> {
127 public:
128 	virtual	void				NodeChanged(Node* node, uint32 statFields,
129 									const OldNodeAttributes& oldAttributes);
130 };
131 
132 
133 // #pragma mark - SizeIndex
134 
135 
136 SizeIndex::SizeIndex()
137 	:
138 	Index(),
139 	fNodes(NULL),
140 	fIteratorsToUpdate(NULL)
141 {
142 }
143 
144 
145 SizeIndex::~SizeIndex()
146 {
147 	if (IsListening())
148 		fVolume->RemoveNodeListener(this);
149 
150 	ASSERT(fIteratorsToUpdate->IsEmpty());
151 
152 	delete fIteratorsToUpdate;
153 	delete fNodes;
154 }
155 
156 
157 status_t
158 SizeIndex::Init(Volume* volume)
159 {
160 	status_t error = Index::Init(volume, "size", B_INT64_TYPE, true,
161 		sizeof(off_t));
162 	if (error != B_OK)
163 		return error;
164 
165 	fVolume->AddNodeListener(this, NULL);
166 
167 	fNodes = new(std::nothrow) NodeTree;
168 	fIteratorsToUpdate = new(std::nothrow) IteratorList;
169 	if (fNodes == NULL || fIteratorsToUpdate == NULL)
170 		return B_NO_MEMORY;
171 
172 	return B_OK;
173 }
174 
175 
176 int32
177 SizeIndex::CountEntries() const
178 {
179 	return fNodes->CountItems();
180 }
181 
182 
183 void
184 SizeIndex::NodeAdded(Node* node)
185 {
186 	fNodes->Insert(node);
187 }
188 
189 
190 void
191 SizeIndex::NodeRemoved(Node* node)
192 {
193 	fNodes->Remove(node, node);
194 }
195 
196 
197 void
198 SizeIndex::NodeChanged(Node* node, uint32 statFields,
199 	const OldNodeAttributes& oldAttributes)
200 {
201 	IteratorList iterators;
202 	iterators.MoveFrom(fIteratorsToUpdate);
203 
204 	off_t oldSize = oldAttributes.FileSize();
205 	off_t newSize = node->FileSize();
206 	if (newSize == oldSize)
207 		return;
208 
209 	NodeTree::Iterator nodeIterator;
210 	Node** foundNode = fNodes->Find(SizeIndexPrimaryKey(node, oldSize), node,
211 		&nodeIterator);
212 
213 	if (foundNode == NULL || *foundNode != node)
214 		return;
215 
216 	// move the iterators that point to the node to the previous node
217 	for (IteratorList::ConstIterator it = iterators.GetIterator();
218 			Iterator* iterator = it.Next();) {
219 		iterator->NodeChangeBegin(node);
220 	}
221 
222 	// remove and re-insert the node
223 	nodeIterator.Remove();
224 	if (fNodes->Insert(node) != B_OK) {
225 		fIteratorsToUpdate->MakeEmpty();
226 		return;
227 	}
228 
229 	// Move the iterators to the next node again. If the node hasn't changed
230 	// its place, they will point to it again, otherwise to the node originally
231 	// succeeding it.
232 	for (IteratorList::ConstIterator it = iterators.GetIterator();
233 			Iterator* iterator = it.Next();) {
234 		iterator->NodeChangeEnd(node);
235 	}
236 
237 	// update live queries
238 	fVolume->UpdateLiveQueries(node, Name(), Type(),
239 		(const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize,
240 		sizeof(newSize));
241 }
242 
243 
244 AbstractIndexIterator*
245 SizeIndex::InternalGetIterator()
246 {
247 	Iterator* iterator = new(std::nothrow) Iterator;
248 	if (iterator != NULL) {
249 		if (!iterator->SetTo(this, 0, true)) {
250 			delete iterator;
251 			iterator = NULL;
252 		}
253 	}
254 	return iterator;
255 }
256 
257 
258 AbstractIndexIterator*
259 SizeIndex::InternalFind(const void* key, size_t length)
260 {
261 	if (length != sizeof(off_t))
262 		return NULL;
263 	Iterator* iterator = new(std::nothrow) Iterator;
264 	if (iterator != NULL) {
265 		if (!iterator->SetTo(this, *(const off_t*)key)) {
266 			delete iterator;
267 			iterator = NULL;
268 		}
269 	}
270 	return iterator;
271 }
272 
273 
274 void
275 SizeIndex::_AddIteratorToUpdate(Iterator* iterator)
276 {
277 	fIteratorsToUpdate->Add(iterator);
278 }
279 
280 
281 // #pragma mark - Iterator
282 
283 
284 void
285 SizeIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
286 	const OldNodeAttributes& oldAttributes)
287 {
288 	fIndex->_AddIteratorToUpdate(this);
289 }
290