xref: /haiku/src/add-ons/kernel/file_systems/bfs/Query.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4  * Copyright 2024, Haiku, Inc. All rights reserved.
5  * Distributed under the terms of the MIT License.
6  */
7 
8 #include "Query.h"
9 
10 #include "BPlusTree.h"
11 #include "bfs.h"
12 #include "Debug.h"
13 #include "Index.h"
14 #include "Inode.h"
15 #include "Volume.h"
16 
17 #include <query_private.h>
18 #include <file_systems/QueryParser.h>
19 
20 
21 // #pragma mark - QueryPolicy
22 
23 
24 struct Query::QueryPolicy {
25 	typedef Query Context;
26 	typedef ::Inode Entry;
27 	typedef ::Inode Node;
28 
29 	struct Index : ::Index {
30 		Index(Context* context)
31 			:
32 			::Index(context->fVolume)
33 		{
34 		}
35 	};
36 
37 	struct IndexIterator : TreeIterator {
38 		off_t offset;
39 
40 		IndexIterator(BPlusTree* tree)
41 			:
42 			TreeIterator(tree)
43 		{
44 		}
45 	};
46 
47 	struct NodeHolder {
48 		Vnode vnode;
49 		NodeGetter nodeGetter;
50 		RecursiveLocker smallDataLocker;
51 	};
52 
53 	static const int32 kMaxFileNameLength = INODE_FILE_NAME_LENGTH;
54 
55 	// Entry interface
56 
57 	static ino_t EntryGetParentID(Inode* inode)
58 	{
59 		return inode->ParentID();
60 	}
61 
62 	static Node* EntryGetNode(Entry* entry)
63 	{
64 		return entry;
65 	}
66 
67 	static ino_t EntryGetNodeID(Entry* entry)
68 	{
69 		return entry->ID();
70 	}
71 
72 	static ssize_t EntryGetName(Inode* inode, void* buffer, size_t bufferSize)
73 	{
74 		RecursiveLocker locker(&inode->SmallDataLock());
75 		status_t status = inode->GetName((char*)buffer, bufferSize);
76 		if (status != B_OK)
77 			return status;
78 		return strlen((const char*)buffer) + 1;
79 	}
80 
81 	static const char* EntryGetNameNoCopy(NodeHolder& holder, Inode* inode)
82 	{
83 		// we need to lock before accessing Inode::Name()
84 		status_t status = holder.nodeGetter.SetTo(inode);
85 		if (status != B_OK)
86 			return NULL;
87 
88 		holder.smallDataLocker.SetTo(inode->SmallDataLock(), false);
89 		uint8* buffer = (uint8*)inode->Name(holder.nodeGetter.Node());
90 		if (buffer == NULL) {
91 			holder.smallDataLocker.Unlock();
92 			return NULL;
93 		}
94 
95 		return (const char*)buffer;
96 	}
97 
98 	// Index interface
99 
100 	static status_t IndexSetTo(Index& index, const char* attribute)
101 	{
102 		return index.SetTo(attribute);
103 	}
104 
105 	static void IndexUnset(Index& index)
106 	{
107 		index.Unset();
108 	}
109 
110 	static int32 IndexGetWeightedScore(Index& index, int32 score)
111 	{
112 		// take index size into account (1024 is the current node size
113 		// in our B+trees)
114 		// 2048 * 2048 == 4194304 is the maximum score (for an empty
115 		// tree, since the header + 1 node are already 2048 bytes)
116 		return score * ((2048 * 1024LL) / index.Node()->Size());
117 	}
118 
119 	static type_code IndexGetType(Index& index)
120 	{
121 		return index.Type();
122 	}
123 
124 	static int32 IndexGetKeySize(Index& index)
125 	{
126 		return index.KeySize();
127 	}
128 
129 	static IndexIterator* IndexCreateIterator(Index& index)
130 	{
131 		IndexIterator* iterator = new(std::nothrow) IndexIterator(index.Node()->Tree());
132 		if (iterator == NULL)
133 			return NULL;
134 
135 		return iterator;
136 	}
137 
138 	// IndexIterator interface
139 
140 	static void IndexIteratorDelete(IndexIterator* iterator)
141 	{
142 		delete iterator;
143 	}
144 
145 	static status_t IndexIteratorFind(IndexIterator* iterator,
146 		const void* value, size_t size)
147 	{
148 		return iterator->Find((const uint8*)value, size);
149 	}
150 
151 	static status_t IndexIteratorFetchNextEntry(IndexIterator* iterator,
152 		void* indexValue, size_t* _keyLength, size_t bufferSize, size_t* _duplicate)
153 	{
154 		uint16 keyLength;
155 		uint16 duplicate;
156 		status_t status = iterator->GetNextEntry((uint8*)indexValue, &keyLength,
157 			bufferSize, &iterator->offset, &duplicate);
158 		if (status != B_OK)
159 			return status;
160 
161 		*_keyLength = keyLength;
162 		*_duplicate = duplicate;
163 		return B_OK;
164 	}
165 
166 	static status_t IndexIteratorGetEntry(Context* context, IndexIterator* iterator,
167 		NodeHolder& holder, Inode** _entry)
168 	{
169 		holder.vnode.SetTo(context->fVolume, iterator->offset);
170 		Inode* inode;
171 		status_t status = holder.vnode.Get(&inode);
172 		if (status != B_OK) {
173 			REPORT_ERROR(status);
174 			FATAL(("could not get inode %" B_PRIdOFF " in index!\n", iterator->offset));
175 			return status;
176 		}
177 
178 		*_entry = inode;
179 		return B_OK;
180 	}
181 
182 	static void IndexIteratorSkipDuplicates(IndexIterator* iterator)
183 	{
184 		iterator->SkipDuplicates();
185 	}
186 
187 	static void IndexIteratorSuspend(IndexIterator* indexIterator)
188 	{
189 		// Nothing to do.
190 	}
191 
192 	static void IndexIteratorResume(IndexIterator* indexIterator)
193 	{
194 		// Nothing to do.
195 	}
196 
197 	// Node interface
198 
199 	static const off_t NodeGetSize(Inode* inode)
200 	{
201 		return inode->Size();
202 	}
203 
204 	static time_t NodeGetLastModifiedTime(Inode* inode)
205 	{
206 		return inode->Node().LastModifiedTime();
207 	}
208 
209 	static status_t NodeGetAttribute(NodeHolder& holder, Inode* inode,
210 		const char* attributeName, uint8*& buffer, size_t* size, int32* type)
211 	{
212 		status_t status = holder.nodeGetter.SetTo(inode);
213 		if (status != B_OK)
214 			return status;
215 
216 		Inode* attribute;
217 
218 		holder.smallDataLocker.SetTo(inode->SmallDataLock(), false);
219 		small_data* smallData = inode->FindSmallData(holder.nodeGetter.Node(),
220 			attributeName);
221 		if (smallData != NULL) {
222 			buffer = smallData->Data();
223 			*type = smallData->type;
224 			*size = smallData->data_size;
225 		} else {
226 			// needed to unlock the small_data section as fast as possible
227 			holder.smallDataLocker.Unlock();
228 			holder.nodeGetter.Unset();
229 
230 			if (inode->GetAttribute(attributeName, &attribute) == B_OK) {
231 				*type = attribute->Type();
232 				if (*size > (size_t)attribute->Size())
233 					*size = attribute->Size();
234 
235 				if (*size > MAX_INDEX_KEY_LENGTH)
236 					*size = MAX_INDEX_KEY_LENGTH;
237 
238 				if (attribute->ReadAt(0, (uint8*)buffer, size) < B_OK) {
239 					inode->ReleaseAttribute(attribute);
240 					return B_IO_ERROR;
241 				}
242 				inode->ReleaseAttribute(attribute);
243 			} else
244 				return B_ENTRY_NOT_FOUND;
245 		}
246 		return B_OK;
247 	}
248 
249 	static Entry* NodeGetFirstReferrer(Node* node)
250 	{
251 		return node;
252 	}
253 
254 	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
255 	{
256 		return NULL;
257 	}
258 
259 	// Volume interface
260 
261 	static dev_t ContextGetVolumeID(Context* context)
262 	{
263 		return context->fVolume->ID();
264 	}
265 };
266 
267 
268 // #pragma mark - Query
269 
270 
271 Query::Query(Volume* volume)
272 	:
273 	fVolume(volume),
274 	fImpl(NULL)
275 {
276 }
277 
278 
279 Query::~Query()
280 {
281 	if (fImpl != NULL) {
282 		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
283 			fVolume->RemoveQuery(this);
284 
285 		delete fImpl;
286 	}
287 }
288 
289 
290 /*static*/ status_t
291 Query::Create(Volume* volume, const char* queryString, uint32 flags,
292 	port_id port, uint32 token, Query*& _query)
293 {
294 	Query* query = new(std::nothrow) Query(volume);
295 	if (query == NULL)
296 		return B_NO_MEMORY;
297 
298 	status_t error = query->_Init(queryString, flags, port, token);
299 	if (error != B_OK) {
300 		delete query;
301 		return error;
302 	}
303 
304 	_query = query;
305 	return B_OK;
306 }
307 
308 
309 status_t
310 Query::Rewind()
311 {
312 	return fImpl->Rewind();
313 }
314 
315 
316 status_t
317 Query::GetNextEntry(struct dirent* entry, size_t size)
318 {
319 	return fImpl->GetNextEntry(entry, size);
320 }
321 
322 
323 void
324 Query::LiveUpdate(Inode* inode, const char* attribute, int32 type,
325 	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
326 {
327 	fImpl->LiveUpdate(inode, inode, attribute, type,
328 		(const uint8*)oldKey, oldLength,
329 		(const uint8*)newKey, newLength);
330 }
331 
332 
333 void
334 Query::LiveUpdateRenameMove(Inode* inode,
335 	ino_t oldDirectoryID, const char* oldName, size_t oldLength,
336 	ino_t newDirectoryID, const char* newName, size_t newLength)
337 {
338 	fImpl->LiveUpdateRenameMove(inode, inode,
339 		oldDirectoryID, oldName, oldLength,
340 		newDirectoryID, newName, newLength);
341 }
342 
343 
344 status_t
345 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
346 {
347 	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
348 		fImpl);
349 	if (error != B_OK)
350 		return error;
351 
352 	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
353 		fVolume->AddQuery(this);
354 
355 	return B_OK;
356 }
357