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