hirlite 0.0.2.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +13 -5
  2. data/ext/hirlite_ext/hirlite_ext.h +1 -1
  3. data/ext/hirlite_ext/rlite.c +3 -23
  4. data/lib/hirlite/connection.rb +4 -0
  5. data/lib/hirlite/version.rb +1 -1
  6. data/vendor/rlite/deps/lua/src/lua_cjson.c +1 -1
  7. data/vendor/rlite/src/Makefile +12 -25
  8. data/vendor/rlite/src/dump.c +3 -3
  9. data/vendor/rlite/src/flock_posix.c +79 -0
  10. data/vendor/rlite/src/flock_win.c +6 -0
  11. data/vendor/rlite/src/hirlite.c +265 -25
  12. data/vendor/rlite/src/hyperloglog.c +1 -1
  13. data/vendor/rlite/src/lzf_c.c +1 -1
  14. data/vendor/rlite/src/lzf_d.c +1 -1
  15. data/vendor/rlite/src/page_btree.c +3 -3
  16. data/vendor/rlite/src/page_key.c +12 -13
  17. data/vendor/rlite/src/page_list.c +4 -4
  18. data/vendor/rlite/src/page_long.c +2 -2
  19. data/vendor/rlite/src/page_multi_string.c +5 -5
  20. data/vendor/rlite/src/page_skiplist.c +3 -3
  21. data/vendor/rlite/src/page_string.c +2 -2
  22. data/vendor/rlite/src/pubsub.c +448 -0
  23. data/vendor/rlite/src/restore.c +5 -5
  24. data/vendor/rlite/src/rlite.c +141 -146
  25. data/vendor/rlite/src/rlite.h +40 -12
  26. data/vendor/rlite/src/{constants.h → rlite/constants.h} +0 -0
  27. data/vendor/rlite/src/{crc64.h → rlite/crc64.h} +0 -0
  28. data/vendor/rlite/src/{dump.h → rlite/dump.h} +0 -0
  29. data/vendor/rlite/src/{endianconv.h → rlite/endianconv.h} +0 -0
  30. data/vendor/rlite/src/rlite/flock.h +8 -0
  31. data/vendor/rlite/src/{hirlite.h → rlite/hirlite.h} +1 -0
  32. data/vendor/rlite/src/{hyperloglog.h → rlite/hyperloglog.h} +0 -0
  33. data/vendor/rlite/src/{lzf.h → rlite/lzf.h} +0 -0
  34. data/vendor/rlite/src/{lzfP.h → rlite/lzfP.h} +0 -0
  35. data/vendor/rlite/src/{page_btree.h → rlite/page_btree.h} +0 -0
  36. data/vendor/rlite/src/{page_key.h → rlite/page_key.h} +0 -0
  37. data/vendor/rlite/src/{page_list.h → rlite/page_list.h} +0 -0
  38. data/vendor/rlite/src/{page_long.h → rlite/page_long.h} +0 -0
  39. data/vendor/rlite/src/{page_multi_string.h → rlite/page_multi_string.h} +0 -0
  40. data/vendor/rlite/src/{page_skiplist.h → rlite/page_skiplist.h} +0 -0
  41. data/vendor/rlite/src/{page_string.h → rlite/page_string.h} +0 -0
  42. data/vendor/rlite/src/{pqsort.h → rlite/pqsort.h} +0 -0
  43. data/vendor/rlite/src/rlite/pubsub.h +25 -0
  44. data/vendor/rlite/src/{rand.h → rlite/rand.h} +0 -0
  45. data/vendor/rlite/src/{restore.h → rlite/restore.h} +0 -0
  46. data/vendor/rlite/src/{scripting.h → rlite/scripting.h} +0 -0
  47. data/vendor/rlite/src/{sha1.h → rlite/sha1.h} +0 -0
  48. data/vendor/rlite/src/rlite/signal.h +11 -0
  49. data/vendor/rlite/src/{solarisfixes.h → rlite/solarisfixes.h} +0 -0
  50. data/vendor/rlite/src/{sort.h → rlite/sort.h} +0 -0
  51. data/vendor/rlite/src/{status.h → rlite/status.h} +1 -0
  52. data/vendor/rlite/src/{type_hash.h → rlite/type_hash.h} +0 -0
  53. data/vendor/rlite/src/{type_list.h → rlite/type_list.h} +0 -0
  54. data/vendor/rlite/src/{type_set.h → rlite/type_set.h} +0 -0
  55. data/vendor/rlite/src/{type_string.h → rlite/type_string.h} +0 -0
  56. data/vendor/rlite/src/{type_zset.h → rlite/type_zset.h} +0 -0
  57. data/vendor/rlite/src/{util.h → rlite/util.h} +2 -1
  58. data/vendor/rlite/src/{utilfromredis.h → rlite/utilfromredis.h} +0 -0
  59. data/vendor/rlite/src/rlite/wal.h +8 -0
  60. data/vendor/rlite/src/scripting.c +8 -10
  61. data/vendor/rlite/src/sha1.c +2 -2
  62. data/vendor/rlite/src/signal_posix.c +118 -0
  63. data/vendor/rlite/src/signal_win.c +17 -0
  64. data/vendor/rlite/src/sort.c +2 -2
  65. data/vendor/rlite/src/type_hash.c +4 -4
  66. data/vendor/rlite/src/type_list.c +4 -4
  67. data/vendor/rlite/src/type_set.c +4 -4
  68. data/vendor/rlite/src/type_string.c +4 -4
  69. data/vendor/rlite/src/type_zset.c +7 -7
  70. data/vendor/rlite/src/util.c +28 -5
  71. data/vendor/rlite/src/utilfromredis.c +1 -1
  72. data/vendor/rlite/src/wal.c +309 -0
  73. metadata +59 -35
