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 #ifndef _JSAHN_FILEMGR_H
19 #define _JSAHN_FILEMGR_H
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <stdint.h>
24 #include <errno.h>
25 
26 #ifdef _ASYNC_IO
27 #if !defined(WIN32) && !defined(_WIN32)
28 #include <libaio.h>
29 #include <sys/time.h>
30 #endif
31 #endif
32 
33 #include "libforestdb/fdb_errors.h"
34 
35 #include "atomic.h"
36 #include "internal_types.h"
37 #include "common.h"
38 #include "hash.h"
39 #include "partiallock.h"
40 #include "atomic.h"
41 #include "checksum.h"
42 #include "filemgr_ops.h"
43 #include "encryption.h"
44 #include "superblock.h"
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
50 #define FILEMGR_SYNC 0x01
51 #define FILEMGR_READONLY 0x02
52 #define FILEMGR_ROLLBACK_IN_PROG 0x04
53 #define FILEMGR_CREATE 0x08
54 #define FILEMGR_REMOVAL_IN_PROG 0x10
55 #define FILEMGR_CREATE_CRC32 0x20 // Used in testing upgrade path
56 #define FILEMGR_CANCEL_COMPACTION 0x40 // Cancel the compaction
57 #define FILEMGR_SUCCESSFULLY_COMPACTED 0x80 // Compaction is done
58 
59 struct filemgr_config {
60 
operator =filemgr_config61     filemgr_config& operator=(const filemgr_config& config) {
62         blocksize = config.blocksize;
63         ncacheblock = config.ncacheblock;
64         flag = config.flag;
65         seqtree_opt = config.seqtree_opt;
66         chunksize = config.chunksize;
67         options = config.options;
68         prefetch_duration = config.prefetch_duration;
69         num_wal_shards = config.num_wal_shards;
70         num_bcache_shards = config.num_bcache_shards;
71         encryption_key = config.encryption_key;
72         atomic_store_uint64_t(&block_reusing_threshold,
73                               atomic_get_uint64_t(&config.block_reusing_threshold,
74                                                   std::memory_order_relaxed),
75                               std::memory_order_relaxed);
76         atomic_store_uint64_t(&num_keeping_headers,
77                               atomic_get_uint64_t(&config.num_keeping_headers,
78                                                   std::memory_order_relaxed),
79                               std::memory_order_relaxed);
80         return *this;
81     }
82 
83     // TODO: Move these variables to private members as we refactor the code in C++.
84     int blocksize;
85     int ncacheblock;
86     int flag;
87     int chunksize;
88     uint8_t options;
89     uint8_t seqtree_opt;
90     uint64_t prefetch_duration;
91     uint16_t num_wal_shards;
92     uint16_t num_bcache_shards;
93     fdb_encryption_key encryption_key;
94     // Stale block reusing threshold
95     atomic_uint64_t block_reusing_threshold;
96     // Number of the last commit headders whose stale blocks should
97     // be kept for snapshot readers.
98     atomic_uint64_t num_keeping_headers;
99 };
100 
101 #ifndef _LATENCY_STATS
102 #define LATENCY_STAT_START()
103 #define LATENCY_STAT_END(file, type)
104 #else
105 #define LATENCY_STAT_START() \
106      uint64_t begin=get_monotonic_ts();
107 #define LATENCY_STAT_END(file, type)\
108     do {\
109         uint64_t end = get_monotonic_ts();\
110         filemgr_update_latency_stat(file, type, ts_diff(begin, end));} while(0)
111 
112 struct latency_stat {
113     atomic_uint32_t lat_min;
114     atomic_uint32_t lat_max;
115     atomic_uint64_t lat_sum;
116     atomic_uint64_t lat_num;
117 };
118 
119 #endif // _LATENCY_STATS
120 
121 struct async_io_handle {
122 #ifdef _ASYNC_IO
123 #if !defined(WIN32) && !defined(_WIN32)
124     struct iocb **ioq;
125     struct io_event *events;
126     io_context_t ioctx;
127 #endif
128 #endif
129     uint8_t *aio_buf;
130     uint64_t *offset_array;
131     size_t queue_depth;
132     size_t block_size;
133     int fd;
134 };
135 
136 typedef int filemgr_fs_type_t;
137 enum {
138     FILEMGR_FS_NO_COW = 0x01,
139     FILEMGR_FS_EXT4_WITH_COW = 0x02,
140     FILEMGR_FS_BTRFS = 0x03
141 };
142 
143 struct filemgr_buffer{
144     void *block;
145     bid_t lastbid;
146 };
147 
148 typedef uint16_t filemgr_header_len_t;
149 typedef uint64_t filemgr_magic_t;
150 typedef uint64_t filemgr_header_revnum_t;
151 
152 struct filemgr_header{
153     filemgr_header_len_t size;
154     filemgr_header_revnum_t revnum;
155     atomic_uint64_t seqnum;
156     atomic_uint64_t bid;
157     struct kvs_ops_stat op_stat; // op stats for default KVS
158     struct kvs_stat stat; // stats for the default KVS
159     void *data;
160 };
161 
162 typedef uint8_t filemgr_prefetch_status_t;
163 enum {
164     FILEMGR_PREFETCH_IDLE = 0,
165     FILEMGR_PREFETCH_RUNNING = 1,
166     FILEMGR_PREFETCH_ABORT = 2
167 };
168 
169 #define DLOCK_MAX (41) /* a prime number */
170 struct wal;
171 struct fnamedic_item;
172 struct kvs_header;
173 
174 typedef struct {
175     mutex_t mutex;
176     bool locked;
177 } mutex_lock_t;
178 
179 struct filemgr {
180     char *filename; // Current file name.
181     atomic_uint32_t ref_count;
182     uint8_t fflags;
183     uint16_t filename_len;
184     uint32_t blocksize;
185     int fd;
186     atomic_uint64_t pos;
187     atomic_uint64_t last_commit;
188     atomic_uint64_t last_writable_bmp_revnum;
189     atomic_uint64_t num_invalidated_blocks;
190     atomic_uint8_t io_in_prog;
191     struct wal *wal;
192     struct filemgr_header header;
193     struct filemgr_ops *ops;
194     struct hash_elem e;
195     atomic_uint8_t status;
196     struct filemgr_config *config;
197 
198     char *old_filename;                 // Old file name before compaction
199     char *new_filename;                 // New file name after compaction
200 
201     std::atomic<struct fnamedic_item *> bcache;
202     fdb_txn global_txn;
203     bool in_place_compaction;
204     filemgr_fs_type_t fs_type;
205     struct kvs_header *kv_header;
206     void (*free_kv_header)(struct filemgr *file); // callback function
207     atomic_uint32_t throttling_delay;
208 
209     // variables related to prefetching
210     atomic_uint8_t prefetch_status;
211     thread_t prefetch_tid;
212 
213     // File format version
214     filemgr_magic_t version;
215 
216     // superblock
217     struct superblock *sb;
218 
219 #ifdef _LATENCY_STATS
220     struct latency_stat lat_stats[FDB_LATENCY_NUM_STATS];
221 #endif //_LATENCY_STATS
222 
223     // spin lock for small region
224     spin_t lock;
225 
226     // lock for data consistency
227 #ifdef __FILEMGR_DATA_PARTIAL_LOCK
228     struct plock plock;
229 #elif defined(__FILEMGR_DATA_MUTEX_LOCK)
230     mutex_t data_mutex[DLOCK_MAX];
231 #else
232     spin_t data_spinlock[DLOCK_MAX];
233 #endif //__FILEMGR_DATA_PARTIAL_LOCK
234 
235     // mutex for synchronization among multiple writers.
236     mutex_lock_t writer_lock;
237 
238     // CRC the file is using.
239     crc_mode_e crc_mode;
240 
241     encryptor encryption;
242 
243     // temporary in-memory list of stale blocks
244     struct list *stale_list;
245     // in-memory clone of system docs for reusable block info
246     // (they are pointed to by stale-block-tree)
247     struct avl_tree stale_info_tree;
248     // temporary tree for merging stale regions
249     struct avl_tree mergetree;
250     std::atomic<bool> stale_info_tree_loaded;
251 
252     // in-memory index for a set of dirty index block updates
253     struct avl_tree dirty_update_idx;
254     // counter for the set of dirty index updates
255     atomic_uint64_t dirty_update_counter;
256     // latest dirty (immutable but not committed yet) update
257     struct filemgr_dirty_update_node *latest_dirty_update;
258     // spin lock for dirty_update_idx
259     spin_t dirty_update_lock;
260 
261     /**
262      * Index for fdb_file_handle belonging to the same filemgr handle.
263      */
264     struct avl_tree fhandle_idx;
265     /**
266      * Spin lock for file handle index.
267      */
268     spin_t fhandle_idx_lock;
269 };
270 
271 struct filemgr_dirty_update_node {
272     union {
273         // AVL-tree element
274         struct avl_node avl;
275         // list element
276         struct list_elem le;
277     };
278     // ID from the counter number
279     uint64_t id;
280     // flag indicating if this set of dirty blocks can be accessible.
281     bool immutable;
282     // flag indicating if this set of dirty blocks are already copied to newer node.
283     bool expired;
284     // number of threads (snapshots) accessing this dirty block set.
285     atomic_uint32_t ref_count;
286     // dirty root node BID for ID tree
287     bid_t idtree_root;
288     // dirty root node BID for sequence tree
289     bid_t seqtree_root;
290     // index for dirty blocks
291     struct avl_tree dirty_blocks;
292 };
293 
294 struct filemgr_dirty_update_block {
295     // AVL-tree element
296     struct avl_node avl;
297     // contents of the block
298     void *addr;
299     // Block ID
300     bid_t bid;
301     // flag indicating if this block is immutable
302     bool immutable;
303 };
304 
305 typedef fdb_status (*register_file_removal_func)(struct filemgr *file,
306                                                  err_log_callback *log_callback);
307 typedef bool (*check_file_removal_func)(const char *filename);
308 
309 typedef struct {
310     struct filemgr *file;
311     int rv;
312 } filemgr_open_result;
313 
314 void filemgr_init(struct filemgr_config *config);
315 void filemgr_set_lazy_file_deletion(bool enable,
316                                     register_file_removal_func regis_func,
317                                     check_file_removal_func check_func);
318 
319 /**
320  * Assign superblock operations.
321  *
322  * @param ops Set of superblock operations to be assigned.
323  * @return void.
324  */
325 void filemgr_set_sb_operation(struct sb_ops ops);
326 
327 uint64_t filemgr_get_bcache_used_space(void);
328 
329 bool filemgr_set_kv_header(struct filemgr *file, struct kvs_header *kv_header,
330                            void (*free_kv_header)(struct filemgr *file));
331 
332 struct kvs_header* filemgr_get_kv_header(struct filemgr *file);
333 
334 size_t filemgr_get_ref_count(struct filemgr *file);
335 
filemgr_incr_ref_count(struct filemgr *file)336 INLINE void filemgr_incr_ref_count(struct filemgr *file) {
337     atomic_incr_uint32_t(&file->ref_count);
338 }
339 
340 /**
341  * Get filemgr instance corresponding to the given file name.
342  *
343  * @param filename File name to find.
344  * @return filemgr instance. NULL if not found.
345  */
346 struct filemgr* filemgr_get_instance(const char* filename);
347 
348 filemgr_open_result filemgr_open(char *filename,
349                                  struct filemgr_ops *ops,
350                                  struct filemgr_config *config,
351                                  err_log_callback *log_callback);
352 
353 uint64_t filemgr_update_header(struct filemgr *file,
354                                void *buf,
355                                size_t len,
356                                bool inc_revnum);
357 filemgr_header_revnum_t filemgr_get_header_revnum(struct filemgr *file);
358 
359 fdb_seqnum_t filemgr_get_seqnum(struct filemgr *file);
360 void filemgr_set_seqnum(struct filemgr *file, fdb_seqnum_t seqnum);
361 
filemgr_get_header_bid(struct filemgr *file)362 INLINE bid_t filemgr_get_header_bid(struct filemgr *file)
363 {
364     return ((file->header.size > 0) ?
365             atomic_get_uint64_t(&file->header.bid) : BLK_NOT_FOUND);
366 }
367 bid_t _filemgr_get_header_bid(struct filemgr *file);
368 void* filemgr_get_header(struct filemgr *file, void *buf, size_t *len,
369                          bid_t *header_bid, fdb_seqnum_t *seqnum,
370                          filemgr_header_revnum_t *header_revnum);
371 
372 /**
373  * Get the current bitmap revision number of superblock.
374  *
375  * @param file Pointer to filemgr handle.
376  * @return Current bitmap revision number.
377  */
378 uint64_t filemgr_get_sb_bmp_revnum(struct filemgr *file);
379 
380 fdb_status filemgr_fetch_header(struct filemgr *file, uint64_t bid,
381                                 void *buf, size_t *len, fdb_seqnum_t *seqnum,
382                                 filemgr_header_revnum_t *header_revnum,
383                                 uint64_t *deltasize, uint64_t *version,
384                                 uint64_t *sb_bmp_revnum,
385                                 err_log_callback *log_callback);
386 uint64_t filemgr_fetch_prev_header(struct filemgr *file, uint64_t bid,
387                                    void *buf, size_t *len, fdb_seqnum_t *seqnum,
388                                    filemgr_header_revnum_t *revnum,
389                                    uint64_t *deltasize, uint64_t *version,
390                                    uint64_t *sb_bmp_revnum,
391                                    err_log_callback *log_callback);
392 fdb_status filemgr_close(struct filemgr *file,
393                          bool cleanup_cache_onclose,
394                          const char *orig_file_name,
395                          err_log_callback *log_callback);
396 
397 void filemgr_remove_all_buffer_blocks(struct filemgr *file);
398 void filemgr_free_func(struct hash_elem *h);
399 
filemgr_get_next_alloc_block(struct filemgr *file)400 INLINE bid_t filemgr_get_next_alloc_block(struct filemgr *file)
401 {
402     return atomic_get_uint64_t(&file->pos) / file->blocksize;
403 }
404 bid_t filemgr_alloc(struct filemgr *file, err_log_callback *log_callback);
405 void filemgr_alloc_multiple(struct filemgr *file, int nblock, bid_t *begin,
406                             bid_t *end, err_log_callback *log_callback);
407 bid_t filemgr_alloc_multiple_cond(struct filemgr *file, bid_t nextbid, int nblock,
408                                   bid_t *begin, bid_t *end,
409                                   err_log_callback *log_callback);
410 
411 // Returns true if the block invalidated is from recent uncommited blocks
412 bool filemgr_invalidate_block(struct filemgr *file, bid_t bid);
413 bool filemgr_is_fully_resident(struct filemgr *file);
414 // returns number of immutable blocks that remain in file
415 uint64_t filemgr_flush_immutable(struct filemgr *file,
416                                  err_log_callback *log_callback);
417 
418 fdb_status filemgr_read(struct filemgr *file,
419                         bid_t bid, void *buf,
420                         err_log_callback *log_callback,
421                         bool read_on_cache_miss);
422 
423 fdb_status filemgr_write_offset(struct filemgr *file, bid_t bid, uint64_t offset,
424                           uint64_t len, void *buf, bool final_write,
425                           err_log_callback *log_callback);
426 fdb_status filemgr_write(struct filemgr *file, bid_t bid, void *buf,
427                    err_log_callback *log_callback);
428 ssize_t filemgr_write_blocks(struct filemgr *file, void *buf, unsigned num_blocks, bid_t start_bid);
429 int filemgr_is_writable(struct filemgr *file, bid_t bid);
430 
431 void filemgr_remove_file(struct filemgr *file);
432 
filemgr_set_io_inprog(struct filemgr *file)433 INLINE void filemgr_set_io_inprog(struct filemgr *file)
434 {
435     atomic_incr_uint8_t(&file->io_in_prog);
436 }
437 
filemgr_clear_io_inprog(struct filemgr *file)438 INLINE void filemgr_clear_io_inprog(struct filemgr *file)
439 {
440     atomic_decr_uint8_t(&file->io_in_prog);
441 }
442 
443 fdb_status filemgr_commit(struct filemgr *file, bool sync,
444                           err_log_callback *log_callback);
445 /**
446  * Commit DB file, and write a DB header at the given BID.
447  *
448  * @param file Pointer to filemgr handle.
449  * @param bid ID of the block that DB header will be written. If this value is set to
450  *        BLK_NOT_FOUND, then DB header is appended at the end of the file.
451  * @param bmp_revnum Revision number of superblock's bitmap when this commit is called.
452  * @param sync Flag for calling fsync().
453  * @param log_callback Pointer to log callback function.
454  * @return FDB_RESULT_SUCCESS on success.
455  */
456 fdb_status filemgr_commit_bid(struct filemgr *file, bid_t bid,
457                               uint64_t bmp_revnum, bool sync,
458                               err_log_callback *log_callback);
459 fdb_status filemgr_sync(struct filemgr *file, bool sync_option,
460                         err_log_callback *log_callback);
461 
462 fdb_status filemgr_shutdown();
463 void filemgr_update_file_status(struct filemgr *file, file_status_t status);
464 
465 /**
466  * Updates the old_filename and new_filename of the current instance,
467  * with the arguments (non-null) provided.
468  *
469  * Returns false if oldFileName has already been set.
470  */
471 bool filemgr_update_file_linkage(struct filemgr *file,
472                                  const char *old_filename,
473                                  const char *new_filename);
474 
475 void filemgr_set_compaction_state(struct filemgr *old_file,
476                                   struct filemgr *new_file,
477                                   file_status_t status);
478 void filemgr_remove_pending(struct filemgr *old_file,
479                             struct filemgr *new_file,
480                             err_log_callback *log_callback);
481 
482 /**
483  * Return name of the latency stat given its type.
484  * @param stat The type of the latency stat to be named.
485  */
486 const char *filemgr_latency_stat_name(fdb_latency_stat_type stat);
487 
488 #ifdef _LATENCY_STATS
489 /**
490  * Initialize a latency stats instance
491  *
492  * @param val Pointer to a latency stats instance to be initialized
493  */
494 void filemgr_init_latency_stat(struct latency_stat *val);
495 
496 /**
497  * Destroy a latency stats instance
498  *
499  * @param val Pointer to a latency stats instance to be destroyed
500  */
501 void filemgr_destroy_latency_stat(struct latency_stat *val);
502 
503 /**
504  * Migrate the latency stats from the source file to the destination file
505  *
506  * @param oldf Pointer to the source file manager
507  * @param newf Pointer to the destination file manager
508  */
509 void filemgr_migrate_latency_stats(struct filemgr *src,
510                                    struct filemgr *dest);
511 
512 /**
513  * Update the latency stats for a given file manager
514  *
515  * @param file Pointer to the file manager whose latency stats need to be updated
516  * @param type Type of a latency stat to be updated
517  * @param val New value of a latency stat
518  */
519 void filemgr_update_latency_stat(struct filemgr *file,
520                                  fdb_latency_stat_type type,
521                                  uint32_t val);
522 
523 /**
524  * Get the latency stats from a given file manager
525  *
526  * @param file Pointer to the file manager
527  * @param type Type of a latency stat to be retrieved
528  * @param stat Pointer to the stats instance to be populated
529  */
530 void filemgr_get_latency_stat(struct filemgr *file,
531                               fdb_latency_stat_type type,
532                               fdb_latency_stat *stat);
533 
534 #ifdef _LATENCY_STATS_DUMP_TO_FILE
535 /**
536  * Write all the latency stats for a given file manager to a stat log file
537  *
538  * @param file Pointer to the file manager
539  * @param log_callback Pointer to the log callback function
540  */
541 void filemgr_dump_latency_stat(struct filemgr *file,
542                                err_log_callback *log_callback);
543 
544 #endif // _LATENCY_STATS_DUMP_TO_FILE
545 #endif // _LATENCY_STATS
546 
547 struct kvs_ops_stat *filemgr_migrate_op_stats(struct filemgr *old_file,
548                                               struct filemgr *new_file,
549                                               struct kvs_info *kvs);
550 fdb_status filemgr_destroy_file(char *filename,
551                                 struct filemgr_config *config,
552                                 struct hash *destroy_set);
553 
554 struct filemgr *filemgr_search_stale_links(struct filemgr *cur_file);
555 typedef char *filemgr_redirect_hdr_func(struct filemgr *old_file,uint8_t *buf,
556                                         struct filemgr *new_file);
557 
558 char *filemgr_redirect_old_file(struct filemgr *very_old_file,
559                                 struct filemgr *new_file,
560                                 filemgr_redirect_hdr_func redirect_func);
filemgr_get_file_status(struct filemgr *file)561 INLINE file_status_t filemgr_get_file_status(struct filemgr *file)
562 {
563     return atomic_get_uint8_t(&file->status);
564 }
filemgr_get_pos(struct filemgr *file)565 INLINE uint64_t filemgr_get_pos(struct filemgr *file)
566 {
567     return atomic_get_uint64_t(&file->pos);
568 }
569 
570 fdb_status filemgr_copy_file_range(struct filemgr *src_file,
571                                    struct filemgr *dst_file,
572                                    bid_t src_bid, bid_t dst_bid,
573                                    bid_t clone_len);
574 
575 bool filemgr_is_rollback_on(struct filemgr *file);
576 void filemgr_set_rollback(struct filemgr *file, uint8_t new_val);
577 
578 /**
579  * Set the file manager's flag to cancel the compaction task that is currently running.
580  *
581  * @param file Pointer to the file manager instance
582  * @param cancel True if the compaction should be cancelled.
583  */
584 void filemgr_set_cancel_compaction(struct filemgr *file, bool cancel);
585 
586 /**
587  * Return true if a compaction cancellation is requested.
588  *
589  * @param file Pointer to the file manager instance
590  * @return True if a compaction cancellation is requested.
591  */
592 bool filemgr_is_compaction_cancellation_requested(struct filemgr *file);
593 
594 void filemgr_set_successfully_compacted(struct filemgr *file);
595 bool filemgr_is_successfully_compacted(struct filemgr *file);
596 
597 void filemgr_set_in_place_compaction(struct filemgr *file,
598                                      bool in_place_compaction);
599 bool filemgr_is_in_place_compaction_set(struct filemgr *file);
600 
601 void filemgr_mutex_openlock(struct filemgr_config *config);
602 void filemgr_mutex_openunlock(void);
603 
604 void filemgr_mutex_lock(struct filemgr *file);
605 bool filemgr_mutex_trylock(struct filemgr *file);
606 void filemgr_mutex_unlock(struct filemgr *file);
607 
608 bool filemgr_is_commit_header(void *head_buffer, size_t blocksize);
609 
610 bool filemgr_is_cow_supported(struct filemgr *src, struct filemgr *dst);
611 
612 void filemgr_set_throttling_delay(struct filemgr *file, uint64_t delay_us);
613 uint32_t filemgr_get_throttling_delay(struct filemgr *file);
614 
filemgr_set_stale_list(struct filemgr *file, struct list *stale_list)615 INLINE void filemgr_set_stale_list(struct filemgr *file,
616                             struct list *stale_list)
617 {
618     file->stale_list = stale_list;
619 }
620 void filemgr_clear_stale_list(struct filemgr *file);
621 void filemgr_clear_stale_info_tree(struct filemgr *file);
622 void filemgr_clear_mergetree(struct filemgr *file);
623 
filemgr_get_stale_list(struct filemgr *file)624 INLINE struct list * filemgr_get_stale_list(struct filemgr *file)
625 {
626     return file->stale_list;
627 }
628 
629 /**
630  * Add an item into stale-block list of the given 'file'.
631  *
632  * @param file Pointer to file handle.
633  * @param pos Byte offset to the beginning of the stale region.
634  * @param len Length of the stale region.
635  * @return void.
636  */
637 void filemgr_add_stale_block(struct filemgr *file,
638                              bid_t pos,
639                              size_t len);
640 
641 /**
642  * Calculate the actual space (including block markers) used for the given document
643  * data, and return the list of regions to be marked as stale (if the given document
644  * is not physically consecutive, more than one regions will be returned).
645  *
646  * @param file Pointer to file handle.
647  * @param offset Byte offset to the beginning of the data.
648  * @param length Length of the data.
649  * @return List of stale regions.
650  */
651 struct stale_regions filemgr_actual_stale_regions(struct filemgr *file,
652                                                   bid_t offset,
653                                                   size_t length);
654 
655 /**
656  * Mark the given region (offset, length) as stale.
657  * This function automatically calculates the additional space used for block
658  * markers or block matadata, by internally calling filemgr_actual_stale_regions().
659  *
660  * @param file Pointer to file handle.
661  * @param offset Byte offset to the beginning of the data.
662  * @param length Length of the data.
663  * @return void.
664  */
665 void filemgr_mark_stale(struct filemgr *file,
666                         bid_t offset,
667                         size_t length);
668 
669 /**
670  * The node structure of fhandle index.
671  */
672 struct filemgr_fhandle_idx_node {
673     /**
674      * Void pointer to file handle.
675      */
676     void *fhandle;
677     /**
678      * AVL tree element.
679      */
680     struct avl_node avl;
681 };
682 
683 /**
684  * Add a FDB file handle into the superblock's global index.
685  *
686  * @param file Pointer to filemgr handle.
687  * @param fhandle Pointer to FDB file handle.
688  * @return True if successfully added.
689  */
690 bool filemgr_fhandle_add(struct filemgr *file, void *fhandle);
691 
692 /**
693  * Remove a FDB file handle from the superblock's global index.
694  *
695  * @param file Pointer to filemgr handle.
696  * @param fhandle Pointer to FDB file handle.
697  * @return True if successfully removed.
698  */
699 bool filemgr_fhandle_remove(struct filemgr *file, void *fhandle);
700 
701 /**
702  * Initialize global structures for dirty update management.
703  *
704  * @param file Pointer to filemgr handle.
705  * @return void.
706  */
707 void filemgr_dirty_update_init(struct filemgr *file);
708 
709 /**
710  * Free global structures for dirty update management.
711  *
712  * @param file Pointer to filemgr handle.
713  * @return void.
714  */
715 void filemgr_dirty_update_free(struct filemgr *file);
716 
717 /**
718  * Create a new dirty update entry.
719  *
720  * @param file Pointer to filemgr handle.
721  * @return Newly created dirty update entry.
722  */
723 struct filemgr_dirty_update_node *filemgr_dirty_update_new_node(struct filemgr *file);
724 
725 /**
726  * Return the latest complete (i.e., immutable) dirty update entry. Note that a
727  * dirty update that is being updated by a writer thread will not be returned.
728  *
729  * @param file Pointer to filemgr handle.
730  * @return Latest dirty update entry.
731  */
732 struct filemgr_dirty_update_node *filemgr_dirty_update_get_latest(struct filemgr *file);
733 
734 /**
735  * Increase the reference counter for the given dirty update entry.
736  *
737  * @param node Pointer to dirty update entry to increase reference counter.
738  * @return void.
739  */
740 void filemgr_dirty_update_inc_ref_count(struct filemgr_dirty_update_node *node);
741 
742 /**
743  * Commit the latest complete dirty update entry and write back all updated
744  * blocks into DB file. This API will remove all complete (i.e., immutable)
745  * dirty update entries whose reference counter is zero.
746  *
747  * @param file Pointer to filemgr handle.
748  * @param commit_node Pointer to dirty update entry to be flushed.
749  * @param log_callback Pointer to the log callback function.
750  * @return void.
751  */
752 void filemgr_dirty_update_commit(struct filemgr *file,
753                                  struct filemgr_dirty_update_node *commit_node,
754                                  err_log_callback *log_callback);
755 
756 /**
757  * Complete the given dirty update entry and make it immutable. This API will
758  * remove all complete (i.e., immutable) dirty update entries which are prior
759  * than the given dirty update entry and whose reference counter is zero.
760  *
761  * @param file Pointer to filemgr handle.
762  * @param node Pointer to dirty update entry to complete.
763  * @param node Pointer to previous dirty update entry.
764  * @return void.
765  */
766 void filemgr_dirty_update_set_immutable(struct filemgr *file,
767                                         struct filemgr_dirty_update_node *prev_node,
768                                         struct filemgr_dirty_update_node *node);
769 
770 /**
771  * Remove a dirty update entry and discard all dirty blocks from memory.
772  *
773  * @param file Pointer to filemgr handle.
774  * @param node Pointer to dirty update entry to be removed.
775  * @return void.
776  */
777 void filemgr_dirty_update_remove_node(struct filemgr *file,
778                                       struct filemgr_dirty_update_node *node);
779 
780 /**
781  * Close a dirty update entry. This API will remove all complete (i.e., immutable)
782  * dirty update entries except for the last immutable update entry.
783  *
784  * @param file Pointer to filemgr handle.
785  * @param node Pointer to dirty update entry to be closed.
786  * @return void.
787  */
788 void filemgr_dirty_update_close_node(struct filemgr *file,
789                                      struct filemgr_dirty_update_node *node);
790 
791 /**
792  * Set dirty root nodes for the given dirty update entry.
793  *
794  * @param file Pointer to filemgr handle.
795  * @param node Pointer to dirty update entry.
796  * @param dirty_idtree_root BID of ID tree root node.
797  * @param dirty_seqtree_root BID of sequence tree root node.
798  * @return void.
799  */
filemgr_dirty_update_set_root(struct filemgr *file, struct filemgr_dirty_update_node *node, bid_t dirty_idtree_root, bid_t dirty_seqtree_root)800 INLINE void filemgr_dirty_update_set_root(struct filemgr *file,
801                                           struct filemgr_dirty_update_node *node,
802                                           bid_t dirty_idtree_root,
803                                           bid_t dirty_seqtree_root)
804 {
805     if (node) {
806         node->idtree_root = dirty_idtree_root;
807         node->seqtree_root = dirty_seqtree_root;
808     }
809 }
810 
811 /**
812  * Get dirty root nodes for the given dirty update entry.
813  *
814  * @param file Pointer to filemgr handle.
815  * @param node Pointer to dirty update entry.
816  * @param dirty_idtree_root Pointer to the BID of ID tree root node.
817  * @param dirty_seqtree_root Pointer to the BID of sequence tree root node.
818  * @return void.
819  */
filemgr_dirty_update_get_root(struct filemgr *file, struct filemgr_dirty_update_node *node, bid_t *dirty_idtree_root, bid_t *dirty_seqtree_root)820 INLINE void filemgr_dirty_update_get_root(struct filemgr *file,
821                                           struct filemgr_dirty_update_node *node,
822                                           bid_t *dirty_idtree_root,
823                                           bid_t *dirty_seqtree_root)
824 {
825     if (node) {
826         *dirty_idtree_root = node->idtree_root;
827         *dirty_seqtree_root = node->seqtree_root;
828     } else {
829         *dirty_idtree_root = *dirty_seqtree_root = BLK_NOT_FOUND;
830     }
831 }
832 
833 /**
834  * Write a dirty block into the given dirty update entry.
835  *
836  * @param file Pointer to filemgr handle.
837  * @param bid BID of the block to be written.
838  * @param buf Pointer to the buffer containing the data to be written.
839  * @param node Pointer to the dirty update entry.
840  * @param log_callback Pointer to the log callback function.
841  * @return FDB_RESULT_SUCCESS on success.
842  */
843 fdb_status filemgr_write_dirty(struct filemgr *file,
844                                bid_t bid,
845                                void *buf,
846                                struct filemgr_dirty_update_node *node,
847                                err_log_callback *log_callback);
848 
849 /**
850  * Read a block through the given dirty update entries. It first tries to read
851  * the block from the writer's (which is being updated) dirty update entry,
852  * and then tries to read it from the reader's (which already became immutable)
853  * dirty update entry. If the block doesn't exist in both entries, then it reads
854  * the block from DB file.
855  *
856  * @param file Pointer to filemgr handle.
857  * @param bid BID of the block to be read.
858  * @param buf Pointer to the buffer where the read data will be copied.
859  * @param node_reader Pointer to the immutable dirty update entry.
860  * @param node_writer Pointer to the mutable dirty update entry.
861  * @param log_callback Pointer to the log callback function.
862  * @param read_on_cache_miss True if we want to read the block from file after
863  *        cache miss.
864  * @return FDB_RESULT_SUCCESS on success.
865  */
866 fdb_status filemgr_read_dirty(struct filemgr *file,
867                               bid_t bid,
868                               void *buf,
869                               struct filemgr_dirty_update_node *node_reader,
870                               struct filemgr_dirty_update_node *node_writer,
871                               err_log_callback *log_callback,
872                               bool read_on_cache_miss);
873 
874 void _kvs_stat_set(struct filemgr *file,
875                    fdb_kvs_id_t kv_id,
876                    struct kvs_stat stat);
877 void _kvs_stat_update_attr(struct filemgr *file,
878                            fdb_kvs_id_t kv_id,
879                            kvs_stat_attr_t attr,
880                            int delta);
881 int _kvs_stat_get_kv_header(struct kvs_header *kv_header,
882                             fdb_kvs_id_t kv_id,
883                             struct kvs_stat *stat);
884 int _kvs_stat_get(struct filemgr *file,
885                   fdb_kvs_id_t kv_id,
886                   struct kvs_stat *stat);
887 uint64_t _kvs_stat_get_sum(struct filemgr *file,
888                            kvs_stat_attr_t attr);
889 int _kvs_ops_stat_get_kv_header(struct kvs_header *kv_header,
890                                 fdb_kvs_id_t kv_id,
891                                 struct kvs_ops_stat *stat);
892 int _kvs_ops_stat_get(struct filemgr *file,
893                       fdb_kvs_id_t kv_id,
894                       struct kvs_ops_stat *stat);
895 
896 void _init_op_stats(struct kvs_ops_stat *stat);
897 struct kvs_ops_stat *filemgr_get_ops_stats(struct filemgr *file,
898                                           struct kvs_info *info);
899 
900 /**
901  * Convert a given errno value to the corresponding fdb_status value.
902  *
903  * @param errno_value errno value
904  * @param default_status Default fdb_status value to be returned if
905  *        there is no corresponding fdb_status value for a given errno value.
906  * @return fdb_status value that corresponds to a given errno value
907  */
908 fdb_status convert_errno_to_fdb_status(int errno_value,
909                                        fdb_status default_status);
910 
911 fdb_status filemgr_invalidate_dbheader(struct filemgr *file, bid_t bid, err_log_callback *log_callback);
912 #ifdef __cplusplus
913 }
914 #endif
915 
916 #endif
917