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 <stdio.h>
19 : : #include <stdlib.h>
20 : : #include <string.h>
21 : : #include <fcntl.h>
22 : : #include <assert.h>
23 : : #include <sys/stat.h>
24 : : #include <stdarg.h>
25 : : #if !defined(WIN32) && !defined(_WIN32)
26 : : #include <sys/time.h>
27 : : #endif
28 : :
29 : : #include "filemgr.h"
30 : : #include "filemgr_ops.h"
31 : : #include "hash_functions.h"
32 : : #include "blockcache.h"
33 : : #include "wal.h"
34 : : #include "list.h"
35 : : #include "fdb_internal.h"
36 : : #include "time_utils.h"
37 : :
38 : : #include "memleak.h"
39 : :
40 : : #ifdef __DEBUG
41 : : #ifndef __DEBUG_FILEMGR
42 : : #undef DBG
43 : : #undef DBGCMD
44 : : #undef DBGSW
45 : : #define DBG(...)
46 : : #define DBGCMD(...)
47 : : #define DBGSW(n, ...)
48 : : #endif
49 : : #endif
50 : :
51 : : // NBUCKET must be power of 2
52 : : #define NBUCKET (1024)
53 : : #define FILEMGR_MAGIC (UINT64_C(0xdeadcafebeefbeef))
54 : :
55 : : // global static variables
56 : : #ifdef SPIN_INITIALIZER
57 : : static spin_t initial_lock = SPIN_INITIALIZER;
58 : : #else
59 : : static volatile unsigned int initial_lock_status = 0;
60 : : static spin_t initial_lock;
61 : : #endif
62 : :
63 : :
64 : : static volatile uint8_t filemgr_initialized = 0;
65 : : static struct filemgr_config global_config;
66 : : static struct hash hash;
67 : : static spin_t filemgr_openlock;
68 : :
69 : : struct temp_buf_item{
70 : : void *addr;
71 : : struct list_elem le;
72 : : };
73 : : static struct list temp_buf;
74 : : static spin_t temp_buf_lock;
75 : :
76 : : static void _filemgr_free_func(struct hash_elem *h);
77 : :
78 : 248 : static void spin_init_wrap(void *lock) {
79 : 248 : spin_init((spin_t*)lock);
80 : 248 : }
81 : :
82 : 247 : static void spin_destroy_wrap(void *lock) {
83 : 247 : spin_destroy((spin_t*)lock);
84 : 247 : }
85 : :
86 : 15333019 : static void spin_lock_wrap(void *lock) {
87 : 15333019 : spin_lock((spin_t*)lock);
88 : 15370980 : }
89 : :
90 : 15370980 : static void spin_unlock_wrap(void *lock) {
91 : 15370980 : spin_unlock((spin_t*)lock);
92 : 15370971 : }
93 : :
94 : 103 : static void mutex_init_wrap(void *lock) {
95 : 103 : mutex_init((mutex_t*)lock);
96 : 103 : }
97 : :
98 : 103 : static void mutex_destroy_wrap(void *lock) {
99 : 103 : mutex_destroy((mutex_t*)lock);
100 : 103 : }
101 : :
102 : 7685490 : static void mutex_lock_wrap(void *lock) {
103 : 7685490 : mutex_lock((mutex_t*)lock);
104 : 7685490 : }
105 : :
106 : 7685490 : static void mutex_unlock_wrap(void *lock) {
107 : 7685490 : mutex_unlock((mutex_t*)lock);
108 : 7685490 : }
109 : :
110 : 4263923 : static int _block_is_overlapped(void *pbid1, void *pis_writer1,
111 : : void *pbid2, void *pis_writer2,
112 : : void *aux)
113 : : {
114 : : (void)aux;
115 : : bid_t bid1, is_writer1, bid2, is_writer2;
116 : 4263923 : bid1 = *(bid_t*)pbid1;
117 : 4263923 : is_writer1 = *(bid_t*)pis_writer1;
118 : 4263923 : bid2 = *(bid_t*)pbid2;
119 : 4263923 : is_writer2 = *(bid_t*)pis_writer2;
120 : :
121 [ + + ]: 4263923 : if (bid1 != bid2) {
122 : : // not overlapped
123 : 4261913 : return 0;
124 : : } else {
125 : : // overlapped
126 [ + - ][ + - ]: 2010 : if (!is_writer1 && !is_writer2) {
127 : : // both are readers
128 : 2010 : return 0;
129 : : } else {
130 : 4263923 : return 1;
131 : : }
132 : : }
133 : : }
134 : :
135 : 8433 : fdb_status fdb_log(err_log_callback *log_callback,
136 : : fdb_status status,
137 : : const char *format, ...)
138 : : {
139 [ + + ][ + + ]: 8433 : if (log_callback && log_callback->callback) {
140 : : char msg[1024];
141 : : va_list args;
142 : 5 : va_start(args, format);
143 : 5 : vsprintf(msg, format, args);
144 : 5 : va_end(args);
145 : 5 : log_callback->callback(status, msg, log_callback->ctx_data);
146 : : }
147 : 8433 : return status;
148 : : }
149 : :
150 : 734455 : static void _log_errno_str(struct filemgr_ops *ops,
151 : : err_log_callback *log_callback,
152 : : fdb_status io_error,
153 : : const char *what,
154 : : const char *filename)
155 : : {
156 [ + + ]: 734455 : if (io_error < 0) {
157 : : char errno_msg[512];
158 : 7858 : ops->get_errno_str(errno_msg, 512);
159 : : fdb_log(log_callback, io_error,
160 : 7858 : "Error in %s on a database file '%s', %s", what, filename, errno_msg);
161 : : }
162 : 734455 : }
163 : :
164 : 1162 : uint32_t _file_hash(struct hash *hash, struct hash_elem *e)
165 : : {
166 : 1162 : struct filemgr *file = _get_entry(e, struct filemgr, e);
167 : 1162 : int len = strlen(file->filename);
168 : 1162 : return chksum(file->filename, len) & ((unsigned)(NBUCKET-1));
169 : : }
170 : :
171 : 629 : int _file_cmp(struct hash_elem *a, struct hash_elem *b)
172 : : {
173 : : struct filemgr *aa, *bb;
174 : 629 : aa = _get_entry(a, struct filemgr, e);
175 : 629 : bb = _get_entry(b, struct filemgr, e);
176 : 629 : return strcmp(aa->filename, bb->filename);
177 : : }
178 : :
179 : 754 : void filemgr_init(struct filemgr_config *config)
180 : : {
181 : : // global initialization
182 : : // initialized only once at first time
183 [ + + ]: 754 : if (!filemgr_initialized) {
184 : : #ifndef SPIN_INITIALIZER
185 : : // Note that only Windows passes through this routine
186 : : if (InterlockedCompareExchange(&initial_lock_status, 1, 0) == 0) {
187 : : // atomically initialize spin lock only once
188 : : spin_init(&initial_lock);
189 : : initial_lock_status = 2;
190 : : } else {
191 : : // the others .. wait until initializing 'initial_lock' is done
192 : : while (initial_lock_status != 2) {
193 : : Sleep(1);
194 : : }
195 : : }
196 : : #endif
197 : :
198 : 125 : spin_lock(&initial_lock);
199 [ + - ]: 125 : if (!filemgr_initialized) {
200 : 125 : global_config = *config;
201 : :
202 [ + + ]: 125 : if (global_config.ncacheblock > 0)
203 : 58 : bcache_init(global_config.ncacheblock, global_config.blocksize);
204 : :
205 : 125 : hash_init(&hash, NBUCKET, _file_hash, _file_cmp);
206 : :
207 : : // initialize temp buffer
208 : 125 : list_init(&temp_buf);
209 : 125 : spin_init(&temp_buf_lock);
210 : :
211 : : // initialize global lock
212 : 125 : spin_init(&filemgr_openlock);
213 : :
214 : : // set the initialize flag
215 : 125 : filemgr_initialized = 1;
216 : : }
217 : 125 : spin_unlock(&initial_lock);
218 : : }
219 : 754 : }
220 : :
221 : 224906 : void * _filemgr_get_temp_buf()
222 : : {
223 : : struct list_elem *e;
224 : : struct temp_buf_item *item;
225 : :
226 : 224906 : spin_lock(&temp_buf_lock);
227 : 224906 : e = list_pop_front(&temp_buf);
228 [ + + ]: 224906 : if (e) {
229 : 224781 : item = _get_entry(e, struct temp_buf_item, le);
230 : : }else{
231 : : void *addr;
232 : :
233 : 125 : malloc_align(addr, FDB_SECTOR_SIZE, global_config.blocksize + sizeof(struct temp_buf_item));
234 : :
235 : 125 : item = (struct temp_buf_item *)((uint8_t *) addr + global_config.blocksize);
236 : 125 : item->addr = addr;
237 : : }
238 : 224906 : spin_unlock(&temp_buf_lock);
239 : :
240 : 224906 : return item->addr;
241 : : }
242 : :
243 : 224906 : void _filemgr_release_temp_buf(void *buf)
244 : : {
245 : : struct temp_buf_item *item;
246 : :
247 : 224906 : spin_lock(&temp_buf_lock);
248 : 224906 : item = (struct temp_buf_item*)((uint8_t *)buf + global_config.blocksize);
249 : 224906 : list_push_front(&temp_buf, &item->le);
250 : 224906 : spin_unlock(&temp_buf_lock);
251 : 224906 : }
252 : :
253 : 123 : void _filemgr_shutdown_temp_buf()
254 : : {
255 : : struct list_elem *e;
256 : : struct temp_buf_item *item;
257 : 123 : size_t count=0;
258 : :
259 : 123 : spin_lock(&temp_buf_lock);
260 : 123 : e = list_begin(&temp_buf);
261 [ + + ]: 246 : while(e){
262 : 123 : item = _get_entry(e, struct temp_buf_item, le);
263 : 123 : e = list_remove(&temp_buf, e);
264 : 123 : free_align(item->addr);
265 : 123 : count++;
266 : : }
267 : 123 : spin_unlock(&temp_buf_lock);
268 : 123 : }
269 : :
270 : 251 : fdb_status _filemgr_read_header(struct filemgr *file)
271 : : {
272 : : uint8_t marker[BLK_MARKER_SIZE];
273 : : filemgr_magic_t magic;
274 : : filemgr_header_len_t len;
275 : : uint8_t *buf;
276 : : uint32_t crc, crc_file;
277 : 251 : fdb_status status = FDB_RESULT_SUCCESS;
278 : :
279 : : // get temp buffer
280 : 251 : buf = (uint8_t *) _filemgr_get_temp_buf();
281 : :
282 [ + + ]: 251 : if (file->pos > 0) {
283 : : // Crash Recovery Test 1: unaligned last block write
284 : 64 : uint64_t remain = file->pos % file->blocksize;
285 [ - + ]: 64 : if (remain) {
286 : 0 : file->pos -= remain;
287 : 0 : file->last_commit = file->pos;
288 : : DBG("Crash Detected: %llu non-block aligned bytes discarded\n",
289 : : remain);
290 : : }
291 : :
292 [ + - ]: 16 : do {
293 : : ssize_t rv = file->ops->pread(file->fd, buf, file->blocksize,
294 : 79 : file->pos - file->blocksize);
295 [ + + ]: 79 : if (rv != file->blocksize) {
296 : 1 : status = FDB_RESULT_READ_FAIL;
297 : : DBG("Unable to read file %s blocksize %llu\n",
298 : : file->filename, file->blocksize);
299 : 1 : break;
300 : : }
301 : 78 : memcpy(marker, buf + file->blocksize - BLK_MARKER_SIZE,
302 : 78 : BLK_MARKER_SIZE);
303 : :
304 [ + + ]: 78 : if (marker[0] == BLK_MARKER_DBHEADER) {
305 : : // possible need for byte conversions here
306 : : memcpy(&magic,
307 : 63 : buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
308 : 63 : sizeof(magic));
309 : 63 : magic = _endian_decode(magic);
310 : :
311 [ + - ]: 63 : if (magic == FILEMGR_MAGIC) {
312 : : memcpy(&len,
313 : : buf + file->blocksize - BLK_MARKER_SIZE -
314 : 63 : sizeof(magic) - sizeof(len),
315 : 63 : sizeof(len));
316 : 63 : len = _endian_decode(len);
317 : :
318 : 63 : crc = chksum(buf, len - sizeof(crc));
319 : 63 : memcpy(&crc_file, buf + len - sizeof(crc), sizeof(crc));
320 : 63 : crc_file = _endian_decode(crc_file);
321 [ + - ]: 63 : if (crc == crc_file) {
322 : 63 : file->header.data = (void *)malloc(len);
323 : :
324 : 63 : memcpy(file->header.data, buf, len);
325 : : memcpy(&file->header.revnum, buf + len,
326 : 63 : sizeof(filemgr_header_revnum_t));
327 : : memcpy((void *) &file->header.seqnum,
328 : 63 : buf + len + sizeof(filemgr_header_revnum_t),
329 : 63 : sizeof(fdb_seqnum_t));
330 : : file->header.revnum =
331 : 63 : _endian_decode(file->header.revnum);
332 : : file->header.seqnum =
333 : 63 : _endian_decode(file->header.seqnum);
334 : 63 : file->header.size = len;
335 : 63 : file->header.bid = (file->pos / file->blocksize) - 1;
336 : :
337 : 63 : file->header.dirty_idtree_root = BLK_NOT_FOUND;
338 : 63 : file->header.dirty_seqtree_root = BLK_NOT_FOUND;
339 : 63 : memset(&file->header.stat, 0x0, sizeof(file->header.stat));
340 : :
341 : : // release temp buffer
342 : 63 : _filemgr_release_temp_buf(buf);
343 : :
344 : 63 : return FDB_RESULT_SUCCESS;
345 : : } else {
346 : 0 : status = FDB_RESULT_CHECKSUM_ERROR;
347 : : DBG("Crash Detected: CRC on disk %u != %u\n",
348 : : crc_file, crc);
349 : : }
350 : : } else {
351 : 0 : status = FDB_RESULT_FILE_CORRUPTION;
352 : : DBG("Crash Detected: Wrong Magic %llu != %llu\n", magic,
353 : : FILEMGR_MAGIC);
354 : : }
355 : : } else {
356 : 15 : status = FDB_RESULT_FILE_CORRUPTION;
357 : : DBG("Crash Detected: Last Block not DBHEADER %0.01x\n",
358 : : marker[0]);
359 : : }
360 : :
361 : 15 : file->pos -= file->blocksize;
362 : 15 : file->last_commit = file->pos;
363 : : } while (file->pos);
364 : : }
365 : :
366 : : // release temp buffer
367 : 188 : _filemgr_release_temp_buf(buf);
368 : :
369 : 188 : file->header.size = 0;
370 : 188 : file->header.revnum = 0;
371 : 188 : file->header.seqnum = 0;
372 : 188 : file->header.data = NULL;
373 : 188 : file->header.dirty_idtree_root = BLK_NOT_FOUND;
374 : 188 : file->header.dirty_seqtree_root = BLK_NOT_FOUND;
375 : 188 : memset(&file->header.stat, 0x0, sizeof(file->header.stat));
376 : 251 : return status;
377 : : }
378 : :
379 : 5 : size_t filemgr_get_ref_count(struct filemgr *file)
380 : : {
381 : 5 : size_t ret = 0;
382 : 5 : spin_lock(&file->lock);
383 : 5 : ret = file->ref_count;
384 : 5 : spin_unlock(&file->lock);
385 : 5 : return ret;
386 : : }
387 : :
388 : : struct filemgr_prefetch_args {
389 : : struct filemgr *file;
390 : : uint64_t duration;
391 : : void *aux;
392 : : };
393 : :
394 : 60 : void *_filemgr_prefetch_thread(void *voidargs)
395 : : {
396 : 60 : struct filemgr_prefetch_args *args = (struct filemgr_prefetch_args*)voidargs;
397 : 60 : uint8_t *buf = alca(uint8_t, args->file->blocksize);
398 : 60 : uint64_t cur_pos = 0, i;
399 : : uint64_t bcache_free_space;
400 : : bid_t bid;
401 : 60 : bool terminate = false;
402 : : struct timeval begin, cur, gap;
403 : :
404 : 60 : spin_lock(&args->file->lock);
405 : 60 : cur_pos = args->file->last_commit;
406 : 60 : spin_unlock(&args->file->lock);
407 [ + + ]: 60 : if (cur_pos < FILEMGR_PREFETCH_UNIT) {
408 : 43 : terminate = true;
409 : : } else {
410 : 17 : cur_pos -= FILEMGR_PREFETCH_UNIT;
411 : : }
412 : : // read backwards from the end of the file, in the unit of FILEMGR_PREFETCH_UNIT
413 : 60 : gettimeofday(&begin, NULL);
414 [ + + ]: 154 : while (!terminate) {
415 [ + + ]: 95348 : for (i = cur_pos;
416 : : i < cur_pos + FILEMGR_PREFETCH_UNIT;
417 : : i += args->file->blocksize) {
418 : :
419 : 95255 : gettimeofday(&cur, NULL);
420 : 95255 : gap = _utime_gap(begin, cur);
421 : 95255 : bcache_free_space = bcache_get_num_free_blocks();
422 : 95255 : bcache_free_space *= args->file->blocksize;
423 : :
424 [ + - ][ + - ]: 95255 : if (args->file->prefetch_status == FILEMGR_PREFETCH_ABORT ||
[ - + ][ - + ]
425 : : gap.tv_sec >= args->duration ||
426 : : bcache_free_space < FILEMGR_PREFETCH_UNIT) {
427 : : // terminate thread when
428 : : // 1. got abort signal
429 : : // 2. time out
430 : : // 3. not enough free space in block cache
431 : 0 : terminate = true;
432 : 0 : break;
433 : : } else {
434 : 95255 : bid = i / args->file->blocksize;
435 [ + + ]: 95255 : if (filemgr_read(args->file, bid, buf, NULL)
436 : : != FDB_RESULT_SUCCESS) {
437 : : // 4. read failure
438 : 1 : terminate = true;
439 : 1 : break;
440 : : }
441 : : }
442 : : }
443 : :
444 [ + + ]: 94 : if (cur_pos >= FILEMGR_PREFETCH_UNIT) {
445 : 78 : cur_pos -= FILEMGR_PREFETCH_UNIT;
446 : : } else {
447 : : // remaining space is less than FILEMGR_PREFETCH_UNIT
448 : 16 : terminate = true;
449 : : }
450 : : }
451 : :
452 : 60 : args->file->prefetch_status = FILEMGR_PREFETCH_IDLE;
453 : 60 : free(args);
454 : 60 : return NULL;
455 : : }
456 : :
457 : : // prefetch the given DB file
458 : 217 : void filemgr_prefetch(struct filemgr *file,
459 : : struct filemgr_config *config)
460 : : {
461 : : uint64_t bcache_free_space;
462 : :
463 : 217 : bcache_free_space = bcache_get_num_free_blocks();
464 : 217 : bcache_free_space *= file->blocksize;
465 : :
466 : : // block cache should have free space larger than FILEMGR_PREFETCH_UNIT
467 : 217 : spin_lock(&file->lock);
468 [ + + ][ + + ]: 217 : if (file->last_commit > 0 &&
469 : : bcache_free_space >= FILEMGR_PREFETCH_UNIT) {
470 : : // invoke prefetch thread
471 : : struct filemgr_prefetch_args *args;
472 : : args = (struct filemgr_prefetch_args *)
473 : 60 : calloc(1, sizeof(struct filemgr_prefetch_args));
474 : 60 : args->file = file;
475 : 60 : args->duration = config->prefetch_duration;
476 : :
477 : 60 : file->prefetch_status = FILEMGR_PREFETCH_RUNNING;
478 : 60 : thread_create(&file->prefetch_tid, _filemgr_prefetch_thread, args);
479 : : }
480 : 217 : spin_unlock(&file->lock);
481 : 217 : }
482 : :
483 : 644 : filemgr_open_result filemgr_open(char *filename, struct filemgr_ops *ops,
484 : : struct filemgr_config *config,
485 : : err_log_callback *log_callback)
486 : : {
487 : 644 : struct filemgr *file = NULL;
488 : : struct filemgr query;
489 : 644 : struct hash_elem *e = NULL;
490 : 644 : bool create = config->options & FILEMGR_CREATE;
491 : 644 : int file_flag = 0x0;
492 : 644 : int fd = -1;
493 : : fdb_status status;
494 : 644 : filemgr_open_result result = {NULL, FDB_RESULT_OPEN_FAIL};
495 : :
496 : 644 : filemgr_init(config);
497 : :
498 : : // check whether file is already opened or not
499 : 644 : query.filename = filename;
500 : 644 : spin_lock(&filemgr_openlock);
501 : 644 : e = hash_find(&hash, &query.e);
502 : :
503 [ + + ]: 644 : if (e) {
504 : : // already opened (return existing structure)
505 : 380 : file = _get_entry(e, struct filemgr, e);
506 : :
507 : 380 : spin_lock(&file->lock);
508 : 380 : file->ref_count++;
509 : :
510 [ + + ]: 380 : if (file->status == FILE_CLOSED) { // if file was closed before
511 : 5 : file_flag = O_RDWR;
512 [ + + ]: 5 : if (create) {
513 : 4 : file_flag |= O_CREAT;
514 : : }
515 : 5 : *file->config = *config;
516 : 5 : file->config->blocksize = global_config.blocksize;
517 : 5 : file->config->ncacheblock = global_config.ncacheblock;
518 : 5 : file_flag |= config->flag;
519 : 5 : file->fd = file->ops->open(file->filename, file_flag, 0666);
520 [ + + ]: 5 : if (file->fd < 0) {
521 [ + - ]: 1 : if (file->fd == FDB_RESULT_NO_SUCH_FILE) {
522 : : // A database file was manually deleted by the user.
523 : : // Clean up global hash table, WAL index, and buffer cache.
524 : : // Then, retry it with a create option below IFF it is not
525 : : // a read-only open attempt
526 : : struct hash_elem *ret;
527 : 1 : spin_unlock(&file->lock);
528 : 1 : ret = hash_remove(&hash, &file->e);
529 [ - + ]: 1 : assert(ret);
530 : 1 : _filemgr_free_func(&file->e);
531 [ + - ]: 1 : if (!create) {
532 : : _log_errno_str(ops, log_callback,
533 : 1 : FDB_RESULT_NO_SUCH_FILE, "OPEN", filename);
534 : 1 : spin_unlock(&filemgr_openlock);
535 : 1 : result.rv = FDB_RESULT_NO_SUCH_FILE;
536 : 1 : return result;
537 : : }
538 : : } else {
539 : : _log_errno_str(file->ops, log_callback,
540 : 0 : (fdb_status)file->fd, "OPEN", filename);
541 : 0 : file->ref_count--;
542 : 0 : spin_unlock(&file->lock);
543 : 0 : spin_unlock(&filemgr_openlock);
544 : 0 : result.rv = file->fd;
545 : 0 : return result;
546 : : }
547 : : } else { // Reopening the closed file is succeed.
548 : 4 : file->status = FILE_NORMAL;
549 [ + - ]: 4 : if (config->options & FILEMGR_SYNC) {
550 : 4 : file->fflags |= FILEMGR_SYNC;
551 : : } else {
552 : 0 : file->fflags &= ~FILEMGR_SYNC;
553 : : }
554 : 4 : spin_unlock(&file->lock);
555 : 4 : spin_unlock(&filemgr_openlock);
556 : 4 : result.file = file;
557 : 4 : result.rv = FDB_RESULT_SUCCESS;
558 : 4 : return result;
559 : : }
560 : : } else { // file is already opened.
561 : :
562 [ + + ]: 375 : if (config->options & FILEMGR_SYNC) {
563 : 372 : file->fflags |= FILEMGR_SYNC;
564 : : } else {
565 : 3 : file->fflags &= ~FILEMGR_SYNC;
566 : : }
567 : :
568 : 375 : spin_unlock(&file->lock);
569 : 375 : spin_unlock(&filemgr_openlock);
570 : 375 : result.file = file;
571 : 375 : result.rv = FDB_RESULT_SUCCESS;
572 : 375 : return result;
573 : : }
574 : : }
575 : :
576 : 264 : file_flag = O_RDWR;
577 [ + + ]: 264 : if (create) {
578 : 234 : file_flag |= O_CREAT;
579 : : }
580 : 264 : file_flag |= config->flag;
581 : 264 : fd = ops->open(filename, file_flag, 0666);
582 [ + + ]: 264 : if (fd < 0) {
583 : 15 : _log_errno_str(ops, log_callback, (fdb_status)fd, "OPEN", filename);
584 : 15 : spin_unlock(&filemgr_openlock);
585 : 15 : result.rv = fd;
586 : 15 : return result;
587 : : }
588 : 249 : file = (struct filemgr*)calloc(1, sizeof(struct filemgr));
589 : 249 : file->filename_len = strlen(filename);
590 : 249 : file->filename = (char*)malloc(file->filename_len + 1);
591 : 249 : strcpy(file->filename, filename);
592 : :
593 : 249 : file->ref_count = 1;
594 : :
595 : 249 : file->wal = (struct wal *)calloc(1, sizeof(struct wal));
596 : 249 : file->wal->flag = 0;
597 : :
598 : 249 : file->ops = ops;
599 : 249 : file->blocksize = global_config.blocksize;
600 : 249 : file->status = FILE_NORMAL;
601 : 249 : file->config = (struct filemgr_config*)malloc(sizeof(struct filemgr_config));
602 : 249 : *file->config = *config;
603 : 249 : file->config->blocksize = global_config.blocksize;
604 : 249 : file->config->ncacheblock = global_config.ncacheblock;
605 : 249 : file->new_file = NULL;
606 : 249 : file->old_filename = NULL;
607 : 249 : file->fd = fd;
608 : :
609 : 249 : cs_off_t offset = file->ops->goto_eof(file->fd);
610 [ - + ]: 249 : if (offset == FDB_RESULT_SEEK_FAIL) {
611 : 0 : _log_errno_str(file->ops, log_callback, FDB_RESULT_SEEK_FAIL, "SEEK_END", filename);
612 : 0 : free(file->wal);
613 : 0 : free(file->filename);
614 : 0 : free(file->config);
615 : 0 : free(file);
616 : 0 : spin_unlock(&filemgr_openlock);
617 : 0 : result.rv = FDB_RESULT_SEEK_FAIL;
618 : 0 : return result;
619 : : }
620 : 249 : file->pos = file->last_commit = offset;
621 : :
622 : 249 : file->bcache = NULL;
623 : 249 : file->in_place_compaction = false;
624 : 249 : file->kv_header = NULL;
625 : 249 : file->prefetch_status = FILEMGR_PREFETCH_IDLE;
626 : :
627 : 249 : status = _filemgr_read_header(file);
628 [ + + ]: 249 : if (status != FDB_RESULT_SUCCESS) {
629 : 1 : _log_errno_str(file->ops, log_callback, status, "READ", filename);
630 : 1 : free(file->wal);
631 : 1 : free(file->filename);
632 : 1 : free(file->config);
633 : 1 : free(file);
634 : 1 : spin_unlock(&filemgr_openlock);
635 : 1 : result.rv = status;
636 : 1 : return result;
637 : : }
638 : :
639 : 248 : spin_init(&file->lock);
640 : :
641 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
642 : : struct plock_ops pops;
643 : : struct plock_config pconfig;
644 : :
645 : 248 : pops.init_user = mutex_init_wrap;
646 : 248 : pops.lock_user = mutex_lock_wrap;
647 : 248 : pops.unlock_user = mutex_unlock_wrap;
648 : 248 : pops.destroy_user = mutex_destroy_wrap;
649 : 248 : pops.init_internal = spin_init_wrap;
650 : 248 : pops.lock_internal = spin_lock_wrap;
651 : 248 : pops.unlock_internal = spin_unlock_wrap;
652 : 248 : pops.destroy_internal = spin_destroy_wrap;
653 : 248 : pops.is_overlapped = _block_is_overlapped;
654 : :
655 : 248 : memset(&pconfig, 0x0, sizeof(pconfig));
656 : 248 : pconfig.ops = &pops;
657 : 248 : pconfig.sizeof_lock_internal = sizeof(spin_t);
658 : 248 : pconfig.sizeof_lock_user = sizeof(mutex_t);
659 : 248 : pconfig.sizeof_range = sizeof(bid_t);
660 : 248 : pconfig.aux = NULL;
661 : 248 : plock_init(&file->plock, &pconfig);
662 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
663 : : int i;
664 : : for (i=0;i<DLOCK_MAX;++i) {
665 : : mutex_init(&file->data_mutex[i]);
666 : : }
667 : : #else
668 : : int i;
669 : : for (i=0;i<DLOCK_MAX;++i) {
670 : : spin_init(&file->data_spinlock[i]);
671 : : }
672 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
673 : :
674 : : #ifdef __FILEMGR_MUTEX_LOCK
675 : 248 : mutex_init(&file->mutex);
676 : : #else
677 : : spin_init(&file->mutex);
678 : : #endif
679 : :
680 : : // initialize WAL
681 [ + - ]: 248 : if (!wal_is_initialized(file)) {
682 : 248 : wal_init(file, FDB_WAL_NBUCKET);
683 : : }
684 : :
685 : : // init global transaction for the file
686 : : file->global_txn.wrapper = (struct wal_txn_wrapper*)
687 : 248 : malloc(sizeof(struct wal_txn_wrapper));
688 : 248 : file->global_txn.wrapper->txn = &file->global_txn;
689 : 248 : file->global_txn.handle = NULL;
690 [ + + ]: 248 : if (file->pos > 0) {
691 : 61 : file->global_txn.prev_hdr_bid = (file->pos / file->blocksize)-1;
692 : : } else {
693 : 187 : file->global_txn.prev_hdr_bid = BLK_NOT_FOUND;
694 : : }
695 : 248 : file->global_txn.items = (struct list *)malloc(sizeof(struct list));
696 : 248 : list_init(file->global_txn.items);
697 : 248 : file->global_txn.isolation = FDB_ISOLATION_READ_COMMITTED;
698 : 248 : wal_add_transaction(file, &file->global_txn);
699 : :
700 : 248 : hash_insert(&hash, &file->e);
701 [ + + ]: 248 : if (config->prefetch_duration > 0) {
702 : 217 : filemgr_prefetch(file, config);
703 : : }
704 : 248 : spin_unlock(&filemgr_openlock);
705 : :
706 [ + + ]: 248 : if (config->options & FILEMGR_SYNC) {
707 : 226 : file->fflags |= FILEMGR_SYNC;
708 : : } else {
709 : 22 : file->fflags &= ~FILEMGR_SYNC;
710 : : }
711 : :
712 : 248 : result.file = file;
713 : 248 : result.rv = FDB_RESULT_SUCCESS;
714 : 644 : return result;
715 : : }
716 : :
717 : 13762 : uint64_t filemgr_update_header(struct filemgr *file, void *buf, size_t len)
718 : : {
719 : : uint64_t ret;
720 : :
721 : 13762 : spin_lock(&file->lock);
722 : :
723 [ + + ]: 13762 : if (file->header.data == NULL) {
724 : 162 : file->header.data = (void *)malloc(len);
725 [ + + ]: 13600 : }else if (file->header.size < len){
726 : 54 : file->header.data = (void *)realloc(file->header.data, len);
727 : : }
728 : 13762 : memcpy(file->header.data, buf, len);
729 : 13762 : file->header.size = len;
730 : 13762 : ++(file->header.revnum);
731 : 13762 : ret = file->header.revnum;
732 : :
733 : 13762 : spin_unlock(&file->lock);
734 : :
735 : 13762 : return ret;
736 : : }
737 : :
738 : 3534784 : filemgr_header_revnum_t filemgr_get_header_revnum(struct filemgr *file)
739 : : {
740 : : filemgr_header_revnum_t ret;
741 : 3534784 : spin_lock(&file->lock);
742 : 3536189 : ret = file->header.revnum;
743 : 3536189 : spin_unlock(&file->lock);
744 : 3535748 : return ret;
745 : : }
746 : :
747 : : // 'filemgr_get_seqnum' & 'filemgr_set_seqnum' have to be protected by
748 : : // 'filemgr_mutex_lock' & 'filemgr_mutex_unlock'.
749 : 2438383 : fdb_seqnum_t filemgr_get_seqnum(struct filemgr *file)
750 : : {
751 : 2438383 : return file->header.seqnum;
752 : : }
753 : :
754 : 2435185 : void filemgr_set_seqnum(struct filemgr *file, fdb_seqnum_t seqnum)
755 : : {
756 : 2435185 : file->header.seqnum = seqnum;
757 : 2435185 : }
758 : :
759 : 0 : char* filemgr_get_filename_ptr(struct filemgr *file, char **filename, uint16_t *len)
760 : : {
761 : 0 : spin_lock(&file->lock);
762 : 0 : *filename = file->filename;
763 : 0 : *len = file->filename_len;
764 : 0 : spin_unlock(&file->lock);
765 : 0 : return *filename;
766 : : }
767 : :
768 : 2990 : bid_t filemgr_get_header_bid(struct filemgr *file)
769 : : {
770 [ + + ]: 2990 : if (file->header.size > 0) {
771 : 2863 : return file->header.bid;
772 : : } else {
773 : 2990 : return BLK_NOT_FOUND;
774 : : }
775 : : }
776 : :
777 : 3014 : void* filemgr_get_header(struct filemgr *file, void *buf, size_t *len)
778 : : {
779 : 3014 : spin_lock(&file->lock);
780 : :
781 [ + + ]: 3014 : if (file->header.size > 0) {
782 [ + + ]: 2887 : if (buf == NULL) {
783 : 2468 : buf = (void*)malloc(file->header.size);
784 : : }
785 : 2887 : memcpy(buf, file->header.data, file->header.size);
786 : : }
787 : 3014 : *len = file->header.size;
788 : :
789 : 3014 : spin_unlock(&file->lock);
790 : :
791 : 3014 : return buf;
792 : : }
793 : :
794 : 2 : fdb_status filemgr_fetch_header(struct filemgr *file, uint64_t bid,
795 : : void *buf, size_t *len,
796 : : err_log_callback *log_callback)
797 : : {
798 : : uint8_t *_buf;
799 : : uint8_t marker[BLK_MARKER_SIZE];
800 : : filemgr_header_len_t hdr_len;
801 : : filemgr_magic_t magic;
802 : 2 : fdb_status status = FDB_RESULT_SUCCESS;
803 : :
804 [ + - ][ - + ]: 2 : if (!bid || bid == BLK_NOT_FOUND) {
805 : 0 : *len = 0; // No other header available
806 : 0 : return FDB_RESULT_SUCCESS;
807 : : }
808 : 2 : _buf = (uint8_t *)_filemgr_get_temp_buf();
809 : :
810 : 2 : status = filemgr_read(file, (bid_t)bid, _buf, log_callback);
811 : :
812 [ - + ]: 2 : if (status != FDB_RESULT_SUCCESS) {
813 : 0 : _filemgr_release_temp_buf(_buf);
814 : 0 : return status;
815 : : }
816 : 2 : memcpy(marker, _buf + file->blocksize - BLK_MARKER_SIZE,
817 : 2 : BLK_MARKER_SIZE);
818 : :
819 [ - + ]: 2 : if (marker[0] != BLK_MARKER_DBHEADER) {
820 : 0 : _filemgr_release_temp_buf(_buf);
821 : 0 : return FDB_RESULT_READ_FAIL;
822 : : }
823 : : memcpy(&magic,
824 : 2 : _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
825 : 2 : sizeof(magic));
826 : 2 : magic = _endian_decode(magic);
827 [ - + ]: 2 : if (magic != FILEMGR_MAGIC) {
828 : 0 : _filemgr_release_temp_buf(_buf);
829 : 0 : return FDB_RESULT_READ_FAIL;
830 : : }
831 : : memcpy(&hdr_len,
832 : : _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic) -
833 : 2 : sizeof(hdr_len), sizeof(hdr_len));
834 : 2 : hdr_len = _endian_decode(hdr_len);
835 : :
836 : 2 : memcpy(buf, _buf, hdr_len);
837 : 2 : *len = hdr_len;
838 : :
839 : 2 : _filemgr_release_temp_buf(_buf);
840 : :
841 : 2 : return status;
842 : : }
843 : :
844 : 138 : uint64_t filemgr_fetch_prev_header(struct filemgr *file, uint64_t bid,
845 : : void *buf, size_t *len, fdb_seqnum_t *seqnum,
846 : : err_log_callback *log_callback)
847 : : {
848 : : uint8_t *_buf;
849 : : uint8_t marker[BLK_MARKER_SIZE];
850 : : fdb_seqnum_t _seqnum;
851 : : filemgr_header_revnum_t _revnum;
852 : : filemgr_header_len_t hdr_len;
853 : : filemgr_magic_t magic;
854 : 138 : int found = 0;
855 : :
856 [ + - ][ - + ]: 138 : if (!bid || bid == BLK_NOT_FOUND) {
857 : 0 : *len = 0; // No other header available
858 : 0 : return bid;
859 : : }
860 : 138 : _buf = (uint8_t *)_filemgr_get_temp_buf();
861 : :
862 : 138 : bid--;
863 : : // Reverse scan the file for a previous DB header
864 [ + - ]: 11175 : do {
865 [ - + ]: 11313 : if (filemgr_read(file, (bid_t)bid, _buf, log_callback)
866 : : != FDB_RESULT_SUCCESS) {
867 : 0 : break;
868 : : }
869 : 11313 : memcpy(marker, _buf + file->blocksize - BLK_MARKER_SIZE,
870 : 11313 : BLK_MARKER_SIZE);
871 : :
872 [ + + ]: 11313 : if (marker[0] != BLK_MARKER_DBHEADER) {
873 : 11175 : continue;
874 : : }
875 : : memcpy(&magic,
876 : 138 : _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic),
877 : 138 : sizeof(magic));
878 : 138 : magic = _endian_decode(magic);
879 [ - + ]: 138 : if (magic != FILEMGR_MAGIC) {
880 : 0 : continue;
881 : : }
882 : : memcpy(&hdr_len,
883 : : _buf + file->blocksize - BLK_MARKER_SIZE - sizeof(magic) -
884 : 138 : sizeof(hdr_len), sizeof(hdr_len));
885 : 138 : hdr_len = _endian_decode(hdr_len);
886 : :
887 : 138 : memcpy(buf, _buf, hdr_len);
888 : : memcpy(&_revnum, _buf + hdr_len,
889 : 138 : sizeof(filemgr_header_revnum_t));
890 : : memcpy(&_seqnum,
891 : 138 : _buf + hdr_len + sizeof(filemgr_header_revnum_t),
892 : 138 : sizeof(fdb_seqnum_t));
893 : 138 : *seqnum = _endian_decode(_seqnum);
894 : 138 : *len = hdr_len;
895 : 138 : found = 1;
896 : 138 : break;
897 : : } while (bid--); // scan even the first block 0
898 : :
899 [ - + ]: 138 : if (!found) { // no other header found till end of file
900 : 0 : *len = 0;
901 : : }
902 : :
903 : 138 : _filemgr_release_temp_buf(_buf);
904 : :
905 : 138 : return bid;
906 : : }
907 : :
908 : 625 : fdb_status filemgr_close(struct filemgr *file, bool cleanup_cache_onclose,
909 : : const char *orig_file_name,
910 : : err_log_callback *log_callback)
911 : : {
912 : 625 : int rv = FDB_RESULT_SUCCESS;
913 : :
914 : 625 : spin_lock(&filemgr_openlock); // Grab the filemgr lock to avoid the race with
915 : : // filemgr_open() because file->lock won't
916 : : // prevent the race condition.
917 : :
918 : : // remove filemgr structure if no thread refers to the file
919 : 625 : spin_lock(&file->lock);
920 [ + + ]: 625 : if (--(file->ref_count) == 0) {
921 : 250 : spin_unlock(&file->lock);
922 [ + + ]: 250 : if (global_config.ncacheblock > 0) {
923 : : // discard all dirty blocks belonged to this file
924 : 121 : bcache_remove_dirty_blocks(file);
925 : : }
926 : :
927 [ + - ]: 250 : if (wal_is_initialized(file)) {
928 : 250 : wal_close(file);
929 : : }
930 : :
931 : 250 : spin_lock(&file->lock);
932 : 250 : rv = file->ops->close(file->fd);
933 [ + + ]: 250 : if (file->status == FILE_REMOVED_PENDING) {
934 : 54 : _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
935 : : // remove file
936 : 54 : remove(file->filename);
937 : : // we can release lock becuase no one will open this file
938 : 54 : spin_unlock(&file->lock);
939 : 54 : struct hash_elem *ret = hash_remove(&hash, &file->e);
940 [ - + ]: 54 : assert(ret);
941 : 54 : spin_unlock(&filemgr_openlock);
942 : 54 : _filemgr_free_func(&file->e);
943 : 54 : return (fdb_status) rv;
944 : : } else {
945 [ + + ]: 196 : if (cleanup_cache_onclose) {
946 : 191 : _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
947 [ + + ][ + - ]: 191 : if (file->in_place_compaction && orig_file_name) {
948 : 6 : struct hash_elem *elem = NULL;
949 : : struct filemgr query;
950 : 6 : query.filename = (char *)orig_file_name;
951 : 6 : elem = hash_find(&hash, &query.e);
952 [ + + ][ - + ]: 6 : if (!elem && rename(file->filename, orig_file_name) < 0) {
[ - + ]
953 : : // Note that the renaming failure is not a critical
954 : : // issue because the last compacted file will be automatically
955 : : // identified and opened in the next fdb_open call.
956 : : _log_errno_str(file->ops, log_callback, FDB_RESULT_FILE_RENAME_FAIL,
957 : 0 : "CLOSE", file->filename);
958 : : }
959 : : }
960 : 191 : spin_unlock(&file->lock);
961 : : // Clean up global hash table, WAL index, and buffer cache.
962 : 191 : struct hash_elem *ret = hash_remove(&hash, &file->e);
963 [ - + ]: 191 : assert(ret);
964 : 191 : spin_unlock(&filemgr_openlock);
965 : 191 : _filemgr_free_func(&file->e);
966 : 191 : return (fdb_status) rv;
967 : : } else {
968 : 5 : file->status = FILE_CLOSED;
969 : : }
970 : : }
971 : : }
972 : :
973 : 380 : _log_errno_str(file->ops, log_callback, (fdb_status)rv, "CLOSE", file->filename);
974 : :
975 : 380 : spin_unlock(&file->lock);
976 : 380 : spin_unlock(&filemgr_openlock);
977 : 625 : return (fdb_status) rv;
978 : : }
979 : :
980 : 247 : static void _filemgr_free_func(struct hash_elem *h)
981 : : {
982 : 247 : struct filemgr *file = _get_entry(h, struct filemgr, e);
983 : :
984 : 247 : spin_lock(&file->lock);
985 [ + + ]: 247 : if (file->prefetch_status == FILEMGR_PREFETCH_RUNNING) {
986 : : // prefetch thread is running
987 : : void *ret;
988 : 1 : file->prefetch_status = FILEMGR_PREFETCH_ABORT;
989 : 1 : spin_unlock(&file->lock);
990 : : // wait
991 : 1 : thread_join(file->prefetch_tid, &ret);
992 : : } else {
993 : 246 : spin_unlock(&file->lock);
994 : : }
995 : :
996 : : // remove all cached blocks
997 [ + + ]: 247 : if (global_config.ncacheblock > 0) {
998 : 121 : bcache_remove_dirty_blocks(file);
999 : 121 : bcache_remove_clean_blocks(file);
1000 : 121 : bcache_remove_file(file);
1001 : : }
1002 : :
1003 [ + + ]: 247 : if (file->kv_header) {
1004 : : // multi KV intance mode & KV header exists
1005 : 225 : file->free_kv_header(file);
1006 : : }
1007 : :
1008 : : // free global transaction
1009 : 247 : wal_remove_transaction(file, &file->global_txn);
1010 : 247 : free(file->global_txn.items);
1011 : 247 : free(file->global_txn.wrapper);
1012 : :
1013 : : // destroy WAL
1014 [ + - ]: 247 : if (wal_is_initialized(file)) {
1015 : 247 : wal_shutdown(file);
1016 : 247 : hash_free(&file->wal->hash_bykey);
1017 : 247 : hash_free(&file->wal->hash_byseq);
1018 : 247 : spin_destroy(&file->wal->lock);
1019 : : }
1020 : 247 : free(file->wal);
1021 : :
1022 : : // free filename and header
1023 : 247 : free(file->filename);
1024 [ + + ]: 247 : if (file->header.data) free(file->header.data);
1025 : : // free old filename if any
1026 : 247 : free(file->old_filename);
1027 : :
1028 : : // destroy locks
1029 : 247 : spin_destroy(&file->lock);
1030 : :
1031 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1032 : 247 : plock_destroy(&file->plock);
1033 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1034 : : int i;
1035 : : for (i=0;i<DLOCK_MAX;++i) {
1036 : : mutex_destroy(&file->data_mutex[i]);
1037 : : }
1038 : : #else
1039 : : int i;
1040 : : for (i=0;i<DLOCK_MAX;++i) {
1041 : : spin_destroy(&file->data_spinlock[i]);
1042 : : }
1043 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1044 : :
1045 : : #ifdef __FILEMGR_MUTEX_LOCK
1046 : 247 : mutex_destroy(&file->mutex);
1047 : : #else
1048 : : spin_destroy(&file->mutex);
1049 : : #endif
1050 : :
1051 : : // free file structure
1052 : 247 : free(file->config);
1053 : 247 : free(file);
1054 : 247 : }
1055 : :
1056 : : // permanently remove file from cache (not just close)
1057 : 0 : void filemgr_remove_file(struct filemgr *file)
1058 : : {
1059 : : struct hash_elem *ret;
1060 : :
1061 [ # # ]: 0 : assert(file);
1062 [ # # ]: 0 : assert(file->ref_count <= 0);
1063 : :
1064 : : // remove from global hash table
1065 : 0 : spin_lock(&filemgr_openlock);
1066 : 0 : ret = hash_remove(&hash, &file->e);
1067 [ # # ]: 0 : assert(ret);
1068 : 0 : spin_unlock(&filemgr_openlock);
1069 : :
1070 : 0 : _filemgr_free_func(&file->e);
1071 : 0 : }
1072 : :
1073 : 123 : void filemgr_shutdown()
1074 : : {
1075 [ + - ]: 123 : if (filemgr_initialized) {
1076 : 123 : spin_lock(&initial_lock);
1077 : :
1078 : 123 : hash_free_active(&hash, _filemgr_free_func);
1079 [ + + ]: 123 : if (global_config.ncacheblock > 0) {
1080 : 56 : bcache_shutdown();
1081 : : }
1082 : 123 : filemgr_initialized = 0;
1083 : : #ifndef SPIN_INITIALIZER
1084 : : initial_lock_status = 0;
1085 : : spin_destroy(&initial_lock);
1086 : : #else
1087 : 123 : initial_lock = SPIN_INITIALIZER;
1088 : : #endif
1089 : 123 : _filemgr_shutdown_temp_buf();
1090 : :
1091 : 123 : spin_unlock(&initial_lock);
1092 : : }
1093 : 123 : }
1094 : :
1095 : 13594 : bid_t filemgr_get_next_alloc_block(struct filemgr *file)
1096 : : {
1097 : 13594 : spin_lock(&file->lock);
1098 : 13594 : bid_t bid = file->pos / file->blocksize;
1099 : 13594 : spin_unlock(&file->lock);
1100 : 13594 : return bid;
1101 : : }
1102 : :
1103 : 105791 : bid_t filemgr_alloc(struct filemgr *file, err_log_callback *log_callback)
1104 : : {
1105 : 105791 : spin_lock(&file->lock);
1106 : 105791 : bid_t bid = file->pos / file->blocksize;
1107 : 105791 : file->pos += file->blocksize;
1108 : :
1109 [ + + ]: 105791 : if (global_config.ncacheblock <= 0) {
1110 : : // if block cache is turned off, write the allocated block before use
1111 : 16927 : uint8_t _buf = 0x0;
1112 : 16927 : ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
1113 : 16927 : _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
1114 : : }
1115 : 105791 : spin_unlock(&file->lock);
1116 : :
1117 : 105791 : return bid;
1118 : : }
1119 : :
1120 : 3150 : void filemgr_alloc_multiple(struct filemgr *file, int nblock, bid_t *begin,
1121 : : bid_t *end, err_log_callback *log_callback)
1122 : : {
1123 : 3150 : spin_lock(&file->lock);
1124 : 3150 : *begin = file->pos / file->blocksize;
1125 : 3150 : *end = *begin + nblock - 1;
1126 : 3150 : file->pos += file->blocksize * nblock;
1127 : :
1128 [ + + ]: 3150 : if (global_config.ncacheblock <= 0) {
1129 : : // if block cache is turned off, write the allocated block before use
1130 : 2187 : uint8_t _buf = 0x0;
1131 : 2187 : ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
1132 : 2187 : _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
1133 : : }
1134 : 3150 : spin_unlock(&file->lock);
1135 : 3150 : }
1136 : :
1137 : : // atomically allocate NBLOCK blocks only when current file position is same to nextbid
1138 : 221763 : bid_t filemgr_alloc_multiple_cond(struct filemgr *file, bid_t nextbid, int nblock,
1139 : : bid_t *begin, bid_t *end,
1140 : : err_log_callback *log_callback)
1141 : : {
1142 : : bid_t bid;
1143 : 221763 : spin_lock(&file->lock);
1144 : 221763 : bid = file->pos / file->blocksize;
1145 [ + + ]: 221763 : if (bid == nextbid) {
1146 : 218613 : *begin = file->pos / file->blocksize;
1147 : 218613 : *end = *begin + nblock - 1;
1148 : 218613 : file->pos += file->blocksize * nblock;
1149 : :
1150 [ + + ]: 218613 : if (global_config.ncacheblock <= 0) {
1151 : : // if block cache is turned off, write the allocated block before use
1152 : 11607 : uint8_t _buf = 0x0;
1153 : 11607 : ssize_t rv = file->ops->pwrite(file->fd, &_buf, 1, file->pos-1);
1154 : 11607 : _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
1155 : : }
1156 : : }else{
1157 : 3150 : *begin = BLK_NOT_FOUND;
1158 : 3150 : *end = BLK_NOT_FOUND;
1159 : : }
1160 : 221763 : spin_unlock(&file->lock);
1161 : 221763 : return bid;
1162 : : }
1163 : :
1164 : : #ifdef __CRC32
1165 : 228538 : INLINE fdb_status _filemgr_crc32_check(struct filemgr *file, void *buf)
1166 : : {
1167 [ + + ]: 228538 : if ( *((uint8_t*)buf + file->blocksize-1) == BLK_MARKER_BNODE ) {
1168 : : uint32_t crc_file, crc;
1169 : 48467 : memcpy(&crc_file, (uint8_t *) buf + BTREE_CRC_OFFSET, sizeof(crc_file));
1170 : 48467 : crc_file = _endian_decode(crc_file);
1171 : 48467 : memset((uint8_t *) buf + BTREE_CRC_OFFSET, 0xff, BTREE_CRC_FIELD_LEN);
1172 : 48467 : crc = chksum(buf, file->blocksize);
1173 [ - + ]: 48463 : if (crc != crc_file) {
1174 : 0 : return FDB_RESULT_CHECKSUM_ERROR;
1175 : : }
1176 : : }
1177 : 228534 : return FDB_RESULT_SUCCESS;
1178 : : }
1179 : : #endif
1180 : :
1181 : 35401 : void filemgr_invalidate_block(struct filemgr *file, bid_t bid)
1182 : : {
1183 [ + + ]: 35401 : if (global_config.ncacheblock > 0) {
1184 : 33427 : bcache_invalidate_block(file, bid);
1185 : : }
1186 : 35401 : }
1187 : :
1188 : 11062602 : fdb_status filemgr_read(struct filemgr *file, bid_t bid, void *buf,
1189 : : err_log_callback *log_callback)
1190 : : {
1191 : : size_t lock_no;
1192 : : ssize_t r;
1193 : 11062602 : uint64_t pos = bid * file->blocksize;
1194 : 11062602 : fdb_status status = FDB_RESULT_SUCCESS;
1195 [ - + ]: 11062602 : assert(pos < file->pos);
1196 : :
1197 [ + + ]: 11062602 : if (global_config.ncacheblock > 0) {
1198 : 10944802 : lock_no = bid % DLOCK_MAX;
1199 : : (void)lock_no;
1200 : :
1201 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1202 : 10944802 : plock_entry_t *plock_entry = NULL;
1203 : 10944802 : bid_t is_writer = 0;
1204 : : #endif
1205 : 10944802 : bool locked = false;
1206 : : // Note: we don't need to grab lock for committed blocks
1207 : : // because they are immutable so that no writer will interfere and
1208 : : // overwrite dirty data
1209 [ + + ]: 10944802 : if (filemgr_is_writable(file, bid)) {
1210 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1211 : 7685415 : plock_entry = plock_lock(&file->plock, &bid, &is_writer);
1212 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1213 : : mutex_lock(&file->data_mutex[lock_no]);
1214 : : #else
1215 : : spin_lock(&file->data_spinlock[lock_no]);
1216 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1217 : 7681533 : locked = true;
1218 : : }
1219 : :
1220 : 10968167 : r = bcache_read(file, bid, buf);
1221 [ + + ]: 10944745 : if (r == 0) {
1222 : : // cache miss
1223 : : // if normal file, just read a block
1224 : 110836 : r = file->ops->pread(file->fd, buf, file->blocksize, pos);
1225 [ + + ]: 110764 : if (r != file->blocksize) {
1226 : : _log_errno_str(file->ops, log_callback,
1227 : 1 : (fdb_status) r, "READ", file->filename);
1228 [ - + ]: 1 : if (locked) {
1229 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1230 : 0 : plock_unlock(&file->plock, plock_entry);
1231 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1232 : : mutex_unlock(&file->data_mutex[lock_no]);
1233 : : #else
1234 : : spin_unlock(&file->data_spinlock[lock_no]);
1235 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1236 : : }
1237 : 1 : return (fdb_status)r;
1238 : : }
1239 : : #ifdef __CRC32
1240 : 110763 : status = _filemgr_crc32_check(file, buf);
1241 [ - + ]: 110720 : if (status != FDB_RESULT_SUCCESS) {
1242 : : _log_errno_str(file->ops, log_callback, status, "READ",
1243 : 0 : file->filename);
1244 : 0 : return status;
1245 : : }
1246 : : #endif
1247 : 110720 : r = bcache_write(file, bid, buf, BCACHE_REQ_CLEAN);
1248 [ - + ]: 110808 : if (r != global_config.blocksize) {
1249 : : _log_errno_str(file->ops, log_callback,
1250 : 0 : (fdb_status) r, "WRITE", file->filename);
1251 : 0 : return FDB_RESULT_WRITE_FAIL;
1252 : : }
1253 : : }
1254 [ + + ]: 10944717 : if (locked) {
1255 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1256 : 7674708 : plock_unlock(&file->plock, plock_entry);
1257 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1258 : : mutex_unlock(&file->data_mutex[lock_no]);
1259 : : #else
1260 : : spin_unlock(&file->data_spinlock[lock_no]);
1261 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1262 : : }
1263 : : } else {
1264 : 117800 : r = file->ops->pread(file->fd, buf, file->blocksize, pos);
1265 [ + + ]: 117800 : if (r != file->blocksize) {
1266 : : _log_errno_str(file->ops, log_callback, (fdb_status) r, "READ",
1267 : 1 : file->filename);
1268 : 1 : return (fdb_status)r;
1269 : : }
1270 : :
1271 : : #ifdef __CRC32
1272 : 117799 : status = _filemgr_crc32_check(file, buf);
1273 [ - + ]: 117799 : if (status != FDB_RESULT_SUCCESS) {
1274 : : _log_errno_str(file->ops, log_callback, status, "READ",
1275 : 0 : file->filename);
1276 : 0 : return status;
1277 : : }
1278 : : #endif
1279 : : }
1280 : 11070995 : return status;
1281 : : }
1282 : :
1283 : 18051487 : fdb_status filemgr_write_offset(struct filemgr *file, bid_t bid,
1284 : : uint64_t offset, uint64_t len, void *buf,
1285 : : err_log_callback *log_callback)
1286 : : {
1287 [ - + ]: 18051487 : assert(offset + len <= file->blocksize);
1288 : :
1289 : : size_t lock_no;
1290 : 18051487 : ssize_t r = 0;
1291 : 18051487 : uint64_t pos = bid * file->blocksize + offset;
1292 [ - + ]: 18051487 : assert(pos >= file->last_commit);
1293 : :
1294 [ + + ]: 18051487 : if (global_config.ncacheblock > 0) {
1295 : 17379527 : lock_no = bid % DLOCK_MAX;
1296 : : (void)lock_no;
1297 : :
1298 [ + + ]: 17379527 : if (len == file->blocksize) {
1299 : : // write entire block .. we don't need to read previous block
1300 : 8378411 : r = bcache_write(file, bid, buf, BCACHE_REQ_DIRTY);
1301 [ - + ]: 8378411 : if (r != global_config.blocksize) {
1302 : : _log_errno_str(file->ops, log_callback,
1303 : 0 : (fdb_status) r, "WRITE", file->filename);
1304 : 0 : return FDB_RESULT_WRITE_FAIL;
1305 : : }
1306 : : } else {
1307 : : // partially write buffer cache first
1308 : 9001116 : r = bcache_write_partial(file, bid, buf, offset, len);
1309 [ + + ]: 9001116 : if (r == 0) {
1310 : : // cache miss
1311 : : // write partially .. we have to read previous contents of the block
1312 : 210755 : uint64_t cur_file_pos = file->ops->goto_eof(file->fd);
1313 : 210755 : bid_t cur_file_last_bid = cur_file_pos / file->blocksize;
1314 : 210755 : bool locked = false;
1315 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1316 : : plock_entry_t *plock_entry;
1317 : : #endif
1318 : 210755 : void *_buf = _filemgr_get_temp_buf();
1319 : :
1320 [ - + ]: 210755 : if (bid >= cur_file_last_bid) {
1321 : : // this is the first time to write this block
1322 : : // we don't need to read previous block from file
1323 : : // and also we don't need to grab lock
1324 : : } else {
1325 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1326 : 0 : bid_t is_writer = 1;
1327 : 0 : plock_entry = plock_lock(&file->plock, &bid, &is_writer);
1328 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1329 : : mutex_lock(&file->data_mutex[lock_no]);
1330 : : #else
1331 : : spin_lock(&file->data_spinlock[lock_no]);
1332 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1333 : 0 : locked = true;
1334 : :
1335 : : r = file->ops->pread(file->fd, _buf, file->blocksize,
1336 : 0 : bid * file->blocksize);
1337 [ # # ]: 0 : if (r != file->blocksize) {
1338 : 0 : _filemgr_release_temp_buf(_buf);
1339 : : _log_errno_str(file->ops, log_callback, (fdb_status) r,
1340 : 0 : "READ", file->filename);
1341 : 0 : return FDB_RESULT_READ_FAIL;
1342 : : }
1343 : : }
1344 : 210755 : memcpy((uint8_t *)_buf + offset, buf, len);
1345 : 210755 : r = bcache_write(file, bid, _buf, BCACHE_REQ_DIRTY);
1346 [ - + ]: 210755 : if (r != global_config.blocksize) {
1347 : 0 : _filemgr_release_temp_buf(_buf);
1348 : : _log_errno_str(file->ops, log_callback,
1349 : 0 : (fdb_status) r, "WRITE", file->filename);
1350 : 0 : return FDB_RESULT_WRITE_FAIL;
1351 : : }
1352 : :
1353 [ - + ]: 210755 : if (locked) {
1354 : : #ifdef __FILEMGR_DATA_PARTIAL_LOCK
1355 : 0 : plock_unlock(&file->plock, plock_entry);
1356 : : #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
1357 : : mutex_unlock(&file->data_mutex[lock_no]);
1358 : : #else
1359 : : spin_unlock(&file->data_spinlock[lock_no]);
1360 : : #endif //__FILEMGR_DATA_PARTIAL_LOCK
1361 : : }
1362 : :
1363 : 210755 : _filemgr_release_temp_buf(_buf);
1364 : : }
1365 : : }
1366 : : } else {
1367 : :
1368 : : #ifdef __CRC32
1369 [ + + ]: 671960 : if (len == file->blocksize) {
1370 : 310564 : uint8_t marker = *((uint8_t*)buf + file->blocksize - 1);
1371 [ + + ]: 310564 : if (marker == BLK_MARKER_BNODE) {
1372 : 310148 : memset((uint8_t *)buf + BTREE_CRC_OFFSET, 0xff, BTREE_CRC_FIELD_LEN);
1373 : 310148 : uint32_t crc32 = chksum(buf, file->blocksize);
1374 : 310119 : crc32 = _endian_encode(crc32);
1375 : 310119 : memcpy((uint8_t *)buf + BTREE_CRC_OFFSET, &crc32, sizeof(crc32));
1376 : : }
1377 : : }
1378 : : #endif
1379 : :
1380 : 671931 : r = file->ops->pwrite(file->fd, buf, len, pos);
1381 : 671976 : _log_errno_str(file->ops, log_callback, (fdb_status) r, "WRITE", file->filename);
1382 [ + + ]: 671960 : if (r != len) {
1383 : 3921 : return FDB_RESULT_READ_FAIL;
1384 : : }
1385 : : }
1386 : 18051506 : return FDB_RESULT_SUCCESS;
1387 : : }
1388 : :
1389 : 8688976 : fdb_status filemgr_write(struct filemgr *file, bid_t bid, void *buf,
1390 : : err_log_callback *log_callback)
1391 : : {
1392 : : return filemgr_write_offset(file, bid, 0, file->blocksize, buf,
1393 : 8688976 : log_callback);
1394 : : }
1395 : :
1396 : 27379467 : int filemgr_is_writable(struct filemgr *file, bid_t bid)
1397 : : {
1398 : 27379467 : spin_lock(&file->lock);
1399 : 27444614 : uint64_t pos = bid * file->blocksize;
1400 [ + + ][ + + ]: 27444614 : int cond = (pos >= file->last_commit && pos < file->pos);
1401 : 27444614 : spin_unlock(&file->lock);
1402 : :
1403 : 27443151 : return cond;
1404 : : }
1405 : :
1406 : 15304 : fdb_status filemgr_commit(struct filemgr *file,
1407 : : err_log_callback *log_callback)
1408 : : {
1409 : 15304 : uint16_t header_len = file->header.size;
1410 : : uint16_t _header_len;
1411 : : fdb_seqnum_t _seqnum;
1412 : : filemgr_header_revnum_t _revnum;
1413 : 15304 : int result = FDB_RESULT_SUCCESS;
1414 : 15304 : filemgr_magic_t magic = FILEMGR_MAGIC;
1415 : : filemgr_magic_t _magic;
1416 : :
1417 [ + + ]: 15304 : if (global_config.ncacheblock > 0) {
1418 : 2669 : result = bcache_flush(file);
1419 [ - + ]: 2669 : if (result != FDB_RESULT_SUCCESS) {
1420 : : _log_errno_str(file->ops, log_callback, (fdb_status) result,
1421 : 0 : "WRITE", file->filename);
1422 : 0 : return (fdb_status)result;
1423 : : }
1424 : : }
1425 : :
1426 : 15304 : spin_lock(&file->lock);
1427 : :
1428 [ + + ][ + - ]: 15304 : if (file->header.size > 0 && file->header.data) {
1429 : 13760 : void *buf = _filemgr_get_temp_buf();
1430 : : uint8_t marker[BLK_MARKER_SIZE];
1431 : :
1432 : : // <-------------------------- block size --------------------------->
1433 : : // <- len -><--- 8 ---><- 8 -> <-- 2 --><- 8 -><- 1 ->
1434 : : // [hdr data][hdr revnum][seqnum] ..(empty).. [hdr len][magic][marker]
1435 : :
1436 : : // header data
1437 : 13760 : memcpy(buf, file->header.data, header_len);
1438 : : // header rev number
1439 : 13760 : _revnum = _endian_encode(file->header.revnum);
1440 : 13760 : memcpy((uint8_t *)buf + header_len, &_revnum,
1441 : 27520 : sizeof(filemgr_header_revnum_t));
1442 : : // file's sequence number
1443 : 13760 : _seqnum = _endian_encode(file->header.seqnum);
1444 : 13760 : memcpy((uint8_t *)buf + header_len + sizeof(filemgr_header_revnum_t),
1445 : 13760 : &_seqnum, sizeof(fdb_seqnum_t));
1446 : :
1447 : : // header length
1448 : 13760 : _header_len = _endian_encode(header_len);
1449 : : memcpy((uint8_t *)buf + (file->blocksize - sizeof(filemgr_magic_t)
1450 : 13760 : - sizeof(header_len) - BLK_MARKER_SIZE),
1451 : 13760 : &_header_len, sizeof(header_len));
1452 : : // magic number
1453 : 13760 : _magic = _endian_encode(magic);
1454 : : memcpy((uint8_t *)buf + (file->blocksize - sizeof(filemgr_magic_t)
1455 : 13760 : - BLK_MARKER_SIZE), &_magic, sizeof(magic));
1456 : :
1457 : : // marker
1458 : 13760 : memset(marker, BLK_MARKER_DBHEADER, BLK_MARKER_SIZE);
1459 : 13760 : memcpy((uint8_t *)buf + file->blocksize - BLK_MARKER_SIZE,
1460 : 13760 : marker, BLK_MARKER_SIZE);
1461 : :
1462 : 13760 : ssize_t rv = file->ops->pwrite(file->fd, buf, file->blocksize, file->pos);
1463 : 13760 : _log_errno_str(file->ops, log_callback, (fdb_status) rv, "WRITE", file->filename);
1464 [ - + ]: 13760 : if (rv != file->blocksize) {
1465 : 0 : _filemgr_release_temp_buf(buf);
1466 : 0 : spin_unlock(&file->lock);
1467 : 0 : return FDB_RESULT_WRITE_FAIL;
1468 : : }
1469 : 13760 : file->header.bid = file->pos / file->blocksize;
1470 : 13760 : file->pos += file->blocksize;
1471 : :
1472 : 13760 : file->header.dirty_idtree_root = BLK_NOT_FOUND;
1473 : 13760 : file->header.dirty_seqtree_root = BLK_NOT_FOUND;
1474 : :
1475 : 13760 : _filemgr_release_temp_buf(buf);
1476 : : }
1477 : : // race condition?
1478 : 15304 : file->last_commit = file->pos;
1479 : :
1480 : 15304 : spin_unlock(&file->lock);
1481 : :
1482 [ + + ]: 15304 : if (file->fflags & FILEMGR_SYNC) {
1483 : 13757 : result = file->ops->fsync(file->fd);
1484 : 13757 : _log_errno_str(file->ops, log_callback, (fdb_status)result, "FSYNC", file->filename);
1485 : : }
1486 : 15304 : return (fdb_status) result;
1487 : : }
1488 : :
1489 : 3615 : fdb_status filemgr_sync(struct filemgr *file, err_log_callback *log_callback)
1490 : : {
1491 : 3615 : fdb_status result = FDB_RESULT_SUCCESS;
1492 [ + + ]: 3615 : if (global_config.ncacheblock > 0) {
1493 : 1089 : result = bcache_flush(file);
1494 [ - + ]: 1089 : if (result != FDB_RESULT_SUCCESS) {
1495 : : _log_errno_str(file->ops, log_callback, (fdb_status) result,
1496 : 0 : "WRITE", file->filename);
1497 : 0 : return result;
1498 : : }
1499 : : }
1500 : :
1501 [ + - ]: 3615 : if (file->fflags & FILEMGR_SYNC) {
1502 : 3615 : int rv = file->ops->fsync(file->fd);
1503 : 3615 : _log_errno_str(file->ops, log_callback, (fdb_status)rv, "FSYNC", file->filename);
1504 : 3615 : return (fdb_status) rv;
1505 : : }
1506 : 3615 : return result;
1507 : : }
1508 : :
1509 : 139 : int filemgr_update_file_status(struct filemgr *file, file_status_t status,
1510 : : char *old_filename)
1511 : : {
1512 : 139 : int ret = 1;
1513 : 139 : spin_lock(&file->lock);
1514 : 139 : file->status = status;
1515 [ + + ]: 139 : if (old_filename) {
1516 [ + + ]: 86 : if (!file->old_filename) {
1517 : 63 : file->old_filename = old_filename;
1518 : : } else {
1519 : 23 : ret = 0;
1520 [ - + ]: 23 : assert(file->ref_count);
1521 : 23 : free(old_filename);
1522 : : }
1523 : : }
1524 : 139 : spin_unlock(&file->lock);
1525 : 139 : return ret;
1526 : : }
1527 : :
1528 : 53 : void filemgr_set_compaction_old(struct filemgr *old_file, struct filemgr *new_file)
1529 : : {
1530 [ - + ]: 53 : assert(new_file);
1531 : :
1532 : 53 : spin_lock(&old_file->lock);
1533 : 53 : old_file->new_file = new_file;
1534 : 53 : old_file->status = FILE_COMPACT_OLD;
1535 : 53 : spin_unlock(&old_file->lock);
1536 : 53 : }
1537 : :
1538 : 55 : void filemgr_remove_pending(struct filemgr *old_file, struct filemgr *new_file)
1539 : : {
1540 [ - + ]: 55 : assert(new_file);
1541 : :
1542 : 55 : spin_lock(&old_file->lock);
1543 [ + - ]: 55 : if (old_file->ref_count > 0) {
1544 : : // delay removing
1545 : 55 : old_file->new_file = new_file;
1546 : 55 : old_file->status = FILE_REMOVED_PENDING;
1547 : 55 : spin_unlock(&old_file->lock);
1548 : : }else{
1549 : : // immediatly remove
1550 : 0 : spin_unlock(&old_file->lock);
1551 : 0 : remove(old_file->filename);
1552 : 0 : filemgr_remove_file(old_file);
1553 : : }
1554 : 55 : }
1555 : :
1556 : : // Note: filemgr_openlock should be held before calling this function.
1557 : 6 : fdb_status filemgr_destroy_file(char *filename,
1558 : : struct filemgr_config *config,
1559 : : struct hash *destroy_file_set)
1560 : : {
1561 : 6 : struct filemgr *file = NULL;
1562 : : struct hash to_destroy_files;
1563 : : struct hash *destroy_set = (destroy_file_set ? destroy_file_set :
1564 [ + + ]: 6 : &to_destroy_files);
1565 : : struct filemgr query;
1566 : 6 : struct hash_elem *e = NULL;
1567 : 6 : fdb_status status = FDB_RESULT_SUCCESS;
1568 : 6 : char *old_filename = NULL;
1569 : :
1570 [ + + ]: 6 : if (!destroy_file_set) { // top level or non-recursive call
1571 : 5 : hash_init(destroy_set, NBUCKET, _file_hash, _file_cmp);
1572 : : }
1573 : :
1574 : 6 : query.filename = filename;
1575 : : // check whether file is already being destroyed in parent recursive call
1576 : 6 : e = hash_find(destroy_set, &query.e);
1577 [ - + ]: 6 : if (e) { // Duplicate filename found, nothing to be done in this call
1578 [ # # ]: 0 : if (!destroy_file_set) { // top level or non-recursive call
1579 : 0 : hash_free(destroy_set);
1580 : : }
1581 : 0 : return status;
1582 : : } else {
1583 : : // Remember file. Stack value ok IFF single direction recursion
1584 : 6 : hash_insert(destroy_set, &query.e);
1585 : : }
1586 : :
1587 : : // check global list of known files to see if it is already opened or not
1588 : 6 : e = hash_find(&hash, &query.e);
1589 [ + + ]: 6 : if (e) {
1590 : : // already opened (return existing structure)
1591 : 2 : file = _get_entry(e, struct filemgr, e);
1592 : :
1593 : 2 : spin_lock(&file->lock);
1594 [ + - ]: 2 : if (file->ref_count) {
1595 : 2 : spin_unlock(&file->lock);
1596 : 2 : status = FDB_RESULT_FILE_IS_BUSY;
1597 [ + - ]: 2 : if (!destroy_file_set) { // top level or non-recursive call
1598 : 2 : hash_free(destroy_set);
1599 : : }
1600 : 2 : return status;
1601 : : }
1602 : 0 : spin_unlock(&file->lock);
1603 [ # # ]: 0 : if (file->old_filename) {
1604 : : status = filemgr_destroy_file(file->old_filename, config,
1605 : 0 : destroy_set);
1606 [ # # ]: 0 : if (status != FDB_RESULT_SUCCESS) {
1607 [ # # ]: 0 : if (!destroy_file_set) { // top level or non-recursive call
1608 : 0 : hash_free(destroy_set);
1609 : : }
1610 : 0 : return status;
1611 : : }
1612 : : }
1613 : :
1614 : : // Cleanup file from in-memory as well as on-disk
1615 : 0 : e = hash_remove(&hash, &file->e);
1616 [ # # ]: 0 : assert(e);
1617 : 0 : _filemgr_free_func(&file->e);
1618 [ # # ]: 0 : if (remove(filename)) {
1619 : 0 : status = FDB_RESULT_FILE_REMOVE_FAIL;
1620 : : }
1621 : : } else { // file not in memory, read on-disk to destroy older versions..
1622 : 4 : file = (struct filemgr *)alca(struct filemgr, 1);
1623 : 4 : file->filename = filename;
1624 : 4 : file->ops = get_filemgr_ops();
1625 : 4 : file->fd = file->ops->open(file->filename, O_RDWR, 0666);
1626 : 4 : file->blocksize = global_config.blocksize;
1627 [ + + ]: 4 : if (file->fd < 0) {
1628 [ - + ]: 2 : if (file->fd != FDB_RESULT_NO_SUCH_FILE) {
1629 [ # # ]: 0 : if (!destroy_file_set) { // top level or non-recursive call
1630 : 0 : hash_free(destroy_set);
1631 : : }
1632 : 0 : return FDB_RESULT_OPEN_FAIL;
1633 : : }
1634 : : } else { // file successfully opened, seek to end to get DB header
1635 : 2 : cs_off_t offset = file->ops->goto_eof(file->fd);
1636 [ - + ]: 2 : if (offset == FDB_RESULT_SEEK_FAIL) {
1637 [ # # ]: 0 : if (!destroy_file_set) { // top level or non-recursive call
1638 : 0 : hash_free(destroy_set);
1639 : : }
1640 : 0 : return FDB_RESULT_SEEK_FAIL;
1641 : : } else { // Need to read DB header which contains old filename
1642 : 2 : file->pos = offset;
1643 : 2 : status = _filemgr_read_header(file);
1644 [ - + ]: 2 : if (status != FDB_RESULT_SUCCESS) {
1645 [ # # ]: 0 : if (!destroy_file_set) { // top level or non-recursive call
1646 : 0 : hash_free(destroy_set);
1647 : : }
1648 : 0 : return status;
1649 : : }
1650 [ + - ]: 2 : if (file->header.data) {
1651 : : uint16_t *new_filename_len_ptr = (uint16_t *)((char *)
1652 : 2 : file->header.data + 64);
1653 : : uint16_t new_filename_len =
1654 : 2 : _endian_decode(*new_filename_len_ptr);
1655 : : uint16_t *old_filename_len_ptr = (uint16_t *)((char *)
1656 : 2 : file->header.data + 66);
1657 : : uint16_t old_filename_len =
1658 : 2 : _endian_decode(*old_filename_len_ptr);
1659 : : old_filename = (char *)file->header.data + 68
1660 : 2 : + new_filename_len;
1661 [ + + ]: 2 : if (old_filename_len) {
1662 : : status = filemgr_destroy_file(old_filename, config,
1663 : 1 : destroy_set);
1664 : : }
1665 : 2 : free(file->header.data);
1666 : : }
1667 [ + - ]: 2 : if (status == FDB_RESULT_SUCCESS) {
1668 [ - + ]: 2 : if (remove(filename)) {
1669 : 0 : status = FDB_RESULT_FILE_REMOVE_FAIL;
1670 : : }
1671 : : }
1672 : : }
1673 : 2 : file->ops->close(file->fd);
1674 : : }
1675 : : }
1676 : :
1677 [ + + ]: 4 : if (!destroy_file_set) { // top level or non-recursive call
1678 : 3 : hash_free(destroy_set);
1679 : : }
1680 : :
1681 : 6 : return status;
1682 : : }
1683 : :
1684 : 45460186 : file_status_t filemgr_get_file_status(struct filemgr *file)
1685 : : {
1686 : 45460186 : spin_lock(&file->lock);
1687 : 45487325 : file_status_t status = file->status;
1688 : 45487325 : spin_unlock(&file->lock);
1689 : 45486681 : return status;
1690 : : }
1691 : :
1692 : 13202328 : uint64_t filemgr_get_pos(struct filemgr *file)
1693 : : {
1694 : 13202328 : spin_lock(&file->lock);
1695 : 13262548 : uint64_t pos = file->pos;
1696 : 13262548 : spin_unlock(&file->lock);
1697 : 13260977 : return pos;
1698 : : }
1699 : :
1700 : 2471039 : bool filemgr_is_rollback_on(struct filemgr *file)
1701 : : {
1702 : 2471039 : spin_lock(&file->lock);
1703 : 2471039 : bool rv = (file->fflags & FILEMGR_ROLLBACK_IN_PROG);
1704 : 2471039 : spin_unlock(&file->lock);
1705 : 2471039 : return rv;
1706 : : }
1707 : :
1708 : 50 : void filemgr_set_rollback(struct filemgr *file, uint8_t new_val)
1709 : : {
1710 : 50 : spin_lock(&file->lock);
1711 [ + + ]: 50 : if (new_val) {
1712 : 25 : file->fflags |= FILEMGR_ROLLBACK_IN_PROG;
1713 : : } else {
1714 : 25 : file->fflags &= ~FILEMGR_ROLLBACK_IN_PROG;
1715 : : }
1716 : 50 : spin_unlock(&file->lock);
1717 : 50 : }
1718 : :
1719 : 53 : void filemgr_set_in_place_compaction(struct filemgr *file,
1720 : : bool in_place_compaction) {
1721 : 53 : spin_lock(&file->lock);
1722 : 53 : file->in_place_compaction = in_place_compaction;
1723 : 53 : spin_unlock(&file->lock);
1724 : 53 : }
1725 : :
1726 : 5 : void filemgr_mutex_openlock(struct filemgr_config *config)
1727 : : {
1728 : 5 : filemgr_init(config);
1729 : :
1730 : 5 : spin_lock(&filemgr_openlock);
1731 : 5 : }
1732 : :
1733 : 5 : void filemgr_mutex_openunlock(void)
1734 : : {
1735 : 5 : spin_unlock(&filemgr_openlock);
1736 : 5 : }
1737 : :
1738 : 2542918 : void filemgr_mutex_lock(struct filemgr *file)
1739 : : {
1740 : : #ifdef __FILEMGR_MUTEX_LOCK
1741 : 2542918 : mutex_lock(&file->mutex);
1742 : : #else
1743 : : spin_lock(&file->mutex);
1744 : : #endif
1745 : 2542917 : }
1746 : :
1747 : 2542918 : void filemgr_mutex_unlock(struct filemgr *file)
1748 : : {
1749 : : #ifdef __FILEMGR_MUTEX_LOCK
1750 : 2542918 : mutex_unlock(&file->mutex);
1751 : : #else
1752 : : spin_unlock(&file->mutex);
1753 : : #endif
1754 : 2542918 : }
1755 : :
1756 : 603 : void filemgr_set_dirty_root(struct filemgr *file,
1757 : : bid_t dirty_idtree_root,
1758 : : bid_t dirty_seqtree_root)
1759 : : {
1760 : 603 : spin_lock(&file->lock);
1761 : 603 : file->header.dirty_idtree_root = dirty_idtree_root;
1762 : 603 : file->header.dirty_seqtree_root = dirty_seqtree_root;
1763 : 603 : spin_unlock(&file->lock);
1764 : 603 : }
1765 : :
1766 : 2412659 : void filemgr_get_dirty_root(struct filemgr *file,
1767 : : bid_t *dirty_idtree_root,
1768 : : bid_t *dirty_seqtree_root)
1769 : : {
1770 : 2412659 : spin_lock(&file->lock);
1771 : 2412659 : *dirty_idtree_root = file->header.dirty_idtree_root;
1772 : 2412659 : *dirty_seqtree_root= file->header.dirty_seqtree_root;
1773 : 2412659 : spin_unlock(&file->lock);
1774 : 2412659 : }
1775 : :
1776 : 150300 : static int _kvs_stat_cmp(struct avl_node *a, struct avl_node *b, void *aux)
1777 : : {
1778 : : struct kvs_node *aa, *bb;
1779 : 150300 : aa = _get_entry(a, struct kvs_node, avl_id);
1780 : 150300 : bb = _get_entry(b, struct kvs_node, avl_id);
1781 : :
1782 [ + + ]: 150300 : if (aa->id < bb->id) {
1783 : 41667 : return -1;
1784 [ + + ]: 108633 : } else if (aa->id > bb->id) {
1785 : 8021 : return 1;
1786 : : } else {
1787 : 150300 : return 0;
1788 : : }
1789 : : }
1790 : :
1791 : 469 : void _kvs_stat_set(struct filemgr *file,
1792 : : fdb_kvs_id_t kv_id,
1793 : : struct kvs_stat stat)
1794 : : {
1795 [ + + ]: 469 : if (kv_id == 0) {
1796 : 365 : spin_lock(&file->lock);
1797 : 365 : file->header.stat = stat;
1798 : 365 : spin_unlock(&file->lock);
1799 : : } else {
1800 : : struct avl_node *a;
1801 : : struct kvs_node query, *node;
1802 : 104 : struct kvs_header *kv_header = file->kv_header;
1803 : :
1804 : 104 : spin_lock(&kv_header->lock);
1805 : 104 : query.id = kv_id;
1806 : 104 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
1807 [ + - ]: 104 : if (a) {
1808 : 104 : node = _get_entry(a, struct kvs_node, avl_id);
1809 : 104 : node->stat = stat;
1810 : : }
1811 : 104 : spin_unlock(&kv_header->lock);
1812 : : }
1813 : 469 : }
1814 : :
1815 : 20874796 : void _kvs_stat_update_attr(struct filemgr *file,
1816 : : fdb_kvs_id_t kv_id,
1817 : : kvs_stat_attr_t attr,
1818 : : int delta)
1819 : : {
1820 : 20874796 : spin_t *lock = NULL;
1821 : : struct kvs_stat *stat;
1822 : :
1823 [ + + ]: 20874796 : if (kv_id == 0) {
1824 : 20790772 : stat = &file->header.stat;
1825 : 20790772 : lock = &file->lock;
1826 : 20790772 : spin_lock(lock);
1827 : : } else {
1828 : : struct avl_node *a;
1829 : : struct kvs_node query, *node;
1830 : 84024 : struct kvs_header *kv_header = file->kv_header;
1831 : :
1832 : 84024 : lock = &kv_header->lock;
1833 : 84024 : spin_lock(lock);
1834 : 84024 : query.id = kv_id;
1835 : 84024 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
1836 [ + + ]: 84024 : if (!a) {
1837 : : // KV instance corresponding to the kv_id is already removed
1838 : 4 : spin_unlock(lock);
1839 : 20874851 : return;
1840 : : }
1841 : 84020 : node = _get_entry(a, struct kvs_node, avl_id);
1842 : 84020 : stat = &node->stat;
1843 : : }
1844 : :
1845 [ + + ]: 20874890 : if (attr == KVS_STAT_DATASIZE) {
1846 : 4269028 : stat->datasize += delta;
1847 [ + + ]: 16605862 : } else if (attr == KVS_STAT_NDOCS) {
1848 : 3768955 : stat->ndocs += delta;
1849 [ + + ]: 12836907 : } else if (attr == KVS_STAT_NLIVENODES) {
1850 : 4269029 : stat->nlivenodes += delta;
1851 [ + + ]: 8567878 : } else if (attr == KVS_STAT_WAL_NDELETES) {
1852 : 1462 : stat->wal_ndeletes += delta;
1853 [ + - ]: 8566416 : } else if (attr == KVS_STAT_WAL_NDOCS) {
1854 : 8566417 : stat->wal_ndocs += delta;
1855 : : }
1856 : 20874890 : spin_unlock(lock);
1857 : : }
1858 : :
1859 : 16490 : int _kvs_stat_get_kv_header(struct kvs_header *kv_header,
1860 : : fdb_kvs_id_t kv_id,
1861 : : struct kvs_stat *stat)
1862 : : {
1863 : 16490 : int ret = 0;
1864 : : struct avl_node *a;
1865 : : struct kvs_node query, *node;
1866 : :
1867 : 16490 : query.id = kv_id;
1868 : 16490 : a = avl_search(kv_header->idx_id, &query.avl_id, _kvs_stat_cmp);
1869 [ + + ]: 16490 : if (a) {
1870 : 16488 : node = _get_entry(a, struct kvs_node, avl_id);
1871 : 16488 : *stat = node->stat;
1872 : : } else {
1873 : 2 : ret = -1;
1874 : : }
1875 : 16490 : return ret;
1876 : : }
1877 : :
1878 : 4283558 : int _kvs_stat_get(struct filemgr *file,
1879 : : fdb_kvs_id_t kv_id,
1880 : : struct kvs_stat *stat)
1881 : : {
1882 : 4283558 : int ret = 0;
1883 : :
1884 [ + + ]: 4283558 : if (kv_id == 0) {
1885 : 4267172 : spin_lock(&file->lock);
1886 : 4267176 : *stat = file->header.stat;
1887 : 4267176 : spin_unlock(&file->lock);
1888 : : } else {
1889 : 16386 : struct kvs_header *kv_header = file->kv_header;
1890 : :
1891 : 16386 : spin_lock(&kv_header->lock);
1892 : 16386 : ret = _kvs_stat_get_kv_header(kv_header, kv_id, stat);
1893 : 16386 : spin_unlock(&kv_header->lock);
1894 : : }
1895 : :
1896 : 4283562 : return ret;
1897 : : }
1898 : :
1899 : 5503 : uint64_t _kvs_stat_get_sum(struct filemgr *file,
1900 : : kvs_stat_attr_t attr)
1901 : : {
1902 : : struct avl_node *a;
1903 : : struct kvs_node *node;
1904 : 5503 : struct kvs_header *kv_header = file->kv_header;
1905 : :
1906 : 5503 : uint64_t ret = 0;
1907 : 5503 : spin_lock(&file->lock);
1908 [ + + ]: 5503 : if (attr == KVS_STAT_DATASIZE) {
1909 : 1115 : ret += file->header.stat.datasize;
1910 [ + + ]: 4388 : } else if (attr == KVS_STAT_NDOCS) {
1911 : 1091 : ret += file->header.stat.ndocs;
1912 [ + + ]: 3297 : } else if (attr == KVS_STAT_NLIVENODES) {
1913 : 1115 : ret += file->header.stat.nlivenodes;
1914 [ + + ]: 2182 : } else if (attr == KVS_STAT_WAL_NDELETES) {
1915 : 1091 : ret += file->header.stat.wal_ndeletes;
1916 [ + - ]: 1091 : } else if (attr == KVS_STAT_WAL_NDOCS) {
1917 : 1091 : ret += file->header.stat.wal_ndocs;
1918 : : }
1919 : 5503 : spin_unlock(&file->lock);
1920 : :
1921 [ + - ]: 5503 : if (kv_header) {
1922 : 5503 : spin_lock(&kv_header->lock);
1923 : 5503 : a = avl_first(kv_header->idx_id);
1924 [ + + ]: 5533 : while (a) {
1925 : 30 : node = _get_entry(a, struct kvs_node, avl_id);
1926 : 30 : a = avl_next(&node->avl_id);
1927 : :
1928 [ + + ]: 30 : if (attr == KVS_STAT_DATASIZE) {
1929 : 6 : ret += node->stat.datasize;
1930 [ + + ]: 24 : } else if (attr == KVS_STAT_NDOCS) {
1931 : 6 : ret += node->stat.ndocs;
1932 [ + + ]: 18 : } else if (attr == KVS_STAT_NLIVENODES) {
1933 : 6 : ret += node->stat.nlivenodes;
1934 [ + + ]: 12 : } else if (attr == KVS_STAT_WAL_NDELETES) {
1935 : 6 : ret += node->stat.wal_ndeletes;
1936 [ + - ]: 6 : } else if (attr == KVS_STAT_WAL_NDOCS) {
1937 : 6 : ret += node->stat.wal_ndocs;
1938 : : }
1939 : : }
1940 : 5503 : spin_unlock(&kv_header->lock);
1941 : : }
1942 : :
1943 : 5503 : return ret;
1944 : : }
1945 : :
|