Contiki-NG
Loading...
Searching...
No Matches
index.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010, Swedish Institute of Computer Science
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/**
31 * \file
32 * This component forwards index calls using the generic index
33 * API to specific implementations.
34 * \author
35 * Nicolas Tsiftes <nvt@sics.se>
36 */
37
38#include "contiki.h"
39#include "lib/memb.h"
40#include "lib/list.h"
41
42#define DEBUG DEBUG_NONE
43#include "net/ipv6/uip-debug.h"
44
45#include "antelope.h"
46#include "attribute.h"
47#include "db-options.h"
48#include "index.h"
49#include "storage.h"
50#include "sys/cc.h"
51
52static index_api_t *index_components[] = {&index_inline,
53 &index_maxheap};
54
55LIST(indices);
56MEMB(index_memb, index_t, DB_INDEX_POOL_SIZE);
57
58static process_event_t load_request_event;
59PROCESS(db_indexer, "DB Indexer");
60
61static index_api_t *
62find_index_api(index_type_t index_type)
63{
64 int i;
65
66 for(i = 0; i < CC_ARRAY_LENGTH(index_components); i++) {
67 if(index_components[i]->type == index_type) {
68 return index_components[i];
69 }
70 }
71
72 return NULL;
73}
74
75void
76index_init(void)
77{
78 list_init(indices);
79 memb_init(&index_memb);
80 process_start(&db_indexer, NULL);
81}
82
83db_result_t
84index_create(index_type_t index_type, relation_t *rel, attribute_t *attr)
85{
86 tuple_id_t cardinality;
87 index_t *index;
88 index_api_t *api;
89
90 cardinality = relation_cardinality(rel);
91 if(cardinality == INVALID_TUPLE) {
92 return DB_STORAGE_ERROR;
93 }
94
95 if(attr->domain != DOMAIN_INT && attr->domain != DOMAIN_LONG) {
96 PRINTF("DB: Cannot create an index for a non-number attribute!\n");
97 return DB_INDEX_ERROR;
98 }
99
100 api = find_index_api(index_type);
101 if(api == NULL) {
102 PRINTF("DB: No API for index type %d\n", (int)index_type);
103 return DB_INDEX_ERROR;
104 }
105
106 if(attr->index != NULL) {
107 /* Refuse to overwrite the old index. */
108 PRINTF("DB: The attribute %s is already indexed\n", attr->name);
109 return DB_INDEX_ERROR;
110 }
111
112 index = memb_alloc(&index_memb);
113 if(index == NULL) {
114 PRINTF("DB: Failed to allocate an index\n");
115 return DB_ALLOCATION_ERROR;
116 }
117
118 index->rel = rel;
119 index->attr = attr;
120 index->api = api;
121 index->flags = 0;
122 index->opaque_data = NULL;
123 index->descriptor_file[0] = '\0';
124 index->type = index_type;
125
126 if(DB_ERROR(api->create(index))) {
127 memb_free(&index_memb, index);
128 PRINTF("DB: Index-specific creation failed for attribute %s\n", attr->name);
129 return DB_INDEX_ERROR;
130 }
131
132 attr->index = index;
133 list_push(indices, index);
134
135 if(index->descriptor_file[0] != '\0' &&
136 DB_ERROR(storage_put_index(index))) {
137 PRINTF("DB: Failed to store index data in file \"%s\"\n",
138 index->descriptor_file);
139 api->destroy(index);
140 attr->index = NULL;
141 list_remove(indices, index);
142 memb_free(&index_memb, index);
143 return DB_INDEX_ERROR;
144 }
145
146 if(!(api->flags & INDEX_API_INLINE) && cardinality > 0) {
147 PRINTF("DB: Created an index for an old relation; issuing a load request\n");
148 index->flags = INDEX_LOAD_NEEDED;
149 process_post(&db_indexer, load_request_event, NULL);
150 } else {
151 /* Inline indexes (i.e., those using the existing storage of the relation)
152 do not need to be reloaded after restarting the system. */
153 PRINTF("DB: Index created for attribute %s\n", attr->name);
154 index->flags |= INDEX_READY;
155 }
156
157 return DB_OK;
158}
159
160db_result_t
161index_destroy(index_t *index)
162{
163 if(DB_ERROR(index_release(index)) ||
164 DB_ERROR(index->api->destroy(index))) {
165 return DB_INDEX_ERROR;
166 }
167
168 return DB_OK;
169}
170
171db_result_t
172index_load(relation_t *rel, attribute_t *attr)
173{
174 index_t *index;
175 index_api_t *api;
176
177 PRINTF("DB: Attempting to load an index over %s.%s\n", rel->name, attr->name);
178
179 index = memb_alloc(&index_memb);
180 if(index == NULL) {
181 PRINTF("DB: No more index objects available\n");
182 return DB_ALLOCATION_ERROR;
183 }
184
185 if(DB_ERROR(storage_get_index(index, rel, attr))) {
186 PRINTF("DB: Failed load an index descriptor from storage\n");
187 memb_free(&index_memb, index);
188 return DB_INDEX_ERROR;
189 }
190
191 index->rel = rel;
192 index->attr = attr;
193 index->opaque_data = NULL;
194
195 api = find_index_api(index->type);
196 if(api == NULL) {
197 PRINTF("DB: No API for index type %d\n", index->type);
198 return DB_INDEX_ERROR;
199 }
200
201 index->api = api;
202
203 if(DB_ERROR(api->load(index))) {
204 PRINTF("DB: Index-specific load failed\n");
205 return DB_INDEX_ERROR;
206 }
207
208 list_push(indices, index);
209 attr->index = index;
210 index->flags = INDEX_READY;
211
212 return DB_OK;
213}
214
215db_result_t
216index_release(index_t *index)
217{
218 if(DB_ERROR(index->api->release(index))) {
219 return DB_INDEX_ERROR;
220 }
221
222 index->attr->index = NULL;
223 list_remove(indices, index);
224 memb_free(&index_memb, index);
225
226 return DB_OK;
227}
228
229db_result_t
230index_insert(index_t *index, attribute_value_t *value,
231 tuple_id_t tuple_id)
232{
233 return index->api->insert(index, value, tuple_id);
234}
235
236db_result_t
237index_delete(index_t *index, attribute_value_t *value)
238{
239 if(index->flags != INDEX_READY) {
240 return DB_INDEX_ERROR;
241 }
242
243 return index->api->delete(index, value);
244}
245
246db_result_t
247index_get_iterator(index_iterator_t *iterator, index_t *index,
248 attribute_value_t *min_value,
249 attribute_value_t *max_value)
250{
251 tuple_id_t cardinality;
252 unsigned long range;
253 unsigned long max_range;
254 long max;
255 long min;
256
257 cardinality = relation_cardinality(index->rel);
258 if(cardinality == INVALID_TUPLE) {
259 return DB_STORAGE_ERROR;
260 }
261
262 if(index->flags != INDEX_READY) {
263 return DB_INDEX_ERROR;
264 }
265
266 min = db_value_to_long(min_value);
267 max = db_value_to_long(max_value);
268
269 range = (unsigned long)max - min;
270 if(range > 0) {
271 /*
272 * Index structures that do not have a natural ability to handle
273 * range queries (e.g., a hash index) can nevertheless emulate them.
274 *
275 * The range query emulation attempts to look up the key for each
276 * value in the search range. If the search range is sparse, this
277 * iteration will incur a considerable overhead per found key.
278 *
279 * Hence, the emulation is preferable when an external module wants
280 * to iterate over a narrow range of keys, for which the total
281 * search cost is smaller than that of an iteration over all tuples
282 * in the relation.
283 */
284 if(!(index->api->flags & INDEX_API_RANGE_QUERIES)) {
285 PRINTF("DB: Range query requested for an index that does not support it\n");
286 max_range = cardinality / DB_INDEX_COST;
287 if(range > max_range) {
288 return DB_INDEX_ERROR;
289 }
290 PRINTF("DB: Using the index anyway because the range is small enough (%lu <= %lu)\n",
291 range, max_range);
292 }
293 }
294
295 iterator->index = index;
296 iterator->min_value = *min_value;
297 iterator->max_value = *max_value;
298 iterator->next_item_no = 0;
299
300 PRINTF("DB: Acquired an index iterator for %s.%s over the range (%ld,%ld)\n",
301 index->rel->name, index->attr->name,
302 min_value->u.long_value, max_value->u.long_value);
303
304 return DB_OK;
305}
306
307tuple_id_t
308index_get_next(index_iterator_t *iterator)
309{
310 long min;
311 long max;
312
313 if(iterator->index == NULL) {
314 /* This attribute is not indexed. */
315 return INVALID_TUPLE;
316 }
317
318 if((iterator->index->attr->flags & ATTRIBUTE_FLAG_UNIQUE) &&
319 iterator->next_item_no == 1) {
320 min = db_value_to_long(&iterator->min_value);
321 max = db_value_to_long(&iterator->max_value);
322 if(min == max) {
323 /*
324 * We stop if this is an equivalence search on an attribute
325 * whose values are unique, and we already found one item.
326 */
327 PRINTF("DB: Equivalence search finished\n");
328 return INVALID_TUPLE;
329 }
330 }
331
332 return iterator->index->api->get_next(iterator);
333}
334
335int
336index_exists(attribute_t *attr)
337{
338 index_t *index;
339
340 index = (index_t *)attr->index;
341 if(index == NULL || index->flags != INDEX_READY) {
342 return 0;
343 }
344
345 return 1;
346}
347
348static index_t *
349get_next_index_to_load(void)
350{
351 index_t *index;
352
353 for(index = list_head(indices); index != NULL; index = index->next) {
354 if(index->flags & INDEX_LOAD_NEEDED) {
355 return index;
356 }
357 }
358
359 return NULL;
360}
361
362PROCESS_THREAD(db_indexer, ev, data)
363{
364 static index_t *index;
365 static db_handle_t handle;
366 static tuple_id_t row;
367 db_result_t result;
368 attribute_value_t value;
369 int column;
370
372 load_request_event = process_alloc_event();
373
374 for(;;) {
375 PROCESS_WAIT_EVENT_UNTIL(ev == load_request_event);
376
377 index = get_next_index_to_load();
378 if(index == NULL) {
379 PRINTF("DB: Request to load an index, but no index is set to be loaded\n");
380 continue;
381 }
382
383 PRINTF("DB: Loading the index for %s.%s...\n",
384 index->rel->name, index->attr->name);
385
386 /* Project the values of the indexed attribute from all tuples in
387 the relation, and insert them into the index again. */
388 if(DB_ERROR(db_query(&handle, "SELECT %s FROM %s;", index->attr->name, index->rel->name))) {
389 index->flags |= INDEX_LOAD_ERROR;
390 index->flags &= ~INDEX_LOAD_NEEDED;
391 continue;
392 }
393
394 for(;; row++) {
396
397 result = db_process(&handle);
398 if(DB_ERROR(result)) {
399 PRINTF("DB: Index loading failed while processing: %s\n",
400 db_get_result_message(result));
401 index->flags |= INDEX_LOAD_ERROR;
402 goto cleanup;
403 }
404 if(result == DB_FINISHED) {
405 break;
406 }
407
408 for(column = 0; column < handle.ncolumns; column++) {
409 if(DB_ERROR(db_get_value(&value, &handle, column))) {
410 index->flags |= INDEX_LOAD_ERROR;
411 goto cleanup;
412 }
413
414 if(DB_ERROR(index_insert(index, &value, row))) {
415 index->flags |= INDEX_LOAD_ERROR;
416 goto cleanup;
417 }
418 }
419 }
420
421 PRINTF("DB: Loaded %lu rows into the index\n",
422 (unsigned long)handle.current_row);
423
424cleanup:
425 if(index->flags & INDEX_LOAD_ERROR) {
426 PRINTF("DB: Failed to load the index for %s.%s\n",
427 index->rel->name, index->attr->name);
428 }
429 index->flags &= ~INDEX_LOAD_NEEDED;
430 index->flags |= INDEX_READY;
431 db_free(&handle);
432 }
433
434
435 PROCESS_END();
436}
Declarations of the main Antelope functions.
Definitions for attributes.
Default definitions of C compiler quirk work-arounds.
#define CC_ARRAY_LENGTH(array)
Counts the number of elements of an array.
Definition cc.h:122
Database configuration options.
static int value(int type)
static void list_init(list_t list)
Initialize a list.
Definition list.h:152
#define LIST(name)
Declare a linked list.
Definition list.h:90
void list_remove(list_t list, const void *item)
Remove a specific element from a list.
Definition list.c:134
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition list.c:90
static void * list_head(const_list_t list)
Get a pointer to the first element of a list.
Definition list.h:169
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition memb.c:78
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition memb.c:59
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition memb.c:52
#define MEMB(name, structure, num)
Declare a memory block.
Definition memb.h:91
#define PROCESS(name, strname)
Declare a process.
Definition process.h:309
#define PROCESS_PAUSE()
Yield the process for a short while.
Definition process.h:223
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition process.c:325
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition process.c:111
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:122
#define PROCESS_WAIT_EVENT_UNTIL(c)
Wait for an event to be posted to the process, with an extra condition.
Definition process.h:159
#define PROCESS_END()
Define the end of a process.
Definition process.h:133
void process_start(struct process *p, process_data_t data)
Start a process.
Definition process.c:121
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:275
Linked list manipulation routines.
Memory block allocation routines.
The storage interface used by the database.
A set of debugging macros for the IP stack.