xref: /haiku/src/add-ons/kernel/file_systems/packagefs/indices/Query.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Query.h"
8 
9 #include <file_systems/QueryParser.h>
10 
11 #include "AttributeCookie.h"
12 #include "Directory.h"
13 #include "Index.h"
14 #include "Node.h"
15 #include "Volume.h"
16 
17 
18 // #pragma mark - QueryPolicy
19 
20 
21 struct Query::QueryPolicy {
22 	typedef Query Context;
23 	typedef ::Node Entry;
24 	typedef ::Node Node;
25 	typedef void* NodeHolder;
26 
27 	struct Index {
28 		Query*		query;
29 		::Index*	index;
30 
31 		Index(Context* context)
32 			:
33 			query(context)
34 		{
35 		}
36 	};
37 
38 	struct IndexIterator : ::IndexIterator {
39 		::Index*			index;
40 		Entry*				entry;
41 
42 		IndexIterator(::Index* index)
43 			:
44 			index(index)
45 		{
46 		}
47 	};
48 
49 	static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
50 
51 	// Entry interface
52 
53 	static ino_t EntryGetParentID(Entry* entry)
54 	{
55 		return entry->Parent()->ID();
56 	}
57 
58 	static Node* EntryGetNode(Entry* entry)
59 	{
60 		return entry;
61 	}
62 
63 	static ino_t EntryGetNodeID(Entry* entry)
64 	{
65 		return entry->ID();
66 	}
67 
68 	static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
69 	{
70 		const char* name = entry->Name();
71 		size_t nameLength = strlen(name);
72 		if (nameLength >= bufferSize)
73 			return B_BUFFER_OVERFLOW;
74 
75 		memcpy(buffer, name, nameLength + 1);
76 		return nameLength + 1;
77 	}
78 
79 	static const char* EntryGetNameNoCopy(NodeHolder& holder, Entry* entry)
80 	{
81 		return entry->Name();
82 	}
83 
84 	// Index interface
85 
86 	static status_t IndexSetTo(Index& index, const char* attribute)
87 	{
88 		index.index = index.query->fVolume->FindIndex(StringKey(attribute));
89 		return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
90 	}
91 
92 	static void IndexUnset(Index& index)
93 	{
94 		index.index = NULL;
95 	}
96 
97 	static int32 IndexGetWeightedScore(Index& index, int32 score)
98 	{
99 		// should be inversely proportional to the index size; max input score
100 		// is 2048
101 		static const int32 maxFactor = (1024 * 1024) - 1;
102 		return score * (maxFactor /
103 			std::min(maxFactor, std::max((int32)1, index.index->CountEntries())));
104 	}
105 
106 	static type_code IndexGetType(Index& index)
107 	{
108 		return index.index->Type();
109 	}
110 
111 	static int32 IndexGetKeySize(Index& index)
112 	{
113 		return index.index->KeyLength();
114 	}
115 
116 	static IndexIterator* IndexCreateIterator(Index& index)
117 	{
118 		IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
119 		if (iterator == NULL)
120 			return NULL;
121 
122 		if (!index.index->GetIterator(*iterator)) {
123 			delete iterator;
124 			return NULL;
125 		}
126 
127 		return iterator;
128 	}
129 
130 	// IndexIterator interface
131 
132 	static void IndexIteratorDelete(IndexIterator* indexIterator)
133 	{
134 		delete indexIterator;
135 	}
136 
137 	static status_t IndexIteratorFind(IndexIterator* indexIterator,
138 		const void* value, size_t size)
139 	{
140 		if (!indexIterator->index->Find(value, size, *indexIterator))
141 			return B_ENTRY_NOT_FOUND;
142 
143 		return B_OK;
144 	}
145 
146 	static status_t IndexIteratorFetchNextEntry(IndexIterator* indexIterator,
147 		void* value, size_t* _valueLength, size_t bufferSize, size_t* duplicate)
148 	{
149 		Node* node = indexIterator->Next(value, _valueLength);
150 		if (node == NULL)
151 			return B_ENTRY_NOT_FOUND;
152 
153 		indexIterator->entry = node;
154 		return B_OK;
155 	}
156 
157 	static status_t IndexIteratorGetEntry(Context* context, IndexIterator* indexIterator,
158 		NodeHolder& holder, Entry** _entry)
159 	{
160 		*_entry = indexIterator->entry;
161 		return B_OK;
162 	}
163 
164 	static void IndexIteratorSkipDuplicates(IndexIterator* indexIterator)
165 	{
166 		// Nothing to do.
167 	}
168 
169 	static void IndexIteratorSuspend(IndexIterator* indexIterator)
170 	{
171 		indexIterator->Suspend();
172 	}
173 
174 	static void IndexIteratorResume(IndexIterator* indexIterator)
175 	{
176 		indexIterator->Resume();
177 	}
178 
179 	// Node interface
180 
181 	static const off_t NodeGetSize(Node* node)
182 	{
183 		return node->FileSize();
184 	}
185 
186 	static time_t NodeGetLastModifiedTime(Node* node)
187 	{
188 		return node->ModifiedTime().tv_sec;
189 	}
190 
191 	static status_t NodeGetAttribute(NodeHolder& nodeHolder, Node* node,
192 		const char* attribute, void* buffer, size_t* _size, int32* _type)
193 	{
194 		// TODO: Creating a cookie is quite a bit of overhead.
195 		AttributeCookie* cookie;
196 		status_t error = node->OpenAttribute(StringKey(attribute), O_RDONLY,
197 			cookie);
198 		if (error != B_OK)
199 			return error;
200 
201 		error = cookie->ReadAttribute(0, buffer, _size);
202 
203 		// also get the attribute type
204 		if (error == B_OK) {
205 			struct stat st;
206 			error = cookie->ReadAttributeStat(&st);
207 			if (error == B_OK)
208 				*_type = st.st_type;
209 		}
210 
211 		cookie->Close();
212 		delete cookie;
213 
214 		return error;
215 	}
216 
217 	static Entry* NodeGetFirstReferrer(Node* node)
218 	{
219 		return node;
220 	}
221 
222 	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
223 	{
224 		return NULL;
225 	}
226 
227 	// Volume interface
228 
229 	static dev_t ContextGetVolumeID(Context* context)
230 	{
231 		return context->fVolume->ID();
232 	}
233 };
234 
235 
236 // #pragma mark - Query
237 
238 
239 Query::Query(Volume* volume)
240 	:
241 	fVolume(volume),
242 	fImpl(NULL)
243 {
244 }
245 
246 
247 Query::~Query()
248 {
249 	if (fImpl != NULL) {
250 		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
251 			fVolume->RemoveQuery(this);
252 
253 		delete fImpl;
254 	}
255 }
256 
257 
258 /*static*/ status_t
259 Query::Create(Volume* volume, const char* queryString, uint32 flags,
260 	port_id port, uint32 token, Query*& _query)
261 {
262 	Query* query = new(std::nothrow) Query(volume);
263 	if (query == NULL)
264 		return B_NO_MEMORY;
265 
266 	status_t error = query->_Init(queryString, flags, port, token);
267 	if (error != B_OK) {
268 		delete query;
269 		return error;
270 	}
271 
272 	_query = query;
273 	return B_OK;
274 }
275 
276 
277 status_t
278 Query::Rewind()
279 {
280 	return fImpl->Rewind();
281 }
282 
283 
284 status_t
285 Query::GetNextEntry(struct dirent* entry, size_t size)
286 {
287 	return fImpl->GetNextEntry(entry, size);
288 }
289 
290 
291 void
292 Query::LiveUpdate(Node* node, const char* attribute, int32 type,
293 	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
294 {
295 	fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey,
296 		oldLength, (const uint8*)newKey, newLength);
297 }
298 
299 
300 status_t
301 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
302 {
303 	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
304 		fImpl);
305 	if (error != B_OK)
306 		return error;
307 
308 	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
309 		fVolume->AddQuery(this);
310 
311 	return B_OK;
312 }
313