@@ -4,10 +4,10 @@
4
4
  #include <math.h>
5
5
  #include <stdlib.h>
6
6
  #include "rlite.h"
7
- #include "page_multi_string.h"
8
- #include "type_hash.h"
9
- #include "page_btree.h"
10
- #include "util.h"
7
+ #include "rlite/page_multi_string.h"
8
+ #include "rlite/type_hash.h"
9
+ #include "rlite/page_btree.h"
10
+ #include "rlite/util.h"
11
11
 
12
12
  static int rl_hash_create(rlite *db, long btree_page, rl_btree **btree)
13
13
  {
@@ -1,9 +1,9 @@
1
1
  #include <stdlib.h>
2
2
  #include "rlite.h"
3
- #include "page_multi_string.h"
4
- #include "type_list.h"
5
- #include "page_list.h"
6
- #include "util.h"
3
+ #include "rlite/page_multi_string.h"
4
+ #include "rlite/type_list.h"
5
+ #include "rlite/page_list.h"
6
+ #include "rlite/util.h"
7
7
 
8
8
  static int rl_llist_create(rlite *db, long list_page, rl_list **_list)
9
9
  {
@@ -1,9 +1,9 @@
1
1
  #include <stdlib.h>
2
2
  #include "rlite.h"
3
- #include "page_multi_string.h"
4
- #include "type_set.h"
5
- #include "page_btree.h"
6
- #include "util.h"
3
+ #include "rlite/page_multi_string.h"
4
+ #include "rlite/type_set.h"
5
+ #include "rlite/page_btree.h"
6
+ #include "rlite/util.h"
7
7
 
8
8
  static int rl_set_create(rlite *db, long btree_page, rl_btree **btree)
9
9
  {
@@ -3,10 +3,10 @@
3
3
  #include <math.h>
4
4
  #include <ctype.h>
5
5
  #include "rlite.h"
6
- #include "page_multi_string.h"
7
- #include "type_string.h"
8
- #include "util.h"
9
- #include "hyperloglog.h"
6
+ #include "rlite/page_multi_string.h"
7
+ #include "rlite/type_string.h"
8
+ #include "rlite/util.h"
9
+ #include "rlite/hyperloglog.h"
10
10
 
11
11
  static int rl_string_get_objects(rlite *db, const unsigned char *key, long keylen, long *_page_number, unsigned long long *expires, long *version)
12
12
  {
@@ -1,13 +1,13 @@
1
1
  #include <math.h>
2
2
  #include <stdlib.h>
3
3
  #include "rlite.h"
4
- #include "page_key.h"
5
- #include "page_multi_string.h"
6
- #include "type_zset.h"
7
- #include "page_btree.h"
8
- #include "page_list.h"
9
- #include "page_skiplist.h"
10
- #include "util.h"
4
+ #include "rlite/page_key.h"
5
+ #include "rlite/page_multi_string.h"
6
+ #include "rlite/type_zset.h"
7
+ #include "rlite/page_btree.h"
8
+ #include "rlite/page_list.h"
9
+ #include "rlite/page_skiplist.h"
10
+ #include "rlite/util.h"
11
11
 
12
12
  static int rl_zset_create(rlite *db, long levels_page_number, rl_btree **btree, long *btree_page, rl_skiplist **_skiplist, long *skiplist_page)
13
13
  {
@@ -2,15 +2,15 @@
2
2
  #include <string.h>
3
3
  #include <stdio.h>
4
4
  #include <math.h>
5
- #include "sha1.h"
5
+ #include "rlite/sha1.h"
6
6
  #ifdef RL_DEBUG
7
7
  #include <unistd.h>
8
8
  #include <sys/stat.h>
9
9
  #include <execinfo.h>
10
10
  #include <valgrind/valgrind.h>
11
11
  #endif
12
- #include "status.h"
13
- #include "util.h"
12
+ #include "rlite/status.h"
13
+ #include "rlite/util.h"
14
14
  #include <sys/time.h>
15
15
 
16
16
  int _sha1_formatter(unsigned char *data, char formatted[40])
@@ -170,13 +170,16 @@ int long_formatter(void *v2, char **formatted, int *size)
170
170
  return RL_OK;
171
171
  }
172
172
 
173
+ #endif
174
+
173
175
  int sha1_formatter(void *v2, char **formatted, int *size)
174
176
  {
175
177
  unsigned char *data = (unsigned char *)v2;
176
- *formatted = rl_malloc(sizeof(char) * 40);
178
+ *formatted = rl_malloc(sizeof(char) * 41);
177
179
  if (*formatted == NULL) {
178
180
  return RL_OUT_OF_MEMORY;
179
181
  }
182
+ (*formatted)[40] = 0;
180
183
  _sha1_formatter(data, *formatted);
181
184
  if (size) {
182
185
  *size = 40;
@@ -184,7 +187,6 @@ int sha1_formatter(void *v2, char **formatted, int *size)
184
187
  return RL_OK;
185
188
  }
186
189
 
187
- #endif
188
190
 
189
191
  // Code for serialize/deserialize double comes from
190
192
  // http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#serialization
@@ -332,3 +334,24 @@ double rl_strtod(unsigned char *_str, long strlen, unsigned char **_eptr) {
332
334
  }
333
335
  return d;
334
336
  }
337
+
338
+ char *rl_get_filename_with_suffix(const char *filename, char *suffix) {
339
+ int retval = RL_OK;
340
+ char *new_path = NULL;
341
+ size_t i, last_slash = 0, filenamelen = strlen(filename);
342
+ size_t suffixlen = strlen(suffix);
343
+ // Adding "." to the beginning of the filename, and null termination
344
+ RL_MALLOC(new_path, sizeof(char) * (filenamelen + suffixlen + 2));
345
+ for (i = filenamelen - 1; i > 0; i--) {
346
+ if (filename[i] == '/') {
347
+ last_slash = i + 1;
348
+ break;
349
+ }
350
+ }
351
+ memcpy(new_path, filename, last_slash);
352
+ new_path[last_slash] = '.';
353
+ memcpy(&new_path[last_slash + 1], &filename[last_slash], filenamelen - last_slash);
354
+ memcpy(&new_path[filenamelen + 1], suffix, suffixlen + 1);
355
+ cleanup:
356
+ return new_path;
357
+ }
@@ -26,7 +26,7 @@
26
26
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
27
  * POSSIBILITY OF SUCH DAMAGE.
28
28
  */
29
- #include "utilfromredis.h"
29
+ #include "rlite/utilfromredis.h"
30
30
  #include <ctype.h>
31
31
  #include <limits.h>
32
32
  #include <string.h>
@@ -0,0 +1,309 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <unistd.h>
4
+
5
+ #include "rlite.h"
6
+ #include "rlite/flock.h"
7
+ #include "rlite/sha1.h"
8
+
9
+ #ifdef RL_DEBUG
10
+ int rl_search_cache(rlite *db, rl_data_type *type, long page_number, void **obj, long *position, void *context, rl_page **pages, long page_len);
11
+ #endif
12
+
13
+ static const char *identifier = "rlwal0.0";
14
+
15
+ static char *get_wal_filename(const char *filename) {
16
+ return rl_get_filename_with_suffix(filename, ".wal");
17
+ }
18
+
19
+ static int rl_delete_wal(const char *wal_path) {
20
+ unlink(wal_path);
21
+ return RL_OK;
22
+ }
23
+
24
+ static int rl_read_wal(const char *wal_path, unsigned char **_data, size_t *_datalen) {
25
+ int retval = RL_OK;
26
+ char *data = NULL;
27
+ size_t datalen;
28
+ FILE *fp = fopen(wal_path, "rb");
29
+ if (fp == NULL) {
30
+ // file does not exist! empty data, retval=ok are set
31
+ goto cleanup;
32
+ }
33
+ RL_CALL(rl_flock, RL_OK, fp, RLITE_FLOCK_EX);
34
+ fseek(fp, 0, SEEK_END);
35
+ datalen = (size_t)ftell(fp);
36
+ fseek(fp, 0, SEEK_SET);
37
+
38
+ data = malloc(datalen * sizeof(char));
39
+ fread(data, datalen, 1, fp);
40
+ fclose(fp);
41
+ cleanup:
42
+ if (retval == RL_OK) {
43
+ *_data = (unsigned char *)data;
44
+ *_datalen = datalen;
45
+ }
46
+ return retval;
47
+ }
48
+
49
+ static int rl_apply_wal_data(rlite *db, unsigned char *data, size_t datalen, int skip_check) {
50
+ if (skip_check == 0) {
51
+ if (datalen < 36 + (size_t)db->page_size) {
52
+ // too short to be a valid wal file
53
+ return RL_UNEXPECTED;
54
+ }
55
+ if (memcmp(data, identifier, strlen(identifier))) {
56
+ // expected identifier
57
+ return RL_UNEXPECTED;
58
+ }
59
+ unsigned char digest[20];
60
+ SHA1_CTX sha;
61
+ SHA1Init(&sha);
62
+ SHA1Update(&sha, &data[32], datalen - 32);
63
+ SHA1Final(digest, &sha);
64
+ if (memcmp(&data[8], digest, 20) != 0) {
65
+ // digest mismatch
66
+ return RL_UNEXPECTED;
67
+ }
68
+ }
69
+ int retval;
70
+ rl_file_driver *driver = db->driver;
71
+ size_t written, position = 28;
72
+ long page_number;
73
+ long i, write_pages_len = get_4bytes(&data[position]);
74
+ position += 4;
75
+ int readwrite = (driver->mode & RLITE_OPEN_READWRITE) != 0;
76
+ rl_page *page_obj;
77
+ for (i = 0; i < write_pages_len; i++) {
78
+ page_number = get_4bytes(&data[position]);
79
+ position += 4;
80
+ if (readwrite) {
81
+ fseek(driver->fp, page_number * db->page_size, SEEK_SET);
82
+ written = fwrite(&data[position], sizeof(unsigned char), db->page_size, driver->fp);
83
+ if ((size_t)db->page_size != written) {
84
+ // at this point we have corrupted the database
85
+ // we have written something, but not all of it
86
+ retval = RL_UNEXPECTED;
87
+ goto cleanup;
88
+ }
89
+ } else {
90
+ /**
91
+ * Since we are in read-only mode, but the wal is fully written,
92
+ * we need to store its information as if it was written in the
93
+ * file, since it might be partially updated.
94
+ * We don't want to modify the file as a side effect when we are
95
+ * in a read only mode.
96
+ */
97
+
98
+ // TODO: better cleanup on OOM
99
+ rl_ensure_pages(db);
100
+ RL_MALLOC(page_obj, sizeof(*page_obj));
101
+ page_obj->page_number = page_number;
102
+ page_obj->type = NULL;
103
+ page_obj->obj = malloc(sizeof(unsigned char) * db->page_size);
104
+ if (page_obj->obj == NULL) {
105
+ rl_free(page_obj);
106
+ return RL_OUT_OF_MEMORY;
107
+ }
108
+ memcpy(page_obj->obj, &data[position], db->page_size);
109
+ db->read_pages[db->read_pages_len] = page_obj;
110
+ db->read_pages_len++;
111
+ }
112
+ if (page_number == 0) {
113
+ // header has changed! need to parse it before using db->page_size
114
+ RL_CALL(rl_header_deserialize, RL_OK, db, NULL, NULL, &data[position]);
115
+ }
116
+ position += db->page_size;
117
+ }
118
+ retval = RL_OK;
119
+ cleanup:
120
+ return retval;
121
+ }
122
+
123
+ static int create_wal_data(rlite *db, unsigned char **_data, size_t *_datalen) {
124
+ // 20 (sha1) + 8 (header) + 4 (number of pages)
125
+ size_t datalen = db->write_pages_len * (db->page_size + 4) + 32;
126
+ unsigned char *data;
127
+ int i, retval = RL_OK;
128
+ rl_page *page;
129
+ SHA1_CTX sha;
130
+ SHA1Init(&sha);
131
+ RL_MALLOC(data, sizeof(char) * datalen);
132
+ size_t position = strlen(identifier);
133
+ memcpy(data, identifier, position);
134
+ position += 20; // leaving space blank for sha1
135
+ put_4bytes(&data[position], db->write_pages_len);
136
+ position += 4;
137
+ for (i = 0; i < db->write_pages_len; i++) {
138
+ page = db->write_pages[i];
139
+ put_4bytes(&data[position], page->page_number);
140
+ position += 4;
141
+ memset(&data[position], 0, db->page_size);
142
+ if (page->type) {
143
+ retval = page->type->serialize(db, page->obj, &data[position]);
144
+ }
145
+ position += db->page_size;
146
+ SHA1Update(&sha, &data[position - db->page_size - 4], db->page_size + 4);
147
+ }
148
+ SHA1Final(&data[strlen(identifier)], &sha);
149
+ *_data = data;
150
+ *_datalen = datalen;
151
+ cleanup:
152
+ if (retval != RL_OK) {
153
+ rl_free(data);
154
+ }
155
+ return retval;
156
+ }
157
+
158
+ static int rl_write_wal_file(FILE *fp, rlite *db, unsigned char **_data, size_t *_datalen) {
159
+ int retval;
160
+ unsigned char *data = NULL;
161
+ size_t datalen = 0;
162
+ RL_CALL(create_wal_data, RL_OK, db, &data, &datalen);
163
+ fwrite(data, sizeof(char), datalen, fp);
164
+ cleanup:
165
+ if (retval == RL_OK && _data) {
166
+ *_data = data;
167
+ *_datalen = datalen;
168
+ } else {
169
+ rl_free(data);
170
+ }
171
+ return retval;
172
+ }
173
+ int rl_write_wal(const char *wal_path, rlite *db, unsigned char **_data, size_t *_datalen) {
174
+ int retval;
175
+ FILE *fp = NULL;
176
+ fp = fopen(wal_path, "wb");
177
+ RL_CALL(rl_flock, RL_OK, fp, RLITE_FLOCK_EX);
178
+ RL_CALL(rl_write_wal_file, RL_OK, fp, db, _data, _datalen);
179
+ cleanup:
180
+ if (fp) {
181
+ fclose(fp);
182
+ }
183
+ return retval;
184
+ }
185
+
186
+ int rl_write_apply_wal(rlite *db) {
187
+ FILE *fp = NULL;
188
+ int retval = RL_OK;
189
+ long i, page_number;
190
+ rl_page *page;
191
+ char *wal_path = NULL;
192
+ unsigned char *data = NULL;
193
+ size_t datalen;
194
+ #ifdef RL_DEBUG
195
+ for (i = 0; i < db->read_pages_len; i++) {
196
+ RL_MALLOC(data, db->page_size * sizeof(unsigned char));
197
+ page = db->read_pages[i];
198
+ memset(data, 0, db->page_size);
199
+ retval = page->type->serialize(db, page->obj, data);
200
+ if (retval != RL_OK) {
201
+ goto cleanup;
202
+ }
203
+ if (memcmp(data, page->serialized_data, db->page_size) != 0) {
204
+ fprintf(stderr, "Read page %ld (%s) has changed\n", page->page_number, page->type->name);
205
+ for (i = 0; i < db->page_size; i++) {
206
+ if (page->serialized_data[i] != data[i]) {
207
+ fprintf(stderr, "Different data in position %ld (expected %d, got %d)\n", i, page->serialized_data[i], data[i]);
208
+ }
209
+ }
210
+ retval = rl_search_cache(db, page->type, page->page_number, NULL, NULL, NULL, db->write_pages, db->write_pages_len);
211
+ if (retval == RL_FOUND) {
212
+ fprintf(stderr, "Page found in write_pages\n");
213
+ }
214
+ else {
215
+ fprintf(stderr, "Page not found in write_pages\n");
216
+ }
217
+ exit(1);
218
+ }
219
+ rl_free(data);
220
+ data = NULL;
221
+ }
222
+ #endif
223
+ if (db->driver_type == RL_FILE_DRIVER) {
224
+ rl_file_driver *driver = db->driver;
225
+ wal_path = get_wal_filename(driver->filename);
226
+ if (wal_path == NULL) {
227
+ retval = RL_UNEXPECTED;
228
+ goto cleanup;
229
+ }
230
+ fp = fopen(wal_path, "wb");
231
+ if (fp == NULL) {
232
+ retval = RL_UNEXPECTED;
233
+ goto cleanup;
234
+ }
235
+ RL_CALL(rl_flock, RL_OK, fp, RLITE_FLOCK_EX);
236
+ RL_CALL(rl_write_wal_file, RL_OK, fp, db, &data, &datalen);
237
+ RL_CALL(rl_apply_wal_data, RL_OK, db, data, datalen, 1);
238
+ ftruncate(fileno(fp), 0);
239
+ fclose(fp);
240
+ fp = NULL;
241
+ RL_CALL(rl_delete_wal, RL_OK, wal_path);
242
+ if (db->write_pages_len > 0) {
243
+ fflush(driver->fp);
244
+ }
245
+ rl_free(data);
246
+ data = NULL;
247
+ }
248
+ else if (db->driver_type == RL_MEMORY_DRIVER) {
249
+ rl_memory_driver *driver = db->driver;
250
+ if (db->write_pages_len > 0) {
251
+ page = db->write_pages[db->write_pages_len - 1];
252
+ if ((page->page_number + 1) * db->page_size > driver->datalen) {
253
+ void *tmp = realloc(driver->data, (page->page_number + 1) * db->page_size * sizeof(unsigned char));
254
+ if (!tmp) {
255
+ retval = RL_OUT_OF_MEMORY;
256
+ goto cleanup;
257
+ }
258
+ driver->data = tmp;
259
+ driver->datalen = (page->page_number + 1) * db->page_size;
260
+ }
261
+ }
262
+ for (i = 0; i < db->write_pages_len; i++) {
263
+ page = db->write_pages[i];
264
+ page_number = page->page_number;
265
+ memset(&driver->data[page_number * db->page_size], 0, db->page_size);
266
+ if (page->type) {
267
+ retval = page->type->serialize(db, page->obj, (unsigned char *)&driver->data[page_number * db->page_size]);
268
+ }
269
+ }
270
+ }
271
+ cleanup:
272
+ if (fp) {
273
+ fclose(fp);
274
+ }
275
+ rl_free(data);
276
+ rl_free(wal_path);
277
+ return retval;
278
+ }
279
+
280
+ int rl_apply_wal(rlite *db) {
281
+ rl_file_driver *driver = db->driver;
282
+ int retval;
283
+ unsigned char *data = NULL;
284
+ size_t datalen;
285
+ char *wal_path = get_wal_filename(driver->filename);
286
+ if (wal_path == NULL) {
287
+ retval = RL_UNEXPECTED;
288
+ goto cleanup;
289
+ }
290
+ if (access(wal_path, F_OK) != 0) {
291
+ retval = RL_OK;
292
+ goto cleanup;
293
+ }
294
+
295
+ RL_CALL(rl_read_wal, RL_OK, wal_path, &data, &datalen);
296
+ if (data != NULL) {
297
+ // regardless the data applies or not, the wal file needs to go away
298
+ // do not goto cleanup if it fails!
299
+ rl_apply_wal_data(db, data, datalen, 0);
300
+ if ((driver->mode & RLITE_OPEN_READWRITE) != 0) {
301
+ RL_CALL(rl_delete_wal, RL_OK, wal_path);
302
+ }
303
+ }
304
+ retval = RL_OK;
305
+ cleanup:
306
+ rl_free(wal_path);
307
+ rl_free(data);
308
+ return retval;
309
+ }