1 #ifndef EXTSTORE_H
2 #define EXTSTORE_H
3 
4 /* A safe-to-read dataset for determining compaction.
5  * id is the array index.
6  */
7 struct extstore_page_data {
8     uint64_t version;
9     uint64_t bytes_used;
10     unsigned int bucket;
11     unsigned int free_bucket;
12     bool active; // page is actively being written to; ignore it except for tallying.
13 };
14 
15 /* Pages can have objects deleted from them at any time. This creates holes
16  * that can't be reused until the page is either evicted or all objects are
17  * deleted.
18  * bytes_fragmented is the total bytes for all of these holes.
19  * It is the size of all used pages minus each page's bytes_used value.
20  */
21 struct extstore_stats {
22     uint64_t page_allocs;
23     uint64_t page_count; /* total page count */
24     uint64_t page_evictions;
25     uint64_t page_reclaims;
26     uint64_t page_size; /* size in bytes per page (supplied by caller) */
27     uint64_t pages_free; /* currently unallocated/unused pages */
28     uint64_t pages_used;
29     uint64_t objects_evicted;
30     uint64_t objects_read;
31     uint64_t objects_written;
32     uint64_t objects_used; /* total number of objects stored */
33     uint64_t bytes_evicted;
34     uint64_t bytes_written;
35     uint64_t bytes_read; /* wbuf - read -> bytes read from storage */
36     uint64_t bytes_used; /* total number of bytes stored */
37     uint64_t bytes_fragmented; /* see above comment */
38     uint64_t io_queue;
39     struct extstore_page_data *page_data;
40 };
41 
42 // TODO: Temporary configuration structure. A "real" library should have an
43 // extstore_set(enum, void *ptr) which hides the implementation.
44 // this is plenty for quick development.
45 struct extstore_conf {
46     unsigned int page_size; // ideally 64-256M in size
47     unsigned int page_count;
48     unsigned int page_buckets; // number of different writeable pages
49     unsigned int free_page_buckets; // buckets of dedicated pages (see code)
50     unsigned int wbuf_size; // must divide cleanly into page_size
51     unsigned int wbuf_count; // this might get locked to "2 per active page"
52     unsigned int io_threadcount;
53     unsigned int io_depth; // with normal I/O, hits locks less. req'd for AIO
54 };
55 
56 struct extstore_conf_file {
57     unsigned int page_count;
58     char *file;
59     int fd; // internal usage
60     uint64_t offset; // internal usage
61     unsigned int bucket; // free page bucket
62     unsigned int free_bucket; // specialized free bucket
63     struct extstore_conf_file *next;
64 };
65 
66 enum obj_io_mode {
67     OBJ_IO_READ = 0,
68     OBJ_IO_WRITE,
69 };
70 
71 typedef struct _obj_io obj_io;
72 typedef void (*obj_io_cb)(void *e, obj_io *io, int ret);
73 
74 /* An object for both reads and writes to the storage engine.
75  * Once an IO is submitted, ->next may be changed by the IO thread. It is not
76  * safe to further modify the IO stack until the entire request is completed.
77  */
78 struct _obj_io {
79     void *data; /* user supplied data pointer */
80     struct _obj_io *next;
81     char *buf;  /* buffer of data to read or write to */
82     struct iovec *iov; /* alternatively, use this iovec */
83     unsigned int iovcnt; /* number of IOV's */
84     unsigned int page_version;     /* page version for read mode */
85     unsigned int len;     /* for both modes */
86     unsigned int offset;  /* for read mode */
87     unsigned short page_id; /* for read mode */
88     enum obj_io_mode mode;
89     /* callback pointers? */
90     obj_io_cb cb;
91 };
92 
93 enum extstore_res {
94     EXTSTORE_INIT_BAD_WBUF_SIZE = 1,
95     EXTSTORE_INIT_NEED_MORE_WBUF,
96     EXTSTORE_INIT_NEED_MORE_BUCKETS,
97     EXTSTORE_INIT_PAGE_WBUF_ALIGNMENT,
98     EXTSTORE_INIT_TOO_MANY_PAGES,
99     EXTSTORE_INIT_OOM,
100     EXTSTORE_INIT_OPEN_FAIL,
101     EXTSTORE_INIT_THREAD_FAIL
102 };
103 
104 const char *extstore_err(enum extstore_res res);
105 void *extstore_init(struct extstore_conf_file *fh, struct extstore_conf *cf, enum extstore_res *res);
106 int extstore_write_request(void *ptr, unsigned int bucket, unsigned int free_bucket, obj_io *io);
107 void extstore_write(void *ptr, obj_io *io);
108 int extstore_submit(void *ptr, obj_io *io);
109 int extstore_submit_bg(void *ptr, obj_io *io);
110 /* count are the number of objects being removed, bytes are the original
111  * length of those objects. Bytes is optional but you can't track
112  * fragmentation without it.
113  */
114 int extstore_check(void *ptr, unsigned int page_id, uint64_t page_version);
115 int extstore_delete(void *ptr, unsigned int page_id, uint64_t page_version, unsigned int count, unsigned int bytes);
116 void extstore_get_stats(void *ptr, struct extstore_stats *st);
117 /* add page data array to a stats structure.
118  * caller must allocate its stats.page_data memory first.
119  */
120 void extstore_get_page_data(void *ptr, struct extstore_stats *st);
121 void extstore_close_page(void *ptr, unsigned int page_id, uint64_t page_version);
122 void extstore_evict_page(void *ptr, unsigned int page_id, uint64_t page_version);
123 
124 #endif
125