xref: /haiku/src/add-ons/kernel/file_systems/packagefs/indices/Query.cpp (revision 5ac9b506412b11afb993bb52d161efe7666958a5)
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;
101 		return score * (maxFactor
102 			/ std::min(maxFactor,
103 				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 IndexIteratorGetNextEntry(IndexIterator* indexIterator,
147 		void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry)
148 	{
149 		Node* node = indexIterator->Next(value, _valueLength);
150 		if (node == NULL)
151 			return B_ENTRY_NOT_FOUND;
152 
153 		*_entry = node;
154 		return B_OK;
155 	}
156 
157 	static void IndexIteratorSuspend(IndexIterator* indexIterator)
158 	{
159 		indexIterator->Suspend();
160 	}
161 
162 	static void IndexIteratorResume(IndexIterator* indexIterator)
163 	{
164 		indexIterator->Resume();
165 	}
166 
167 	// Node interface
168 
169 	static const off_t NodeGetSize(Node* node)
170 	{
171 		return node->FileSize();
172 	}
173 
174 	static time_t NodeGetLastModifiedTime(Node* node)
175 	{
176 		return node->ModifiedTime().tv_sec;
177 	}
178 
179 	static status_t NodeGetAttribute(Node* node, const char* attribute,
180 		void* buffer, size_t* _size, int32* _type)
181 	{
182 		// TODO: Creating a cookie is quite a bit of overhead.
183 		AttributeCookie* cookie;
184 		status_t error = node->OpenAttribute(StringKey(attribute), O_RDONLY,
185 			cookie);
186 		if (error != B_OK)
187 			return error;
188 
189 		error = cookie->ReadAttribute(0, buffer, _size);
190 
191 		// also get the attribute type
192 		if (error == B_OK) {
193 			struct stat st;
194 			error = cookie->ReadAttributeStat(&st);
195 			if (error == B_OK)
196 				*_type = st.st_type;
197 		}
198 
199 		cookie->Close();
200 		delete cookie;
201 
202 		return error;
203 	}
204 
205 	static Entry* NodeGetFirstReferrer(Node* node)
206 	{
207 		return node;
208 	}
209 
210 	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
211 	{
212 		return NULL;
213 	}
214 
215 	// Volume interface
216 
217 	static dev_t ContextGetVolumeID(Context* context)
218 	{
219 		return context->fVolume->ID();
220 	}
221 };
222 
223 
224 // #pragma mark - Query
225 
226 
227 Query::Query(Volume* volume)
228 	:
229 	fVolume(volume),
230 	fImpl(NULL)
231 {
232 }
233 
234 
235 Query::~Query()
236 {
237 	if (fImpl != NULL) {
238 		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
239 			fVolume->RemoveQuery(this);
240 
241 		delete fImpl;
242 	}
243 }
244 
245 
246 /*static*/ status_t
247 Query::Create(Volume* volume, const char* queryString, uint32 flags,
248 	port_id port, uint32 token, Query*& _query)
249 {
250 	Query* query = new(std::nothrow) Query(volume);
251 	if (query == NULL)
252 		return B_NO_MEMORY;
253 
254 	status_t error = query->_Init(queryString, flags, port, token);
255 	if (error != B_OK) {
256 		delete query;
257 		return error;
258 	}
259 
260 	_query = query;
261 	return B_OK;
262 }
263 
264 
265 status_t
266 Query::Rewind()
267 {
268 	return fImpl->Rewind();
269 }
270 
271 
272 status_t
273 Query::GetNextEntry(struct dirent* entry, size_t size)
274 {
275 	return fImpl->GetNextEntry(entry, size);
276 }
277 
278 
279 void
280 Query::LiveUpdate(Node* node, const char* attribute, int32 type,
281 	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
282 {
283 	fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey,
284 		oldLength, (const uint8*)newKey, newLength);
285 }
286 
287 
288 status_t
289 Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
290 {
291 	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
292 		fImpl);
293 	if (error != B_OK)
294 		return error;
295 
296 	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
297 		fVolume->AddQuery(this);
298 
299 	return B_OK;
300 }
301