Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 : : /*
3 : : * Copyright 2010 Couchbase, Inc
4 : : *
5 : : * Licensed under the Apache License, Version 2.0 (the "License");
6 : : * you may not use this file except in compliance with the License.
7 : : * You may obtain a copy of the License at
8 : : *
9 : : * http://www.apache.org/licenses/LICENSE-2.0
10 : : *
11 : : * Unless required by applicable law or agreed to in writing, software
12 : : * distributed under the License is distributed on an "AS IS" BASIS,
13 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : : * See the License for the specific language governing permissions and
15 : : * limitations under the License.
16 : : */
17 : :
18 : : #include <stdlib.h>
19 : : #include <string.h>
20 : :
21 : : #include "libforestdb/forestdb.h"
22 : : #include "common.h"
23 : : #include "internal_types.h"
24 : : #include "fdb_internal.h"
25 : : #include "configuration.h"
26 : : #include "avltree.h"
27 : : #include "list.h"
28 : : #include "docio.h"
29 : : #include "filemgr.h"
30 : : #include "wal.h"
31 : : #include "hbtrie.h"
32 : : #include "btreeblock.h"
33 : : #include "snapshot.h"
34 : :
35 : : #include "memleak.h"
36 : :
37 : : static const char *default_kvs_name = DEFAULT_KVS_NAME;
38 : :
39 : : // list element for opened KV store handles
40 : : // (in-memory data: managed by the file handle)
41 : : struct kvs_opened_node {
42 : : fdb_kvs_handle *handle;
43 : : struct list_elem le;
44 : : };
45 : :
46 : : // list element for custom cmp functions in fhandle
47 : : struct cmp_func_node {
48 : : char *kvs_name;
49 : : fdb_custom_cmp_variable func;
50 : : struct list_elem le;
51 : : };
52 : :
53 : 940 : static int _kvs_cmp_name(struct avl_node *a, struct avl_node *b, void *aux)
54 : : {
55 : : struct kvs_node *aa, *bb;
56 : 940 : aa = _get_entry(a, struct kvs_node, avl_name);
57 : 940 : bb = _get_entry(b, struct kvs_node, avl_name);
58 : 940 : return strcmp(aa->kvs_name, bb->kvs_name);
59 : : }
60 : :
61 : 79965 : static int _kvs_cmp_id(struct avl_node *a, struct avl_node *b, void *aux)
62 : : {
63 : : struct kvs_node *aa, *bb;
64 : 79965 : aa = _get_entry(a, struct kvs_node, avl_id);
65 : 79965 : bb = _get_entry(b, struct kvs_node, avl_id);
66 : :
67 [ + + ]: 79965 : if (aa->id < bb->id) {
68 : 25757 : return -1;
69 [ + + ]: 54208 : } else if (aa->id > bb->id) {
70 : 2719 : return 1;
71 : : } else {
72 : 79965 : return 0;
73 : : }
74 : : }
75 : :
76 : 290 : void fdb_file_handle_init(fdb_file_handle *fhandle,
77 : : fdb_kvs_handle *root)
78 : : {
79 : 290 : fhandle->root = root;
80 : 290 : fhandle->flags = 0x0;
81 : 290 : root->fhandle = fhandle;
82 : 290 : fhandle->handles = (struct list*)calloc(1, sizeof(struct list));
83 : 290 : fhandle->cmp_func_list = NULL;
84 : 290 : spin_init(&fhandle->lock);
85 : 290 : }
86 : :
87 : 274 : void fdb_file_handle_close_all(fdb_file_handle *fhandle)
88 : : {
89 : : struct list_elem *e;
90 : : struct kvs_opened_node *node;
91 : :
92 : 274 : spin_lock(&fhandle->lock);
93 : 274 : e = list_begin(fhandle->handles);
94 [ - + ]: 274 : while (e) {
95 : 0 : node = _get_entry(e, struct kvs_opened_node, le);
96 : 0 : e = list_next(e);
97 : 0 : _fdb_close(node->handle);
98 : 0 : free(node->handle);
99 : 0 : free(node);
100 : : }
101 : 274 : spin_unlock(&fhandle->lock);
102 : 274 : }
103 : :
104 : 13 : void fdb_file_handle_parse_cmp_func(fdb_file_handle *fhandle,
105 : : size_t n_func,
106 : : char **kvs_names,
107 : : fdb_custom_cmp_variable *functions)
108 : : {
109 : : int i;
110 : : struct cmp_func_node *node;
111 : :
112 [ + - ][ + - ]: 13 : if (n_func == 0 || !kvs_names || !functions) {
[ - + ]
113 : 13 : return;
114 : : }
115 : :
116 : 13 : fhandle->cmp_func_list = (struct list*)calloc(1, sizeof(struct list));
117 [ + + ]: 46 : for (i=0;i<n_func;++i){
118 : 33 : node = (struct cmp_func_node*)calloc(1, sizeof(struct cmp_func_node));
119 [ + + ]: 33 : if (kvs_names[i]) {
120 : 28 : node->kvs_name = (char*)calloc(1, strlen(kvs_names[i])+1);
121 : 28 : strcpy(node->kvs_name, kvs_names[i]);
122 : : } else {
123 : : // NULL .. default KVS
124 : 5 : node->kvs_name = NULL;
125 : : }
126 : 33 : node->func = functions[i];
127 : 33 : list_push_back(fhandle->cmp_func_list, &node->le);
128 : : }
129 : : }
130 : :
131 : 289 : static void _free_cmp_func_list(fdb_file_handle *fhandle)
132 : : {
133 : : struct list_elem *e;
134 : : struct cmp_func_node *cmp_node;
135 : :
136 [ + + ]: 289 : if (!fhandle->cmp_func_list) {
137 : 289 : return;
138 : : }
139 : :
140 : 13 : e = list_begin(fhandle->cmp_func_list);
141 [ + + ]: 46 : while (e) {
142 : 33 : cmp_node = _get_entry(e, struct cmp_func_node, le);
143 : 33 : e = list_remove(fhandle->cmp_func_list, &cmp_node->le);
144 : :
145 : 33 : free(cmp_node->kvs_name);
146 : 33 : free(cmp_node);
147 : : }
148 : 13 : free(fhandle->cmp_func_list);
149 : 13 : fhandle->cmp_func_list = NULL;
150 : : }
151 : :
152 : 289 : void fdb_file_handle_free(fdb_file_handle *fhandle)
153 : : {
154 : 289 : free(fhandle->handles);
155 : 289 : _free_cmp_func_list(fhandle);
156 : 289 : spin_destroy(&fhandle->lock);
157 : 289 : free(fhandle);
158 : 289 : }
159 : :
160 : 282 : fdb_status fdb_kvs_cmp_check(fdb_kvs_handle *handle)
161 : : {
162 : : int ori_flag;
163 : 282 : fdb_file_handle *fhandle = handle->fhandle;
164 : : fdb_custom_cmp_variable ori_custom_cmp;
165 : 282 : struct filemgr *file = handle->file;
166 : : struct cmp_func_node *cmp_node;
167 : : struct kvs_node *kvs_node, query;
168 : : struct list_elem *e;
169 : : struct avl_node *a;
170 : :
171 : 282 : spin_lock(&file->kv_header->lock);
172 : 282 : ori_flag = file->kv_header->custom_cmp_enabled;
173 : 282 : ori_custom_cmp = file->kv_header->default_kvs_cmp;
174 : :
175 [ + + ]: 282 : if (fhandle->cmp_func_list) {
176 : 13 : handle->kvs_config.custom_cmp = NULL;
177 : :
178 : 13 : e = list_begin(fhandle->cmp_func_list);
179 [ + + ]: 46 : while (e) {
180 : 33 : cmp_node = _get_entry(e, struct cmp_func_node, le);
181 [ + + ][ + + ]: 33 : if (cmp_node->kvs_name == NULL ||
182 : 28 : !strcmp(cmp_node->kvs_name, default_kvs_name)) { // default KVS
183 : 12 : handle->kvs_config.custom_cmp = cmp_node->func;
184 : 12 : file->kv_header->default_kvs_cmp = cmp_node->func;
185 : 12 : file->kv_header->custom_cmp_enabled = 1;
186 : : } else {
187 : : // search by name
188 : 21 : query.kvs_name = cmp_node->kvs_name;
189 : : a = avl_search(file->kv_header->idx_name,
190 : : &query.avl_name,
191 : 21 : _kvs_cmp_name);
192 [ + + ]: 21 : if (a) { // found
193 : 17 : kvs_node = _get_entry(a, struct kvs_node, avl_name);
194 [ + + ]: 17 : if (!kvs_node->custom_cmp) {
195 : 12 : kvs_node->custom_cmp = cmp_node->func;
196 : : }
197 : 17 : file->kv_header->custom_cmp_enabled = 1;
198 : : }
199 : : }
200 : 33 : e = list_next(&cmp_node->le);
201 : : }
202 : : }
203 : :
204 : : // first check the default KVS
205 : : // 1. root handle has not been opened yet: don't care
206 : : // 2. root handle was opened before: must match the flag
207 [ + + ]: 282 : if (fhandle->flags & FHANDLE_ROOT_INITIALIZED) {
208 [ + + ][ + + ]: 141 : if (fhandle->flags & FHANDLE_ROOT_CUSTOM_CMP &&
209 : : handle->kvs_config.custom_cmp == NULL) {
210 : : // custom cmp function was assigned before,
211 : : // but no custom cmp function is assigned
212 : 1 : file->kv_header->custom_cmp_enabled = ori_flag;
213 : 1 : file->kv_header->default_kvs_cmp = ori_custom_cmp;
214 : 1 : spin_unlock(&file->kv_header->lock);
215 : 1 : return FDB_RESULT_INVALID_CMP_FUNCTION;
216 : : }
217 [ + + ][ + + ]: 140 : if (!(fhandle->flags & FHANDLE_ROOT_CUSTOM_CMP) &&
218 : : handle->kvs_config.custom_cmp) {
219 : : // custom cmp function was not assigned before,
220 : : // but custom cmp function is assigned from user
221 : 1 : file->kv_header->custom_cmp_enabled = ori_flag;
222 : 1 : file->kv_header->default_kvs_cmp = ori_custom_cmp;
223 : 1 : spin_unlock(&file->kv_header->lock);
224 : 1 : return FDB_RESULT_INVALID_CMP_FUNCTION;
225 : : }
226 : : }
227 : :
228 : : // next check other KVSs
229 : 280 : a = avl_first(file->kv_header->idx_name);
230 [ + + ]: 709 : while (a) {
231 : 431 : kvs_node = _get_entry(a, struct kvs_node, avl_name);
232 : 431 : a = avl_next(a);
233 : :
234 [ + + ][ + + ]: 431 : if (kvs_node->flags & KVS_FLAG_CUSTOM_CMP &&
235 : : kvs_node->custom_cmp == NULL) {
236 : : // custom cmp function was assigned before,
237 : : // but no custom cmp function is assigned
238 : 2 : file->kv_header->custom_cmp_enabled = ori_flag;
239 : 2 : file->kv_header->default_kvs_cmp = ori_custom_cmp;
240 : 2 : spin_unlock(&file->kv_header->lock);
241 : 2 : return FDB_RESULT_INVALID_CMP_FUNCTION;
242 : : }
243 [ + + ][ - + ]: 429 : if (!(kvs_node->flags & KVS_FLAG_CUSTOM_CMP) &&
244 : : kvs_node->custom_cmp) {
245 : : // custom cmp function was not assigned before,
246 : : // but custom cmp function is assigned from user
247 : 0 : file->kv_header->custom_cmp_enabled = ori_flag;
248 : 0 : file->kv_header->default_kvs_cmp = ori_custom_cmp;
249 : 0 : spin_unlock(&file->kv_header->lock);
250 : 0 : return FDB_RESULT_INVALID_CMP_FUNCTION;
251 : : }
252 : : }
253 : :
254 : 278 : spin_unlock(&file->kv_header->lock);
255 : 282 : return FDB_RESULT_SUCCESS;
256 : : }
257 : :
258 : 319 : fdb_custom_cmp_variable fdb_kvs_find_cmp_name(fdb_kvs_handle *handle,
259 : : char *kvs_name)
260 : : {
261 : : fdb_file_handle *fhandle;
262 : : struct list_elem *e;
263 : : struct cmp_func_node *cmp_node;
264 : :
265 : 319 : fhandle = handle->fhandle;
266 [ + + ]: 319 : if (!fhandle->cmp_func_list) {
267 : 300 : return NULL;
268 : : }
269 : :
270 : 19 : e = list_begin(fhandle->cmp_func_list);
271 [ + + ]: 28 : while (e) {
272 : 26 : cmp_node = _get_entry(e, struct cmp_func_node, le);
273 [ + + ][ + + ]: 26 : if (kvs_name == NULL ||
274 : 16 : !strcmp(kvs_name, default_kvs_name)) {
275 [ + + ][ + + ]: 13 : if (cmp_node->kvs_name == NULL ||
276 : 7 : !strcmp(cmp_node->kvs_name, default_kvs_name)) { // default KVS
277 : 12 : return cmp_node->func;
278 : : }
279 [ + + ][ + + ]: 13 : } else if (cmp_node->kvs_name &&
280 : 10 : !strcmp(cmp_node->kvs_name, kvs_name)) {
281 : 5 : return cmp_node->func;
282 : : }
283 : 9 : e = list_next(&cmp_node->le);
284 : : }
285 : 319 : return NULL;
286 : : }
287 : :
288 : 9860484 : void * fdb_kvs_find_cmp_chunk(void *chunk, void *aux)
289 : : {
290 : : fdb_kvs_id_t kv_id, _kv_id;
291 : 9860484 : struct hbtrie *trie = (struct hbtrie *)aux;
292 : : struct btreeblk_handle *bhandle;
293 : : struct filemgr *file;
294 : : struct avl_node *a;
295 : : struct kvs_node query, *node;
296 : :
297 : 9860484 : bhandle = (struct btreeblk_handle*)trie->btreeblk_handle;
298 : 9860484 : file = bhandle->file;
299 : :
300 [ + + ]: 9860484 : if (!file->kv_header->custom_cmp_enabled) {
301 : 9837131 : return NULL;
302 : : }
303 : :
304 : 23353 : _kv_id = *((fdb_kvs_id_t *)chunk);
305 : 23353 : kv_id = _endian_decode(_kv_id);
306 : :
307 : : // search by id
308 [ + + ]: 23353 : if (kv_id > 0) {
309 : 13660 : query.id = kv_id;
310 : 13660 : spin_lock(&file->kv_header->lock);
311 : 13660 : a = avl_search(file->kv_header->idx_id, &query.avl_id, _kvs_cmp_id);
312 : 13660 : spin_unlock(&file->kv_header->lock);
313 : :
314 [ + + ]: 13660 : if (a) {
315 : 13658 : node = _get_entry(a, struct kvs_node, avl_id);
316 : 13658 : return (void *)node->custom_cmp;
317 : : }
318 : : } else {
319 : : // root handle
320 : 9693 : return (void *)file->kv_header->default_kvs_cmp;
321 : : }
322 : 9860484 : return NULL;
323 : : }
324 : :
325 : 610 : void fdb_kvs_info_create(fdb_kvs_handle *root_handle,
326 : : fdb_kvs_handle *handle,
327 : : struct filemgr *file,
328 : : const char *kvs_name)
329 : : {
330 : : struct kvs_node query, *kvs_node;
331 : : struct kvs_opened_node *opened_node;
332 : : struct avl_node *a;
333 : :
334 : 610 : handle->kvs = (struct kvs_info*)calloc(1, sizeof(struct kvs_info));
335 : :
336 [ + + ]: 610 : if (root_handle == NULL) {
337 : : // 'handle' is a super handle
338 : 282 : handle->kvs->type = KVS_ROOT;
339 : 282 : handle->kvs->root = handle->fhandle->root;
340 : : // super handle's ID is always 0
341 : 282 : handle->kvs->id = 0;
342 : : // force custom cmp function
343 : 282 : spin_lock(&file->kv_header->lock);
344 : 282 : handle->kvs_config.custom_cmp = file->kv_header->default_kvs_cmp;
345 : 282 : spin_unlock(&file->kv_header->lock);
346 : :
347 : : } else {
348 : : // 'handle' is a sub handle (i.e., KV instance in a DB instance)
349 : 328 : handle->kvs->type = KVS_SUB;
350 : 328 : handle->kvs->root = root_handle;
351 : :
352 [ + + ]: 328 : if (kvs_name) {
353 : 298 : spin_lock(&file->kv_header->lock);
354 : 298 : query.kvs_name = (char*)kvs_name;
355 : : a = avl_search(file->kv_header->idx_name, &query.avl_name,
356 : 298 : _kvs_cmp_name);
357 [ + + ]: 298 : if (a == NULL) {
358 : : // KV instance name is not found
359 : 107 : free(handle->kvs);
360 : 107 : handle->kvs = NULL;
361 : 107 : spin_unlock(&file->kv_header->lock);
362 : 610 : return;
363 : : }
364 : 191 : kvs_node = _get_entry(a, struct kvs_node, avl_name);
365 : 191 : handle->kvs->id = kvs_node->id;
366 : : // force custom cmp function
367 : 191 : handle->kvs_config.custom_cmp = kvs_node->custom_cmp;
368 : 191 : spin_unlock(&file->kv_header->lock);
369 : : } else {
370 : : // snapshot of the root handle
371 : 30 : handle->kvs->id = 0;
372 : : }
373 : :
374 : : opened_node = (struct kvs_opened_node *)
375 : 221 : calloc(1, sizeof(struct kvs_opened_node));
376 : 221 : opened_node->handle = handle;
377 : :
378 : 221 : handle->node = opened_node;
379 : 221 : spin_lock(&root_handle->fhandle->lock);
380 : 221 : list_push_back(root_handle->fhandle->handles, &opened_node->le);
381 : 221 : spin_unlock(&root_handle->fhandle->lock);
382 : : }
383 : : }
384 : :
385 : 506 : void fdb_kvs_info_free(fdb_kvs_handle *handle)
386 : : {
387 [ + + ]: 506 : if (handle->kvs == NULL) {
388 : 506 : return;
389 : : }
390 : :
391 : 501 : free(handle->kvs);
392 : 501 : handle->kvs = NULL;
393 : : }
394 : :
395 : 335 : void _fdb_kvs_header_create(struct kvs_header **kv_header_ptr)
396 : : {
397 : : struct kvs_header *kv_header;
398 : :
399 : 335 : kv_header = (struct kvs_header *)calloc(1, sizeof(struct kvs_header));
400 : 335 : *kv_header_ptr = kv_header;
401 : :
402 : : // KV ID '0' is reserved for default KV instance (super handle)
403 : 335 : kv_header->id_counter = 1;
404 : 335 : kv_header->default_kvs_cmp = NULL;
405 : 335 : kv_header->custom_cmp_enabled = 0;
406 : 335 : kv_header->idx_name = (struct avl_tree*)malloc(sizeof(struct avl_tree));
407 : 335 : kv_header->idx_id = (struct avl_tree*)malloc(sizeof(struct avl_tree));
408 : 335 : avl_init(kv_header->idx_name, NULL);
409 : 335 : avl_init(kv_header->idx_id, NULL);
410 : 335 : spin_init(&kv_header->lock);
411 : 335 : }
412 : :
413 : 238 : void fdb_kvs_header_create(struct filemgr *file)
414 : : {
415 [ + + ]: 238 : if (file->kv_header) {
416 : 238 : return; // already exist
417 : : }
418 : :
419 : 225 : _fdb_kvs_header_create(&file->kv_header);
420 : 225 : file->free_kv_header = fdb_kvs_header_free;
421 : : }
422 : :
423 : 53 : static void fdb_kvs_header_reset_all_stats(struct filemgr *file)
424 : : {
425 : : struct avl_node *a;
426 : : struct kvs_node *node;
427 : 53 : struct kvs_header *kv_header = file->kv_header;
428 : :
429 : 53 : spin_lock(&kv_header->lock);
430 : 53 : a = avl_first(kv_header->idx_id);
431 [ + + ]: 58 : while (a) {
432 : 5 : node = _get_entry(a, struct kvs_node, avl_id);
433 : 5 : a = avl_next(&node->avl_id);
434 : 5 : memset(&node->stat, 0x0, sizeof(node->stat));
435 : : }
436 : 53 : spin_unlock(&kv_header->lock);
437 : 53 : }
438 : :
439 : 53 : void fdb_kvs_header_copy(fdb_kvs_handle *handle,
440 : : struct filemgr *new_file,
441 : : struct docio_handle *new_dhandle)
442 : : {
443 : : // copy KV header data in 'handle' to new file
444 : 53 : fdb_kvs_header_create(new_file);
445 : : // read from 'handle->dhandle', and import into 'new_file'
446 : : fdb_kvs_header_read(new_file, handle->dhandle,
447 : 53 : handle->kv_info_offset);
448 : : // write KV header in 'new_file' using 'new_dhandle'
449 : : handle->kv_info_offset = fdb_kvs_header_append(new_file,
450 : 53 : new_dhandle);
451 : 53 : fdb_kvs_header_reset_all_stats(new_file);
452 : 53 : spin_lock(&handle->file->kv_header->lock);
453 : 53 : spin_lock(&new_file->kv_header->lock);
454 : : new_file->kv_header->default_kvs_cmp =
455 : 53 : handle->file->kv_header->default_kvs_cmp;
456 : : new_file->kv_header->custom_cmp_enabled =
457 : 53 : handle->file->kv_header->custom_cmp_enabled;
458 : 53 : spin_unlock(&new_file->kv_header->lock);
459 : 53 : spin_unlock(&handle->file->kv_header->lock);
460 : 53 : }
461 : :
462 : : // export KV header info to raw data
463 : 13878 : void _fdb_kvs_header_export(struct kvs_header *kv_header,
464 : : void **data, size_t *len)
465 : : {
466 : : /* << raw data structure >>
467 : : * [# KV instances]: 8 bytes
468 : : * [current KV ID counter]: 8 bytes
469 : : * ---
470 : : * [name length]: 2 bytes
471 : : * [instance name]: x bytes
472 : : * [instance ID]: 8 bytes
473 : : * [sequence number]: 8 bytes
474 : : * [# live index nodes]: 8 bytes
475 : : * [# docs]: 8 bytes
476 : : * [data size]: 8 bytes
477 : : * [flags]: 8 bytes
478 : : * ...
479 : : */
480 : :
481 : 13878 : int size = 0;
482 : 13878 : int offset = 0;
483 : : uint16_t name_len, _name_len;
484 : 13878 : uint64_t c = 0;
485 : : uint64_t _n_kv, _kv_id, _flags;
486 : : uint64_t _nlivenodes, _ndocs, _datasize;
487 : : fdb_kvs_id_t _id_counter;
488 : : fdb_seqnum_t _seqnum;
489 : : struct kvs_node *node;
490 : : struct avl_node *a;
491 : :
492 [ - + ]: 13878 : if (kv_header == NULL) {
493 : 0 : *data = NULL;
494 : 0 : *len = 0;
495 : 13878 : return ;
496 : : }
497 : :
498 : 13878 : spin_lock(&kv_header->lock);
499 : :
500 : : // pre-scan to estimate the size of data
501 : 13878 : size += sizeof(uint64_t);
502 : 13878 : size += sizeof(fdb_kvs_id_t);
503 : 13878 : a = avl_first(kv_header->idx_name);
504 [ + + ]: 14967 : while(a) {
505 : 1089 : node = _get_entry(a, struct kvs_node, avl_name);
506 : 1089 : c++;
507 : 1089 : size += sizeof(uint16_t); // length
508 : 1089 : size += strlen(node->kvs_name)+1; // name
509 : 1089 : size += sizeof(node->id); // ID
510 : 1089 : size += sizeof(node->seqnum); // seq number
511 : 1089 : size += sizeof(node->stat.nlivenodes); // # live index nodes
512 : 1089 : size += sizeof(node->stat.ndocs); // # docs
513 : 1089 : size += sizeof(node->stat.datasize); // data size
514 : 1089 : size += sizeof(node->flags); // flags
515 : 1089 : a = avl_next(a);
516 : : }
517 : :
518 : 13878 : *data = (void *)malloc(size);
519 : :
520 : : // # KV instances
521 : 13878 : _n_kv = _endian_encode(c);
522 : 13878 : memcpy((uint8_t*)*data + offset, &_n_kv, sizeof(_n_kv));
523 : 13878 : offset += sizeof(_n_kv);
524 : :
525 : : // ID counter
526 : 13878 : _id_counter = _endian_encode(kv_header->id_counter);
527 : 13878 : memcpy((uint8_t*)*data + offset, &_id_counter, sizeof(_id_counter));
528 : 13878 : offset += sizeof(_id_counter);
529 : :
530 : 13878 : a = avl_first(kv_header->idx_name);
531 [ + + ]: 14967 : while(a) {
532 : 1089 : node = _get_entry(a, struct kvs_node, avl_name);
533 : :
534 : : // name length
535 : 1089 : name_len = strlen(node->kvs_name)+1;
536 : 1089 : _name_len = _endian_encode(name_len);
537 : 1089 : memcpy((uint8_t*)*data + offset, &_name_len, sizeof(_name_len));
538 : 1089 : offset += sizeof(_name_len);
539 : :
540 : : // name
541 : 1089 : memcpy((uint8_t*)*data + offset, node->kvs_name, name_len);
542 : 1089 : offset += name_len;
543 : :
544 : : // KV ID
545 : 1089 : _kv_id = _endian_encode(node->id);
546 : 1089 : memcpy((uint8_t*)*data + offset, &_kv_id, sizeof(_kv_id));
547 : 1089 : offset += sizeof(_kv_id);
548 : :
549 : : // seq number
550 : 1089 : _seqnum = _endian_encode(node->seqnum);
551 : 1089 : memcpy((uint8_t*)*data + offset, &_seqnum, sizeof(_seqnum));
552 : 1089 : offset += sizeof(_seqnum);
553 : :
554 : : // # live index nodes
555 : 1089 : _nlivenodes = _endian_encode(node->stat.nlivenodes);
556 : 1089 : memcpy((uint8_t*)*data + offset, &_nlivenodes, sizeof(_nlivenodes));
557 : 1089 : offset += sizeof(_nlivenodes);
558 : :
559 : : // # docs
560 : 1089 : _ndocs = _endian_encode(node->stat.ndocs);
561 : 1089 : memcpy((uint8_t*)*data + offset, &_ndocs, sizeof(_ndocs));
562 : 1089 : offset += sizeof(_ndocs);
563 : :
564 : : // datasize
565 : 1089 : _datasize = _endian_encode(node->stat.datasize);
566 : 1089 : memcpy((uint8_t*)*data + offset, &_datasize, sizeof(_datasize));
567 : 1089 : offset += sizeof(_datasize);
568 : :
569 : : // flags
570 : 1089 : _flags = _endian_encode(node->flags);
571 : 1089 : memcpy((uint8_t*)*data + offset, &_flags, sizeof(_flags));
572 : 1089 : offset += sizeof(_flags);
573 : :
574 : 1089 : a = avl_next(a);
575 : : }
576 : :
577 : 13878 : *len = size;
578 : :
579 : 13878 : spin_unlock(&kv_header->lock);
580 : : }
581 : :
582 : 223 : void _fdb_kvs_header_import(struct kvs_header *kv_header,
583 : : void *data, size_t len)
584 : : {
585 : 223 : int i, offset = 0;
586 : : uint16_t name_len, _name_len;
587 : : uint64_t n_kv, _n_kv, kv_id, _kv_id, flags, _flags;
588 : : uint64_t _nlivenodes, _ndocs, _datasize;
589 : : fdb_kvs_id_t id_counter, _id_counter;
590 : : fdb_seqnum_t seqnum, _seqnum;
591 : : struct kvs_node *node;
592 : :
593 : : // # KV instances
594 : 223 : memcpy(&_n_kv, (uint8_t*)data + offset, sizeof(_n_kv));
595 : 223 : offset += sizeof(_n_kv);
596 : 223 : n_kv = _endian_decode(_n_kv);
597 : :
598 : : // ID counter
599 : 223 : memcpy(&_id_counter, (uint8_t*)data + offset, sizeof(_id_counter));
600 : 223 : offset += sizeof(_id_counter);
601 : 223 : id_counter = _endian_decode(_id_counter);
602 : :
603 : 223 : spin_lock(&kv_header->lock);
604 : 223 : kv_header->id_counter = id_counter;
605 : :
606 [ + + ]: 376 : for (i=0;i<n_kv;++i){
607 : 153 : node = (struct kvs_node *)calloc(1, sizeof(struct kvs_node));
608 : :
609 : : // nname length
610 : 153 : memcpy(&_name_len, (uint8_t*)data + offset, sizeof(_name_len));
611 : 153 : offset += sizeof(_name_len);
612 : 153 : name_len = _endian_decode(_name_len);
613 : :
614 : : // name
615 : 153 : node->kvs_name = (char *)malloc(name_len);
616 : 153 : memcpy(node->kvs_name, (uint8_t*)data + offset, name_len);
617 : 153 : offset += name_len;
618 : :
619 : : // KV ID
620 : 153 : memcpy(&_kv_id, (uint8_t*)data + offset, sizeof(_kv_id));
621 : 153 : offset += sizeof(_kv_id);
622 : 153 : kv_id = _endian_decode(_kv_id);
623 : 153 : node->id = kv_id;
624 : :
625 : : // seq number
626 : 153 : memcpy(&_seqnum, (uint8_t*)data + offset, sizeof(_seqnum));
627 : 153 : offset += sizeof(_seqnum);
628 : 153 : seqnum = _endian_decode(_seqnum);
629 : 153 : node->seqnum = seqnum;
630 : :
631 : : // # live index nodes
632 : 153 : memcpy(&_nlivenodes, (uint8_t*)data + offset, sizeof(_nlivenodes));
633 : 153 : offset += sizeof(_nlivenodes);
634 : 153 : node->stat.nlivenodes = _endian_decode(_nlivenodes);
635 : :
636 : : // # docs
637 : 153 : memcpy(&_ndocs, (uint8_t*)data + offset, sizeof(_ndocs));
638 : 153 : offset += sizeof(_ndocs);
639 : 153 : node->stat.ndocs = _endian_decode(_ndocs);
640 : :
641 : : // datasize
642 : 153 : memcpy(&_datasize, (uint8_t*)data + offset, sizeof(_datasize));
643 : 153 : offset += sizeof(_datasize);
644 : 153 : node->stat.datasize = _endian_decode(_datasize);
645 : :
646 : : // flags
647 : 153 : memcpy(&_flags, (uint8_t*)data + offset, sizeof(_flags));
648 : 153 : offset += sizeof(_flags);
649 : 153 : flags = _endian_decode(_flags);
650 : 153 : node->flags = flags;
651 : :
652 : : // custom cmp function (in-memory attr)
653 : 153 : node->custom_cmp = NULL;
654 : :
655 : 153 : avl_insert(kv_header->idx_name, &node->avl_name, _kvs_cmp_name);
656 : 153 : avl_insert(kv_header->idx_id, &node->avl_id, _kvs_cmp_id);
657 : : }
658 : 223 : spin_unlock(&kv_header->lock);
659 : 223 : }
660 : :
661 : 13878 : uint64_t fdb_kvs_header_append(struct filemgr *file,
662 : : struct docio_handle *dhandle)
663 : : {
664 : 13878 : char *doc_key = alca(char, 32);
665 : : void *data;
666 : : size_t len;
667 : : uint64_t kv_info_offset;
668 : : struct docio_object doc;
669 : :
670 : 13878 : _fdb_kvs_header_export(file->kv_header, &data, &len);
671 : :
672 : 13878 : memset(&doc, 0, sizeof(struct docio_object));
673 : 13878 : sprintf(doc_key, "KV_header");
674 : 13878 : doc.key = (void *)doc_key;
675 : 13878 : doc.meta = NULL;
676 : 13878 : doc.body = data;
677 : 13878 : doc.length.keylen = strlen(doc_key) + 1;
678 : 13878 : doc.length.metalen = 0;
679 : 13878 : doc.length.bodylen = len;
680 : 13878 : doc.seqnum = 0;
681 : 13878 : kv_info_offset = docio_append_doc_system(dhandle, &doc);
682 : 13878 : free(data);
683 : :
684 : 13878 : return kv_info_offset;
685 : : }
686 : :
687 : 113 : void fdb_kvs_header_read(struct filemgr *file,
688 : : struct docio_handle *dhandle,
689 : : uint64_t kv_info_offset)
690 : : {
691 : : uint64_t offset;
692 : : struct docio_object doc;
693 : :
694 : 113 : memset(&doc, 0, sizeof(struct docio_object));
695 : 113 : offset = docio_read_doc(dhandle, kv_info_offset, &doc);
696 : :
697 [ - + ]: 113 : if (offset == kv_info_offset) {
698 : 113 : return;
699 : : }
700 : :
701 : 113 : _fdb_kvs_header_import(file->kv_header, doc.body, doc.length.bodylen);
702 : 113 : free_docio_object(&doc, 1, 1, 1);
703 : : }
704 : :
705 : 20424 : fdb_seqnum_t _fdb_kvs_get_seqnum(struct kvs_header *kv_header,
706 : : fdb_kvs_id_t id)
707 : : {
708 : : fdb_seqnum_t seqnum;
709 : : struct kvs_node query, *node;
710 : : struct avl_node *a;
711 : :
712 : 20424 : spin_lock(&kv_header->lock);
713 : 20424 : query.id = id;
714 : 20424 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_cmp_id);
715 [ + - ]: 20424 : if (a) {
716 : 20424 : node = _get_entry(a, struct kvs_node, avl_id);
717 : 20424 : seqnum = node->seqnum;
718 : : } else {
719 : : // not existing KV ID.
720 : : // this is necessary for _fdb_restore_wal()
721 : : // not to restore documents in deleted KV store.
722 : 0 : seqnum = 0;
723 : : }
724 : 20424 : spin_unlock(&kv_header->lock);
725 : :
726 : 20424 : return seqnum;
727 : : }
728 : :
729 : 23066 : fdb_seqnum_t fdb_kvs_get_seqnum(struct filemgr *file,
730 : : fdb_kvs_id_t id)
731 : : {
732 [ + + ]: 23066 : if (id == 0) {
733 : : // default KV instance
734 : 2948 : return filemgr_get_seqnum(file);
735 : : }
736 : :
737 : 23066 : return _fdb_kvs_get_seqnum(file->kv_header, id);
738 : : }
739 : :
740 : : LIBFDB_API
741 : 106 : fdb_status fdb_get_kvs_seqnum(fdb_kvs_handle *handle, fdb_seqnum_t *seqnum)
742 : : {
743 [ - + ]: 106 : if (!handle) {
744 : 0 : return FDB_RESULT_INVALID_HANDLE;
745 : : }
746 [ - + ]: 106 : if (!seqnum) {
747 : 0 : return FDB_RESULT_INVALID_ARGS;
748 : : }
749 : :
750 [ + + ]: 106 : if (handle->shandle) {
751 : : // handle for snapshot
752 : : // return MAX_SEQNUM instead of the file's sequence number
753 : 6 : *seqnum = handle->max_seqnum;
754 : : } else {
755 : 100 : fdb_check_file_reopen(handle);
756 : 100 : fdb_link_new_file(handle);
757 : 100 : fdb_sync_db_header(handle);
758 : :
759 [ + + ][ + + ]: 100 : if (handle->kvs == NULL ||
760 : : handle->kvs->id == 0) {
761 [ - + ]: 42 : if (handle->new_file) {
762 : 0 : filemgr_mutex_lock(handle->new_file);
763 : 0 : *seqnum = filemgr_get_seqnum(handle->new_file);
764 : 0 : filemgr_mutex_unlock(handle->new_file);
765 : : } else {
766 : 21 : filemgr_mutex_lock(handle->file);
767 : 21 : *seqnum = filemgr_get_seqnum(handle->file);
768 : 21 : filemgr_mutex_unlock(handle->file);
769 : : }
770 : : } else {
771 : 79 : *seqnum = fdb_kvs_get_seqnum(handle->file, handle->kvs->id);
772 : : }
773 : : }
774 : 106 : return FDB_RESULT_SUCCESS;
775 : : }
776 : :
777 : 17343 : void fdb_kvs_set_seqnum(struct filemgr *file,
778 : : fdb_kvs_id_t id,
779 : : fdb_seqnum_t seqnum)
780 : : {
781 : 17343 : struct kvs_header *kv_header = file->kv_header;
782 : : struct kvs_node query, *node;
783 : : struct avl_node *a;
784 : :
785 [ + + ]: 17343 : if (id == 0) {
786 : : // default KV instance
787 : 7 : filemgr_set_seqnum(file, seqnum);
788 : 17343 : return;
789 : : }
790 : :
791 : 17336 : spin_lock(&kv_header->lock);
792 : 17336 : query.id = id;
793 : 17336 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_cmp_id);
794 : 17336 : node = _get_entry(a, struct kvs_node, avl_id);
795 : 17336 : node->seqnum = seqnum;
796 : 17336 : spin_unlock(&kv_header->lock);
797 : : }
798 : :
799 : 335 : void _fdb_kvs_header_free(struct kvs_header *kv_header)
800 : : {
801 : : struct kvs_node *node;
802 : : struct avl_node *a;
803 : :
804 : 335 : a = avl_first(kv_header->idx_name);
805 [ + + ]: 587 : while (a) {
806 : 252 : node = _get_entry(a, struct kvs_node, avl_name);
807 : 252 : a = avl_next(a);
808 : 252 : avl_remove(kv_header->idx_name, &node->avl_name);
809 : :
810 : 252 : free(node->kvs_name);
811 : 252 : free(node);
812 : : }
813 : 335 : free(kv_header->idx_name);
814 : 335 : free(kv_header->idx_id);
815 : 335 : free(kv_header);
816 : 335 : }
817 : :
818 : 225 : void fdb_kvs_header_free(struct filemgr *file)
819 : : {
820 [ - + ]: 225 : if (file->kv_header == NULL) {
821 : 225 : return;
822 : : }
823 : :
824 : 225 : _fdb_kvs_header_free(file->kv_header);
825 : 225 : file->kv_header = NULL;
826 : : }
827 : :
828 : 105 : fdb_status _fdb_kvs_create(fdb_kvs_handle *root_handle,
829 : : const char *kvs_name,
830 : : fdb_kvs_config *kvs_config)
831 : : {
832 : : int kv_ins_name_len;
833 : 105 : fdb_status fs = FDB_RESULT_SUCCESS;
834 : : struct avl_node *a;
835 : : struct filemgr *file;
836 : : struct docio_handle *dhandle;
837 : : struct kvs_node *node, query;
838 : : struct kvs_header *kv_header;
839 : :
840 [ - + ]: 105 : if (root_handle->config.multi_kv_instances == false) {
841 : : // cannot open KV instance under single DB instance mode
842 : 0 : return FDB_RESULT_INVALID_CONFIG;
843 : : }
844 [ - + ]: 105 : if (root_handle->kvs->type != KVS_ROOT) {
845 : 0 : return FDB_RESULT_INVALID_HANDLE;
846 : : }
847 : :
848 : : fdb_kvs_create_start:
849 : 105 : fdb_check_file_reopen(root_handle);
850 : 105 : filemgr_mutex_lock(root_handle->file);
851 : 105 : fdb_sync_db_header(root_handle);
852 : 105 : fdb_link_new_file(root_handle);
853 : :
854 [ - + ]: 105 : if (filemgr_is_rollback_on(root_handle->file)) {
855 : 0 : filemgr_mutex_unlock(root_handle->file);
856 : 0 : return FDB_RESULT_FAIL_BY_ROLLBACK;
857 : : }
858 : :
859 [ + - ]: 105 : if (root_handle->new_file == NULL) {
860 : 105 : file = root_handle->file;
861 : 105 : dhandle = root_handle->dhandle;
862 : : } else {
863 : : // compaction is being performed and new file exists
864 : : // relay lock
865 : 0 : filemgr_mutex_lock(root_handle->new_file);
866 : 0 : filemgr_mutex_unlock(root_handle->file);
867 : 0 : file = root_handle->new_file;
868 : 0 : dhandle = root_handle->new_dhandle;
869 : : }
870 : :
871 [ - + ]: 105 : if (!(file->status == FILE_NORMAL ||
872 [ # # ]: 0 : file->status == FILE_COMPACT_NEW)) {
873 : : // we must not write into this file
874 : : // file status was changed by other thread .. start over
875 : 0 : filemgr_mutex_unlock(file);
876 : 0 : goto fdb_kvs_create_start;
877 : : }
878 : :
879 : 105 : kv_header = file->kv_header;
880 : 105 : spin_lock(&kv_header->lock);
881 : :
882 : : // find existing KV instance
883 : : // search by name
884 : 105 : query.kvs_name = (char*)kvs_name;
885 : 105 : a = avl_search(kv_header->idx_name, &query.avl_name, _kvs_cmp_name);
886 [ - + ]: 105 : if (a) { // KV name already exists
887 : 0 : spin_unlock(&kv_header->lock);
888 : 0 : filemgr_mutex_unlock(file);
889 : 0 : return FDB_RESULT_INVALID_KV_INSTANCE_NAME;
890 : : }
891 : :
892 : : // create a kvs_node and insert
893 : 105 : node = (struct kvs_node *)calloc(1, sizeof(struct kvs_node));
894 : 105 : node->id = kv_header->id_counter++;
895 : 105 : node->seqnum = 0;
896 : 105 : node->flags = 0x0;
897 : : // search fhandle's custom cmp func list first
898 : : node->custom_cmp = fdb_kvs_find_cmp_name(root_handle,
899 : 105 : (char *)kvs_name);
900 [ + + ][ + + ]: 105 : if (node->custom_cmp == NULL && kvs_config->custom_cmp) {
901 : : // follow kvs_config's custom cmp next
902 : 11 : node->custom_cmp = kvs_config->custom_cmp;
903 : : }
904 [ + + ]: 105 : if (node->custom_cmp) { // custom cmp function is used
905 : 15 : node->flags |= KVS_FLAG_CUSTOM_CMP;
906 : 15 : kv_header->custom_cmp_enabled = 1;
907 : : }
908 : 105 : kv_ins_name_len = strlen(kvs_name)+1;
909 : 105 : node->kvs_name = (char *)malloc(kv_ins_name_len);
910 : 105 : strcpy(node->kvs_name, kvs_name);
911 : :
912 : 105 : avl_insert(kv_header->idx_name, &node->avl_name, _kvs_cmp_name);
913 : 105 : avl_insert(kv_header->idx_id, &node->avl_id, _kvs_cmp_id);
914 : 105 : spin_unlock(&kv_header->lock);
915 : :
916 : : // sync dirty root nodes
917 : : bid_t dirty_idtree_root, dirty_seqtree_root;
918 : 105 : filemgr_get_dirty_root(root_handle->file, &dirty_idtree_root, &dirty_seqtree_root);
919 [ - + ]: 105 : if (dirty_idtree_root != BLK_NOT_FOUND) {
920 : 0 : root_handle->trie->root_bid = dirty_idtree_root;
921 : : }
922 [ + - ][ - + ]: 105 : if (root_handle->config.seqtree_opt == FDB_SEQTREE_USE &&
923 : : dirty_seqtree_root != BLK_NOT_FOUND) {
924 : 0 : root_handle->seqtree->root_bid = dirty_seqtree_root;
925 : : }
926 : :
927 : : // append system doc
928 : 105 : root_handle->kv_info_offset = fdb_kvs_header_append(file, dhandle);
929 : :
930 : : // if no compaction is being performed, append header and commit
931 [ + - ]: 105 : if (root_handle->file == file) {
932 : 105 : root_handle->cur_header_revnum = fdb_set_file_header(root_handle);
933 : 105 : fs = filemgr_commit(root_handle->file, &root_handle->log_callback);
934 : : }
935 : :
936 : 105 : filemgr_mutex_unlock(file);
937 : :
938 : 105 : return fs;
939 : : }
940 : :
941 : : // this function just returns pointer
942 : 50 : char* _fdb_kvs_get_name(fdb_kvs_handle *handle, struct filemgr *file)
943 : : {
944 : : struct kvs_node *node, query;
945 : : struct avl_node *a;
946 : :
947 : 50 : query.id = handle->kvs->id;
948 [ + + ]: 50 : if (query.id == 0) { // default KV instance
949 : 30 : return NULL;
950 : : }
951 : 20 : filemgr_mutex_lock(file);
952 : 20 : a = avl_search(file->kv_header->idx_id, &query.avl_id, _kvs_cmp_id);
953 [ + - ]: 20 : if (a) {
954 : 20 : node = _get_entry(a, struct kvs_node, avl_id);
955 : 20 : filemgr_mutex_unlock(file);
956 : 20 : return node->kvs_name;
957 : : }
958 : 0 : filemgr_mutex_unlock(file);
959 : 50 : return NULL;
960 : : }
961 : :
962 : 223 : fdb_status _fdb_kvs_open(fdb_kvs_handle *root_handle,
963 : : fdb_config *config,
964 : : fdb_kvs_config *kvs_config,
965 : : struct filemgr *file,
966 : : const char *kvs_name,
967 : : fdb_kvs_handle *handle)
968 : : {
969 : : fdb_status fs;
970 : :
971 [ + - ]: 223 : if (handle->kvs == NULL) {
972 : : // create kvs_info
973 : 223 : filemgr_mutex_lock(file);
974 : 223 : fdb_kvs_info_create(root_handle, handle, file, kvs_name);
975 : 223 : filemgr_mutex_unlock(file);
976 : : }
977 : :
978 [ + + ]: 223 : if (handle->kvs == NULL) {
979 : : // KV instance name is not found
980 [ + + ]: 107 : if (!kvs_config->create_if_missing) {
981 : 2 : return FDB_RESULT_INVALID_KV_INSTANCE_NAME;
982 : : }
983 [ - + ]: 105 : if (root_handle->config.flags == FDB_OPEN_FLAG_RDONLY) {
984 : 0 : return FDB_RESULT_RONLY_VIOLATION;
985 : : }
986 : :
987 : : // create
988 : 105 : fs = _fdb_kvs_create(root_handle, kvs_name, kvs_config);
989 [ - + ]: 105 : if (fs != FDB_RESULT_SUCCESS) { // create fail
990 : 0 : return FDB_RESULT_INVALID_KV_INSTANCE_NAME;
991 : : }
992 : : // create kvs_info again
993 : 105 : filemgr_mutex_lock(file);
994 : 105 : fdb_kvs_info_create(root_handle, handle, file, kvs_name);
995 : 105 : filemgr_mutex_unlock(file);
996 [ - + ]: 105 : if (handle->kvs == NULL) { // fail again
997 : 0 : return FDB_RESULT_INVALID_KV_INSTANCE_NAME;
998 : : }
999 : : }
1000 : 221 : fs = _fdb_open(handle, file->filename, config);
1001 [ + + ]: 221 : if (fs != FDB_RESULT_SUCCESS) {
1002 [ + - ]: 1 : if (handle->node) {
1003 : 1 : spin_lock(&root_handle->fhandle->lock);
1004 : 1 : list_remove(root_handle->fhandle->handles, &handle->node->le);
1005 : 1 : spin_unlock(&root_handle->fhandle->lock);
1006 : 1 : free(handle->node);
1007 : : } // 'handle->node == NULL' happens only during rollback
1008 : 1 : free(handle->kvs);
1009 : : }
1010 : 223 : return fs;
1011 : : }
1012 : :
1013 : : LIBFDB_API
1014 : 394 : fdb_status fdb_kvs_open(fdb_file_handle *fhandle,
1015 : : fdb_kvs_handle **ptr_handle,
1016 : : const char *kvs_name,
1017 : : fdb_kvs_config *kvs_config)
1018 : : {
1019 : : fdb_kvs_handle *handle;
1020 : : fdb_config config;
1021 : : fdb_status fs;
1022 : : fdb_kvs_handle *root_handle;
1023 : : fdb_kvs_config config_local;
1024 : 394 : struct filemgr *file = NULL;
1025 : :
1026 [ - + ]: 394 : if (!fhandle) {
1027 : 0 : return FDB_RESULT_INVALID_HANDLE;
1028 : : }
1029 : 394 : root_handle = fhandle->root;
1030 : 394 : config = root_handle->config;
1031 : :
1032 [ + - ]: 394 : if (kvs_config) {
1033 [ + - ]: 394 : if (validate_fdb_kvs_config(kvs_config)) {
1034 : 394 : config_local = *kvs_config;
1035 : : } else {
1036 : 0 : return FDB_RESULT_INVALID_CONFIG;
1037 : : }
1038 : : } else {
1039 : 0 : config_local = get_default_kvs_config();
1040 : : }
1041 : :
1042 : 394 : fdb_check_file_reopen(root_handle);
1043 : 394 : fdb_link_new_file(root_handle);
1044 : 394 : fdb_sync_db_header(root_handle);
1045 [ + - ]: 394 : if (root_handle->new_file == NULL) {
1046 : 394 : file = root_handle->file;
1047 : : } else{
1048 : 0 : file = root_handle->new_file;
1049 : : }
1050 : :
1051 [ + + ][ + + ]: 394 : if (kvs_name == NULL || !strcmp(kvs_name, default_kvs_name)) {
1052 : : // return the default KV store handle
1053 : 221 : spin_lock(&fhandle->lock);
1054 [ + + ]: 221 : if (!(fhandle->flags & FHANDLE_ROOT_OPENED)) {
1055 : : // the root handle is not opened yet
1056 : : // just return the root handle
1057 : : fdb_custom_cmp_variable default_kvs_cmp;
1058 : :
1059 : 218 : root_handle->kvs_config = config_local;
1060 : :
1061 [ + + ]: 218 : if (root_handle->file->kv_header) {
1062 : : // search fhandle's custom cmp func list first
1063 : 214 : default_kvs_cmp = fdb_kvs_find_cmp_name(root_handle, (char *)kvs_name);
1064 : :
1065 : 214 : spin_lock(&root_handle->file->kv_header->lock);
1066 : 214 : root_handle->file->kv_header->default_kvs_cmp = default_kvs_cmp;
1067 : :
1068 [ + + ][ + + ]: 214 : if (root_handle->file->kv_header->default_kvs_cmp == NULL &&
1069 : : root_handle->kvs_config.custom_cmp) {
1070 : : // follow kvs_config's custom cmp next
1071 : : root_handle->file->kv_header->default_kvs_cmp =
1072 : 7 : root_handle->kvs_config.custom_cmp;
1073 : : }
1074 : :
1075 [ + + ]: 214 : if (root_handle->file->kv_header->default_kvs_cmp) {
1076 : 19 : root_handle->file->kv_header->custom_cmp_enabled = 1;
1077 : 19 : fhandle->flags |= FHANDLE_ROOT_CUSTOM_CMP;
1078 : : }
1079 : 214 : spin_unlock(&root_handle->file->kv_header->lock);
1080 : : }
1081 : :
1082 : 218 : *ptr_handle = root_handle;
1083 : 218 : fhandle->flags |= FHANDLE_ROOT_INITIALIZED;
1084 : 218 : fhandle->flags |= FHANDLE_ROOT_OPENED;
1085 : 218 : fs = FDB_RESULT_SUCCESS;
1086 : 218 : spin_unlock(&fhandle->lock);
1087 : :
1088 : : } else {
1089 : : // the root handle is already opened
1090 : : // open new default KV store handle
1091 : 3 : spin_unlock(&fhandle->lock);
1092 : 3 : handle = (fdb_kvs_handle*)calloc(1, sizeof(fdb_kvs_handle));
1093 : 3 : handle->kvs_config = config_local;
1094 : :
1095 [ + - ]: 3 : if (root_handle->file->kv_header) {
1096 : 3 : spin_lock(&root_handle->file->kv_header->lock);
1097 : : handle->kvs_config.custom_cmp =
1098 : 3 : root_handle->file->kv_header->default_kvs_cmp;
1099 : 3 : spin_unlock(&root_handle->file->kv_header->lock);
1100 : : }
1101 : :
1102 : 3 : handle->fhandle = fhandle;
1103 : 3 : fs = _fdb_open(handle, file->filename, &config);
1104 [ - + ]: 3 : if (fs != FDB_RESULT_SUCCESS) {
1105 : 0 : free(handle);
1106 : 0 : *ptr_handle = NULL;
1107 : : } else {
1108 : : // insert into fhandle's list
1109 : : struct kvs_opened_node *node;
1110 : : node = (struct kvs_opened_node *)
1111 : 3 : calloc(1, sizeof(struct kvs_opened_node));
1112 : 3 : node->handle = handle;
1113 : 3 : spin_lock(&fhandle->lock);
1114 : 3 : list_push_front(fhandle->handles, &node->le);
1115 : 3 : spin_unlock(&fhandle->lock);
1116 : :
1117 : 3 : handle->node = node;
1118 : 3 : *ptr_handle = handle;
1119 : : }
1120 : : }
1121 : 221 : return fs;
1122 : : }
1123 : :
1124 [ - + ]: 173 : if (config.multi_kv_instances == false) {
1125 : : // cannot open KV instance under single DB instance mode
1126 : 0 : return FDB_RESULT_INVALID_CONFIG;
1127 : : }
1128 [ - + ]: 173 : if (root_handle->kvs->type != KVS_ROOT) {
1129 : 0 : return FDB_RESULT_INVALID_HANDLE;
1130 : : }
1131 [ - + ]: 173 : if (root_handle->shandle) {
1132 : : // cannot open KV instance from a snapshot
1133 : 0 : return FDB_RESULT_INVALID_ARGS;
1134 : : }
1135 : :
1136 : 173 : handle = (fdb_kvs_handle *)calloc(1, sizeof(fdb_kvs_handle));
1137 [ - + ]: 173 : if (!handle) {
1138 : 0 : return FDB_RESULT_ALLOC_FAIL;
1139 : : }
1140 : :
1141 : 173 : handle->fhandle = fhandle;
1142 : : fs = _fdb_kvs_open(root_handle, &config, &config_local,
1143 : 173 : file, kvs_name, handle);
1144 [ + + ]: 173 : if (fs == FDB_RESULT_SUCCESS) {
1145 : 171 : *ptr_handle = handle;
1146 : : } else {
1147 : 2 : *ptr_handle = NULL;
1148 : 2 : free(handle);
1149 : : }
1150 : 394 : return fs;
1151 : : }
1152 : :
1153 : : LIBFDB_API
1154 : 168 : fdb_status fdb_kvs_open_default(fdb_file_handle *fhandle,
1155 : : fdb_kvs_handle **ptr_handle,
1156 : : fdb_kvs_config *config)
1157 : : {
1158 : 168 : return fdb_kvs_open(fhandle, ptr_handle, NULL, config);
1159 : : }
1160 : :
1161 : 156 : fdb_status _fdb_kvs_close(fdb_kvs_handle *handle)
1162 : : {
1163 : 156 : fdb_kvs_handle *root_handle = handle->kvs->root;
1164 : : fdb_status fs;
1165 : :
1166 [ + + ]: 156 : if (handle->node) {
1167 : 149 : spin_lock(&root_handle->fhandle->lock);
1168 : 149 : list_remove(root_handle->fhandle->handles, &handle->node->le);
1169 : 149 : spin_unlock(&root_handle->fhandle->lock);
1170 : 149 : free(handle->node);
1171 : : } // 'handle->node == NULL' happens only during rollback
1172 : :
1173 : 156 : fs = _fdb_close(handle);
1174 : 156 : return fs;
1175 : : }
1176 : :
1177 : : // close all sub-KV store handles belonging to the root handle
1178 : 270 : fdb_status fdb_kvs_close_all(fdb_kvs_handle *root_handle)
1179 : : {
1180 : : fdb_status fs;
1181 : : struct list_elem *e;
1182 : : struct kvs_opened_node *node;
1183 : :
1184 : 270 : spin_lock(&root_handle->fhandle->lock);
1185 : 270 : e = list_begin(root_handle->fhandle->handles);
1186 [ + + ]: 343 : while (e) {
1187 : 73 : node = _get_entry(e, struct kvs_opened_node, le);
1188 : 73 : e = list_remove(root_handle->fhandle->handles, &node->le);
1189 : 73 : fs = _fdb_close(node->handle);
1190 [ - + ]: 73 : if (fs != FDB_RESULT_SUCCESS) {
1191 : 0 : spin_unlock(&root_handle->fhandle->lock);
1192 : 0 : return fs;
1193 : : }
1194 : 73 : fdb_kvs_info_free(node->handle);
1195 : 73 : free(node->handle);
1196 : 73 : free(node);
1197 : : }
1198 : 270 : spin_unlock(&root_handle->fhandle->lock);
1199 : :
1200 : 270 : return FDB_RESULT_SUCCESS;
1201 : : }
1202 : :
1203 : : LIBFDB_API
1204 : 261 : fdb_status fdb_kvs_close(fdb_kvs_handle *handle)
1205 : : {
1206 : : fdb_status fs;
1207 : :
1208 [ - + ]: 261 : if (!handle) {
1209 : 0 : return FDB_RESULT_INVALID_HANDLE;
1210 : : }
1211 : :
1212 [ + + ][ - + ]: 261 : if (handle->shandle && handle->kvs == NULL) {
1213 : : // snapshot of the default KV store + single KV store mode
1214 : : // directly close handle
1215 : : // (snapshot of the other KV stores will be closed
1216 : : // using _fdb_kvs_close(...) below)
1217 : 0 : fs = _fdb_close(handle);
1218 [ # # ]: 0 : if (fs == FDB_RESULT_SUCCESS) {
1219 : 0 : free(handle);
1220 : : }
1221 : 0 : return fs;
1222 : : }
1223 : :
1224 [ + + ][ + + ]: 261 : if (handle->kvs == NULL ||
1225 : : handle->kvs->type == KVS_ROOT) {
1226 : : // the default KV store handle
1227 : :
1228 [ + + ]: 127 : if (handle->fhandle->root == handle) {
1229 : : // do nothing for root handle
1230 : : // the root handle will be closed with fdb_close() API call.
1231 : 126 : spin_lock(&handle->fhandle->lock);
1232 : 126 : handle->fhandle->flags &= ~FHANDLE_ROOT_OPENED; // remove flag
1233 : 126 : spin_unlock(&handle->fhandle->lock);
1234 : 126 : return FDB_RESULT_SUCCESS;
1235 : :
1236 : : } else {
1237 : : // the default KV store but not the root handle .. normally close
1238 : 1 : spin_lock(&handle->fhandle->lock);
1239 : 1 : fs = _fdb_close(handle);
1240 [ + - ]: 1 : if (fs == FDB_RESULT_SUCCESS) {
1241 : : // remove from 'handles' list in the root node
1242 [ + - ]: 1 : if (handle->kvs) {
1243 : 1 : fdb_kvs_info_free(handle);
1244 : : }
1245 : 1 : list_remove(handle->fhandle->handles, &handle->node->le);
1246 : 1 : spin_unlock(&handle->fhandle->lock);
1247 : 1 : free(handle->node);
1248 : 1 : free(handle);
1249 : : } else {
1250 : 0 : spin_unlock(&handle->fhandle->lock);
1251 : : }
1252 : 1 : return fs;
1253 : : }
1254 : : }
1255 : :
1256 [ + - ][ - + ]: 134 : if (handle->kvs && handle->kvs->root == NULL) {
1257 : 0 : return FDB_RESULT_INVALID_ARGS;
1258 : : }
1259 : 134 : fs = _fdb_kvs_close(handle);
1260 [ + - ]: 134 : if (fs == FDB_RESULT_SUCCESS) {
1261 : 134 : fdb_kvs_info_free(handle);
1262 : 134 : free(handle);
1263 : : }
1264 : 261 : return fs;
1265 : : }
1266 : :
1267 : 25 : fdb_status fdb_kvs_rollback(fdb_kvs_handle **handle_ptr, fdb_seqnum_t seqnum)
1268 : : {
1269 : : fdb_config config;
1270 : : fdb_kvs_config kvs_config;
1271 : : fdb_kvs_handle *handle_in, *handle, *super_handle;
1272 : : fdb_status fs;
1273 : : fdb_seqnum_t old_seqnum;
1274 : :
1275 [ + - ][ - + ]: 25 : if (!handle_ptr || !seqnum) {
1276 : 0 : return FDB_RESULT_INVALID_ARGS;
1277 : : }
1278 : :
1279 : 25 : handle_in = *handle_ptr;
1280 [ - + ]: 25 : if (!handle_in->kvs) {
1281 : 0 : return FDB_RESULT_INVALID_ARGS;
1282 : : }
1283 : 25 : super_handle = handle_in->kvs->root;
1284 : 25 : config = handle_in->config;
1285 : 25 : kvs_config = handle_in->kvs_config;
1286 : :
1287 : : // Sequence trees are a must for rollback
1288 [ - + ]: 25 : if (handle_in->config.seqtree_opt != FDB_SEQTREE_USE) {
1289 : 0 : return FDB_RESULT_INVALID_CONFIG;
1290 : : }
1291 : :
1292 [ - + ]: 25 : if (handle_in->config.flags & FDB_OPEN_FLAG_RDONLY) {
1293 : : return fdb_log(&handle_in->log_callback,
1294 : : FDB_RESULT_RONLY_VIOLATION,
1295 : : "Warning: Rollback is not allowed on "
1296 : : "the read-only DB file '%s'.",
1297 : 0 : handle_in->file->filename);
1298 : : }
1299 : :
1300 : : // if the max sequence number seen by this handle is lower than the
1301 : : // requested snapshot marker, it means the snapshot is not yet visible
1302 : : // even via the current fdb_kvs_handle
1303 [ + + ]: 25 : if (seqnum > handle_in->seqnum) {
1304 : 2 : return FDB_RESULT_NO_DB_INSTANCE;
1305 : : }
1306 : :
1307 : 23 : handle = (fdb_kvs_handle *) calloc(1, sizeof(fdb_kvs_handle));
1308 [ - + ]: 23 : if (!handle) {
1309 : 0 : return FDB_RESULT_ALLOC_FAIL;
1310 : : }
1311 : :
1312 : 23 : filemgr_mutex_lock(handle_in->file);
1313 : 23 : filemgr_set_rollback(handle_in->file, 1); // disallow writes operations
1314 : : // All transactions should be closed before rollback
1315 [ + + ]: 23 : if (wal_txn_exists(handle_in->file)) {
1316 : 1 : filemgr_set_rollback(handle_in->file, 0);
1317 : 1 : filemgr_mutex_unlock(handle_in->file);
1318 : 1 : free(handle);
1319 : 1 : return FDB_RESULT_FAIL_BY_TRANSACTION;
1320 : : }
1321 : : // There should be no compaction on the file
1322 [ - + ]: 22 : if (filemgr_get_file_status(handle_in->file) != FILE_NORMAL) {
1323 : 0 : filemgr_set_rollback(handle_in->file, 0);
1324 : 0 : filemgr_mutex_unlock(handle_in->file);
1325 : 0 : free(handle);
1326 : 0 : return FDB_RESULT_FAIL_BY_COMPACTION;
1327 : : }
1328 : 22 : filemgr_mutex_unlock(handle_in->file);
1329 : :
1330 : 22 : handle->log_callback = handle_in->log_callback;
1331 : 22 : handle->max_seqnum = seqnum;
1332 : 22 : handle->fhandle = handle_in->fhandle;
1333 : :
1334 [ + + ]: 22 : if (handle_in->kvs->type == KVS_SUB) {
1335 : : fs = _fdb_kvs_open(handle_in->kvs->root,
1336 : : &config,
1337 : : &kvs_config,
1338 : : handle_in->file,
1339 : : _fdb_kvs_get_name(handle_in,
1340 : 15 : handle_in->file),
1341 : 15 : handle);
1342 : : } else {
1343 : 7 : fs = _fdb_open(handle, handle_in->file->filename, &config);
1344 : : }
1345 : 22 : filemgr_set_rollback(handle_in->file, 0); // allow mutations
1346 : :
1347 [ + - ]: 22 : if (fs == FDB_RESULT_SUCCESS) {
1348 : : // get KV instance's sub B+trees' root node BIDs
1349 : : // from both ID-tree and Seq-tree, AND
1350 : : // replace current handle's sub B+trees' root node BIDs
1351 : : // by old BIDs
1352 : : bid_t id_root, seq_root, dummy;
1353 : : fdb_kvs_id_t _kv_id;
1354 : : hbtrie_result hr;
1355 : :
1356 : 22 : filemgr_mutex_lock(handle_in->file);
1357 : :
1358 : 22 : _kv_id = _endian_encode(handle->kvs->id);
1359 : :
1360 : : // read root BID of the KV instance from the old handle
1361 : : // and overwrite into the current handle
1362 : : hr = hbtrie_find_partial(handle->trie, &_kv_id,
1363 : 22 : sizeof(fdb_kvs_id_t), &id_root);
1364 : 22 : btreeblk_end(handle->bhandle);
1365 [ + + ]: 22 : if (hr == HBTRIE_RESULT_SUCCESS) {
1366 : : hr = hbtrie_insert_partial(super_handle->trie,
1367 : : &_kv_id, sizeof(fdb_kvs_id_t),
1368 : 19 : &id_root, &dummy);
1369 : 19 : btreeblk_end(super_handle->bhandle);
1370 : : }
1371 : :
1372 : : // same as above for seq-trie
1373 : : hr = hbtrie_find_partial(handle->seqtrie, &_kv_id,
1374 : 22 : sizeof(fdb_kvs_id_t), &seq_root);
1375 : 22 : btreeblk_end(handle->bhandle);
1376 [ + + ]: 22 : if (hr == HBTRIE_RESULT_SUCCESS) {
1377 : : hr = hbtrie_insert_partial(super_handle->seqtrie,
1378 : : &_kv_id, sizeof(fdb_kvs_id_t),
1379 : 19 : &seq_root, &dummy);
1380 : 19 : btreeblk_end(super_handle->bhandle);
1381 : : }
1382 : :
1383 : : old_seqnum = fdb_kvs_get_seqnum(handle_in->file,
1384 : 22 : handle_in->kvs->id);
1385 : : fdb_kvs_set_seqnum(handle_in->file,
1386 : 22 : handle_in->kvs->id, seqnum);
1387 : 22 : handle_in->seqnum = seqnum;
1388 : 22 : filemgr_mutex_unlock(handle_in->file);
1389 : :
1390 : 22 : fs = _fdb_commit(super_handle, FDB_COMMIT_NORMAL);
1391 [ + - ]: 22 : if (fs == FDB_RESULT_SUCCESS) {
1392 : 22 : _fdb_kvs_close(handle);
1393 : 22 : *handle_ptr = handle_in;
1394 : 22 : fdb_kvs_info_free(handle);
1395 : 22 : free(handle);
1396 : : } else {
1397 : : // cancel the rolling-back of the sequence number
1398 : 0 : filemgr_mutex_lock(handle_in->file);
1399 : : fdb_kvs_set_seqnum(handle_in->file,
1400 : 0 : handle_in->kvs->id, old_seqnum);
1401 : 0 : filemgr_mutex_unlock(handle_in->file);
1402 : 0 : _fdb_kvs_close(handle);
1403 : 0 : fdb_kvs_info_free(handle);
1404 : 0 : free(handle);
1405 : : }
1406 : : } else {
1407 : 0 : free(handle);
1408 : : }
1409 : :
1410 : 25 : return fs;
1411 : : }
1412 : :
1413 : : LIBFDB_API
1414 : 10 : fdb_status fdb_kvs_remove(fdb_file_handle *fhandle,
1415 : : const char *kvs_name)
1416 : : {
1417 : 10 : fdb_status fs = FDB_RESULT_SUCCESS;
1418 : : fdb_kvs_id_t kv_id, _kv_id;
1419 : : fdb_kvs_handle *root_handle;
1420 : 10 : struct avl_node *a = NULL;
1421 : : struct list_elem *e;
1422 : : struct filemgr *file;
1423 : : struct docio_handle *dhandle;
1424 : : struct kvs_node *node, query;
1425 : : struct kvs_header *kv_header;
1426 : : struct kvs_opened_node *opened_node;
1427 : :
1428 [ - + ]: 10 : if (!fhandle) {
1429 : 0 : return FDB_RESULT_INVALID_HANDLE;
1430 : : }
1431 : 10 : root_handle = fhandle->root;
1432 : :
1433 [ - + ]: 10 : if (root_handle->config.multi_kv_instances == false) {
1434 : : // cannot remove the KV instance under single DB instance mode
1435 : 0 : return FDB_RESULT_INVALID_CONFIG;
1436 : : }
1437 [ - + ]: 10 : if (root_handle->kvs->type != KVS_ROOT) {
1438 : 0 : return FDB_RESULT_INVALID_HANDLE;
1439 : : }
1440 : :
1441 : : fdb_kvs_remove_start:
1442 : 10 : fdb_check_file_reopen(root_handle);
1443 : 10 : filemgr_mutex_lock(root_handle->file);
1444 : 10 : fdb_sync_db_header(root_handle);
1445 : 10 : fdb_link_new_file(root_handle);
1446 : :
1447 [ - + ]: 10 : if (filemgr_is_rollback_on(root_handle->file)) {
1448 : 0 : filemgr_mutex_unlock(root_handle->file);
1449 : 0 : return FDB_RESULT_FAIL_BY_ROLLBACK;
1450 : : }
1451 : :
1452 [ + - ]: 10 : if (root_handle->new_file == NULL) {
1453 : 10 : file = root_handle->file;
1454 : 10 : dhandle = root_handle->dhandle;
1455 : : } else {
1456 : : // compaction is being performed and new file exists
1457 : : // relay lock
1458 : 0 : filemgr_mutex_lock(root_handle->new_file);
1459 : 0 : filemgr_mutex_unlock(root_handle->file);
1460 : 0 : file = root_handle->new_file;
1461 : 0 : dhandle = root_handle->new_dhandle;
1462 : : }
1463 : :
1464 [ - + ]: 10 : if (!(file->status == FILE_NORMAL ||
1465 [ # # ]: 0 : file->status == FILE_COMPACT_NEW)) {
1466 : : // we must not write into this file
1467 : : // file status was changed by other thread .. start over
1468 : 0 : filemgr_mutex_unlock(file);
1469 : 0 : goto fdb_kvs_remove_start;
1470 : : }
1471 : :
1472 : : // find the kvs_node and remove
1473 : :
1474 : : // search by name to get ID
1475 : 10 : spin_lock(&root_handle->fhandle->lock);
1476 : :
1477 [ + - ][ + + ]: 10 : if (kvs_name == NULL || !strcmp(kvs_name, default_kvs_name)) {
1478 : : // default KV store .. KV ID = 0
1479 : 2 : kv_id = _kv_id = 0;
1480 : 2 : e = list_begin(root_handle->fhandle->handles);
1481 [ - + ]: 2 : while (e) {
1482 : 0 : opened_node = _get_entry(e, struct kvs_opened_node, le);
1483 [ # # ][ # # ]: 0 : if ((opened_node->handle->kvs &&
[ # # ]
1484 : : opened_node->handle->kvs->id == kv_id) ||
1485 : : opened_node->handle->kvs == NULL) // single KV instance mode
1486 : : {
1487 : : // there is an opened handle
1488 : 0 : spin_unlock(&root_handle->fhandle->lock);
1489 : 0 : filemgr_mutex_unlock(file);
1490 : 0 : return FDB_RESULT_KV_STORE_BUSY;
1491 : : }
1492 : 0 : e = list_next(e);
1493 : : }
1494 : 2 : spin_unlock(&root_handle->fhandle->lock);
1495 : :
1496 : : } else {
1497 : 8 : kv_header = file->kv_header;
1498 : 8 : spin_lock(&kv_header->lock);
1499 : 8 : query.kvs_name = (char*)kvs_name;
1500 : 8 : a = avl_search(kv_header->idx_name, &query.avl_name, _kvs_cmp_name);
1501 [ - + ]: 8 : if (a == NULL) { // KV name doesn't exist
1502 : 0 : spin_unlock(&kv_header->lock);
1503 : 0 : spin_unlock(&root_handle->fhandle->lock);
1504 : 0 : filemgr_mutex_unlock(file);
1505 : 0 : return FDB_RESULT_KV_STORE_NOT_FOUND;
1506 : : }
1507 : 8 : node = _get_entry(a, struct kvs_node, avl_name);
1508 : 8 : kv_id = node->id;
1509 : :
1510 : 8 : e = list_begin(root_handle->fhandle->handles);
1511 [ + + ]: 11 : while (e) {
1512 : 5 : opened_node = _get_entry(e, struct kvs_opened_node, le);
1513 [ + - ][ + + ]: 5 : if (opened_node->handle->kvs &&
1514 : : opened_node->handle->kvs->id == kv_id) {
1515 : : // there is an opened handle
1516 : 2 : spin_unlock(&kv_header->lock);
1517 : 2 : spin_unlock(&root_handle->fhandle->lock);
1518 : 2 : filemgr_mutex_unlock(file);
1519 : 2 : return FDB_RESULT_KV_STORE_BUSY;
1520 : : }
1521 : 3 : e = list_next(e);
1522 : : }
1523 : :
1524 : 6 : avl_remove(kv_header->idx_name, &node->avl_name);
1525 : 6 : avl_remove(kv_header->idx_id, &node->avl_id);
1526 : 6 : spin_unlock(&kv_header->lock);
1527 : 6 : spin_unlock(&root_handle->fhandle->lock);
1528 : :
1529 : 6 : kv_id = node->id;
1530 : 6 : _kv_id = _endian_encode(kv_id);
1531 : :
1532 : : // free node
1533 : 6 : free(node->kvs_name);
1534 : 6 : free(node);
1535 : : }
1536 : :
1537 : : // sync dirty root nodes
1538 : : bid_t dirty_idtree_root, dirty_seqtree_root;
1539 : 8 : filemgr_get_dirty_root(root_handle->file, &dirty_idtree_root, &dirty_seqtree_root);
1540 [ + + ]: 8 : if (dirty_idtree_root != BLK_NOT_FOUND) {
1541 : 1 : root_handle->trie->root_bid = dirty_idtree_root;
1542 : : }
1543 [ + - ][ + + ]: 8 : if (root_handle->config.seqtree_opt == FDB_SEQTREE_USE &&
1544 : : dirty_seqtree_root != BLK_NOT_FOUND) {
1545 : 1 : root_handle->seqtree->root_bid = dirty_seqtree_root;
1546 : : }
1547 : :
1548 : : // remove from super handle's HB+trie
1549 : 8 : hbtrie_remove_partial(root_handle->trie, &_kv_id, sizeof(_kv_id));
1550 : 8 : btreeblk_end(root_handle->bhandle);
1551 [ + - ]: 8 : if (root_handle->config.seqtree_opt == FDB_SEQTREE_USE) {
1552 : 8 : hbtrie_remove_partial(root_handle->seqtrie, &_kv_id, sizeof(_kv_id));
1553 : 8 : btreeblk_end(root_handle->bhandle);
1554 : : }
1555 : :
1556 : : // append system doc
1557 : 8 : root_handle->kv_info_offset = fdb_kvs_header_append(file, dhandle);
1558 : :
1559 : : // if no compaction is being performed, append header and commit
1560 [ + - ]: 8 : if (root_handle->file == file) {
1561 : 8 : root_handle->cur_header_revnum = fdb_set_file_header(root_handle);
1562 : 8 : fs = filemgr_commit(root_handle->file, &root_handle->log_callback);
1563 : : }
1564 : :
1565 : 8 : filemgr_mutex_unlock(file);
1566 : :
1567 : 10 : return fs;
1568 : : }
1569 : :
1570 : : LIBFDB_API
1571 : 76 : fdb_status fdb_get_kvs_info(fdb_kvs_handle *handle, fdb_kvs_info *info)
1572 : : {
1573 : : uint64_t ndocs;
1574 : : uint64_t wal_docs;
1575 : : uint64_t wal_deletes;
1576 : : uint64_t wal_n_inserts;
1577 : : uint64_t datasize;
1578 : : uint64_t nlivenodes;
1579 : : fdb_kvs_id_t kv_id;
1580 : : struct avl_node *a;
1581 : : struct kvs_node *node, query;
1582 : : struct kvs_header *kv_header;
1583 : : struct kvs_stat stat;
1584 : :
1585 [ + - ][ - + ]: 76 : if (!handle || !info) {
1586 : 0 : return FDB_RESULT_INVALID_ARGS;
1587 : : }
1588 : :
1589 [ + + ]: 76 : if (handle->kvs == NULL) {
1590 : 1 : info->name = default_kvs_name;
1591 : 1 : kv_id = 0;
1592 : :
1593 : : } else {
1594 : 75 : kv_header = handle->file->kv_header;
1595 : 75 : kv_id = handle->kvs->id;
1596 : 75 : spin_lock(&kv_header->lock);
1597 : :
1598 : 75 : query.id = handle->kvs->id;
1599 : 75 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_cmp_id);
1600 [ + + ]: 75 : if (a) { // sub handle
1601 : 51 : node = _get_entry(a, struct kvs_node, avl_id);
1602 : 51 : info->name = (const char*)node->kvs_name;
1603 : : } else { // root handle
1604 : 24 : info->name = default_kvs_name;
1605 : : }
1606 : 75 : spin_unlock(&kv_header->lock);
1607 : : }
1608 : :
1609 [ + + ]: 76 : if (handle->shandle) {
1610 : : // snapshot .. get its local stats
1611 : 6 : snap_get_stat(handle->shandle, &stat);
1612 : : } else {
1613 : 70 : _kvs_stat_get(handle->file, kv_id, &stat);
1614 : : }
1615 : 76 : ndocs = stat.ndocs;
1616 : 76 : wal_docs = stat.wal_ndocs;
1617 : 76 : wal_deletes = stat.wal_ndeletes;
1618 : 76 : wal_n_inserts = wal_docs - wal_deletes;
1619 : :
1620 [ + + ]: 76 : if (ndocs + wal_n_inserts < wal_deletes) {
1621 : 1 : info->doc_count = 0;
1622 : : } else {
1623 [ + + ]: 75 : if (ndocs) {
1624 : 58 : info->doc_count = ndocs + wal_n_inserts - wal_deletes;
1625 : : } else {
1626 : 17 : info->doc_count = wal_n_inserts;
1627 : : }
1628 : : }
1629 : :
1630 : 76 : datasize = stat.datasize;
1631 : 76 : nlivenodes = stat.nlivenodes;
1632 : :
1633 : 76 : info->space_used = datasize;
1634 : 76 : info->space_used += nlivenodes * handle->config.blocksize;
1635 : :
1636 : 76 : fdb_get_kvs_seqnum(handle, &info->last_seqnum);
1637 : :
1638 : 76 : info->file = handle->fhandle;
1639 : 76 : return FDB_RESULT_SUCCESS;
1640 : : }
1641 : :
1642 : : LIBFDB_API
1643 : 2 : fdb_status fdb_get_kvs_name_list(fdb_file_handle *fhandle,
1644 : : fdb_kvs_name_list *kvs_name_list)
1645 : : {
1646 : : size_t num, size, offset;
1647 : : char *ptr;
1648 : : char **segment;
1649 : : fdb_kvs_handle *root_handle;
1650 : : struct kvs_header *kv_header;
1651 : : struct kvs_node *node;
1652 : : struct avl_node *a;
1653 : :
1654 [ + - ][ - + ]: 2 : if (!fhandle || !kvs_name_list) {
1655 : 0 : return FDB_RESULT_INVALID_ARGS;
1656 : : }
1657 : :
1658 : 2 : root_handle = fhandle->root;
1659 [ - + ]: 2 : if (root_handle->new_file) {
1660 : 0 : kv_header = root_handle->new_file->kv_header;
1661 : : } else {
1662 : 2 : kv_header = root_handle->file->kv_header;
1663 : : }
1664 : :
1665 : 2 : spin_lock(&kv_header->lock);
1666 : : // sum all lengths of KVS names first
1667 : : // (to calculate the size of memory segment to be allocated)
1668 : 2 : num = 1;
1669 : 2 : size = strlen(default_kvs_name) + 1;
1670 : 2 : a = avl_first(kv_header->idx_id);
1671 [ + + ]: 6 : while (a) {
1672 : 4 : node = _get_entry(a, struct kvs_node, avl_id);
1673 : 4 : a = avl_next(&node->avl_id);
1674 : :
1675 : 4 : num++;
1676 : 4 : size += strlen(node->kvs_name) + 1;
1677 : : }
1678 : 2 : size += num * sizeof(char*);
1679 : :
1680 : : // allocate memory segment
1681 : 2 : segment = (char**)calloc(1, size);
1682 : 2 : kvs_name_list->num_kvs_names = num;
1683 : 2 : kvs_name_list->kvs_names = segment;
1684 : :
1685 : 2 : ptr = (char*)segment + num * sizeof(char*);
1686 : 2 : offset = num = 0;
1687 : :
1688 : : // copy default KVS name
1689 : 2 : strcpy(ptr + offset, default_kvs_name);
1690 : 2 : segment[num] = ptr + offset;
1691 : 2 : num++;
1692 : 2 : offset += strlen(default_kvs_name) + 1;
1693 : :
1694 : : // copy the others
1695 : 2 : a = avl_first(kv_header->idx_name);
1696 [ + + ]: 6 : while (a) {
1697 : 4 : node = _get_entry(a, struct kvs_node, avl_name);
1698 : 4 : a = avl_next(&node->avl_name);
1699 : :
1700 : 4 : strcpy(ptr + offset, node->kvs_name);
1701 : 4 : segment[num] = ptr + offset;
1702 : :
1703 : 4 : num++;
1704 : 4 : offset += strlen(node->kvs_name) + 1;
1705 : : }
1706 : :
1707 : 2 : spin_unlock(&kv_header->lock);
1708 : :
1709 : 2 : return FDB_RESULT_SUCCESS;
1710 : : }
1711 : :
1712 : : LIBFDB_API
1713 : 2 : fdb_status fdb_free_kvs_name_list(fdb_kvs_name_list *kvs_name_list)
1714 : : {
1715 [ - + ]: 2 : if (!kvs_name_list) {
1716 : 0 : return FDB_RESULT_INVALID_ARGS;
1717 : : }
1718 : 2 : free(kvs_name_list->kvs_names);
1719 : 2 : kvs_name_list->kvs_names = NULL;
1720 : 2 : kvs_name_list->num_kvs_names = 0;
1721 : :
1722 : 2 : return FDB_RESULT_SUCCESS;
1723 : : }
|