Line data Source code
1 : /**
2 : * @file
3 : * RocksDB backend for the key/value Store
4 : *
5 : * @authors
6 : * Copyright (C) 2020 Tino Reichardt <milky-neomutt@mcmilk.de>
7 : *
8 : * @copyright
9 : * This program is free software: you can redistribute it and/or modify it under
10 : * the terms of the GNU General Public License as published by the Free Software
11 : * Foundation, either version 2 of the License, or (at your option) any later
12 : * version.
13 : *
14 : * This program is distributed in the hope that it will be useful, but WITHOUT
15 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 : * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 : * details.
18 : *
19 : * You should have received a copy of the GNU General Public License along with
20 : * this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : /**
24 : * @page store_rocksdb RocksDB
25 : *
26 : * Use the RocksDB - A persistent key-value store for fast storage environments
27 : * https://rocksdb.org/
28 : */
29 :
30 : #include "config.h"
31 : #include <stddef.h>
32 : #include <fcntl.h>
33 : #include <rocksdb/c.h>
34 : #include <rocksdb/version.h>
35 : #include <string.h>
36 : #include "mutt/lib.h"
37 : #include "lib.h"
38 :
39 : /**
40 : * struct RocksDbCtx - Berkeley DB context
41 : */
42 : struct RocksDbCtx
43 : {
44 : rocksdb_t *db;
45 : rocksdb_options_t *options;
46 : rocksdb_readoptions_t *read_options;
47 : rocksdb_writeoptions_t *write_options;
48 : char *err;
49 : };
50 :
51 : /**
52 : * store_rocksdb_open - Implements StoreOps::open()
53 : */
54 4 : static void *store_rocksdb_open(const char *path)
55 : {
56 4 : if (!path)
57 2 : return NULL;
58 :
59 2 : struct RocksDbCtx *ctx = mutt_mem_malloc(sizeof(struct RocksDbCtx));
60 :
61 : /* RocksDB store errors in form of strings */
62 2 : ctx->err = NULL;
63 :
64 : /* setup generic options, create new db and limit log to one file */
65 2 : ctx->options = rocksdb_options_create();
66 2 : rocksdb_options_set_create_if_missing(ctx->options, 1);
67 2 : rocksdb_options_set_keep_log_file_num(ctx->options, 1);
68 :
69 : /* setup read options, we verify with checksums */
70 2 : ctx->read_options = rocksdb_readoptions_create();
71 2 : rocksdb_readoptions_set_verify_checksums(ctx->read_options, 1);
72 :
73 : /* setup write options, no sync needed, disable WAL */
74 2 : ctx->write_options = rocksdb_writeoptions_create();
75 2 : rocksdb_writeoptions_set_sync(ctx->write_options, 0);
76 2 : rocksdb_writeoptions_disable_WAL(ctx->write_options, 1);
77 :
78 2 : rocksdb_options_set_compression(ctx->options, rocksdb_no_compression);
79 :
80 : /* open database and check for error in ctx->error */
81 2 : ctx->db = rocksdb_open(ctx->options, path, &ctx->err);
82 2 : if (ctx->err)
83 : {
84 0 : rocksdb_free(ctx->err);
85 0 : FREE(&ctx);
86 0 : return NULL;
87 : }
88 :
89 2 : return ctx;
90 : }
91 :
92 : /**
93 : * store_rocksdb_fetch - Implements StoreOps::fetch()
94 : */
95 4 : static void *store_rocksdb_fetch(void *store, const char *key, size_t klen, size_t *vlen)
96 : {
97 4 : if (!store)
98 2 : return NULL;
99 :
100 2 : struct RocksDbCtx *ctx = store;
101 :
102 2 : void *rv = rocksdb_get(ctx->db, ctx->read_options, key, klen, vlen, &ctx->err);
103 2 : if (ctx->err)
104 : {
105 0 : rocksdb_free(ctx->err);
106 0 : ctx->err = NULL;
107 0 : return NULL;
108 : }
109 :
110 2 : return rv;
111 : }
112 :
113 : /**
114 : * store_rocksdb_free - Implements StoreOps::free()
115 : */
116 6 : static void store_rocksdb_free(void *store, void **ptr)
117 : {
118 6 : FREE(ptr);
119 6 : }
120 :
121 : /**
122 : * store_rocksdb_store - Implements StoreOps::store()
123 : */
124 4 : static int store_rocksdb_store(void *store, const char *key, size_t klen,
125 : void *value, size_t vlen)
126 : {
127 4 : if (!store)
128 2 : return -1;
129 :
130 2 : struct RocksDbCtx *ctx = store;
131 :
132 2 : rocksdb_put(ctx->db, ctx->write_options, key, klen, value, vlen, &ctx->err);
133 2 : if (ctx->err)
134 : {
135 0 : rocksdb_free(ctx->err);
136 0 : ctx->err = NULL;
137 0 : return -1;
138 : }
139 :
140 2 : return 0;
141 : }
142 :
143 : /**
144 : * store_rocksdb_delete_record - Implements StoreOps::delete_record()
145 : */
146 4 : static int store_rocksdb_delete_record(void *store, const char *key, size_t klen)
147 : {
148 4 : if (!store)
149 2 : return -1;
150 :
151 2 : struct RocksDbCtx *ctx = store;
152 :
153 2 : rocksdb_delete(ctx->db, ctx->write_options, key, klen, &ctx->err);
154 2 : if (ctx->err)
155 : {
156 0 : rocksdb_free(ctx->err);
157 0 : ctx->err = NULL;
158 0 : return -1;
159 : }
160 :
161 2 : return 0;
162 : }
163 :
164 : /**
165 : * store_rocksdb_close - Implements StoreOps::close()
166 : */
167 6 : static void store_rocksdb_close(void **ptr)
168 : {
169 6 : if (!ptr || !*ptr)
170 4 : return;
171 :
172 2 : struct RocksDbCtx *ctx = *ptr;
173 :
174 : /* close database and free resources */
175 2 : rocksdb_close(ctx->db);
176 2 : rocksdb_options_destroy(ctx->options);
177 2 : rocksdb_readoptions_destroy(ctx->read_options);
178 2 : rocksdb_writeoptions_destroy(ctx->write_options);
179 :
180 2 : FREE(ptr);
181 2 : *ptr = NULL;
182 : }
183 :
184 : /**
185 : * store_rocksdb_version - Implements StoreOps::version()
186 : */
187 2 : static const char *store_rocksdb_version(void)
188 : {
189 : /* return sth. like "RocksDB 6.7.3" */
190 : #define RDBVER(major, minor, patch) #major "." #minor "." #patch
191 2 : return "RocksDB " RDBVER(ROCKSDB_MAJOR, ROCKSDB_MINOR, ROCKSDB_PATCH);
192 : }
193 :
194 : STORE_BACKEND_OPS(rocksdb)
|