sophia-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +22 -0
- data/ext/extconf.rb +13 -0
- data/ext/sophia.c +220 -0
- data/lib/sophia-ruby.rb +1 -0
- data/lib/sophia/version.rb +3 -0
- data/sophia-ruby.gemspec +47 -0
- data/test/test_sophia.rb +33 -0
- data/vendor/sophia/.gitignore +18 -0
- data/vendor/sophia/COPYRIGHT +29 -0
- data/vendor/sophia/README +5 -0
- data/vendor/sophia/db/a.h +58 -0
- data/vendor/sophia/db/cat.c +195 -0
- data/vendor/sophia/db/cat.h +32 -0
- data/vendor/sophia/db/core.h +129 -0
- data/vendor/sophia/db/crc.c +343 -0
- data/vendor/sophia/db/crc.h +14 -0
- data/vendor/sophia/db/cursor.c +551 -0
- data/vendor/sophia/db/cursor.h +47 -0
- data/vendor/sophia/db/e.c +49 -0
- data/vendor/sophia/db/e.h +49 -0
- data/vendor/sophia/db/file.c +355 -0
- data/vendor/sophia/db/file.h +106 -0
- data/vendor/sophia/db/gc.c +71 -0
- data/vendor/sophia/db/gc.h +14 -0
- data/vendor/sophia/db/i.c +368 -0
- data/vendor/sophia/db/i.h +155 -0
- data/vendor/sophia/db/list.h +91 -0
- data/vendor/sophia/db/lock.h +77 -0
- data/vendor/sophia/db/macro.h +20 -0
- data/vendor/sophia/db/makefile +44 -0
- data/vendor/sophia/db/merge.c +662 -0
- data/vendor/sophia/db/merge.h +14 -0
- data/vendor/sophia/db/meta.h +87 -0
- data/vendor/sophia/db/recover.c +433 -0
- data/vendor/sophia/db/recover.h +14 -0
- data/vendor/sophia/db/ref.h +111 -0
- data/vendor/sophia/db/rep.c +128 -0
- data/vendor/sophia/db/rep.h +120 -0
- data/vendor/sophia/db/sophia.h +84 -0
- data/vendor/sophia/db/sp.c +626 -0
- data/vendor/sophia/db/sp.h +50 -0
- data/vendor/sophia/db/task.h +70 -0
- data/vendor/sophia/db/track.h +99 -0
- data/vendor/sophia/db/util.c +105 -0
- data/vendor/sophia/db/util.h +25 -0
- data/vendor/sophia/makefile +7 -0
- data/vendor/sophia/sophia.gyp +30 -0
- data/vendor/sophia/test/common.c +870 -0
- data/vendor/sophia/test/crash.c +492 -0
- data/vendor/sophia/test/i.c +403 -0
- data/vendor/sophia/test/limit.c +65 -0
- data/vendor/sophia/test/makefile +30 -0
- data/vendor/sophia/test/merge.c +890 -0
- data/vendor/sophia/test/recover.c +1550 -0
- data/vendor/sophia/test/test.h +66 -0
- metadata +134 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
#ifndef SP_META_H_
|
2
|
+
#define SP_META_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
/* on-disk */
|
13
|
+
|
14
|
+
typedef struct splogh splogh;
|
15
|
+
typedef struct speofh speofh;
|
16
|
+
typedef struct sppageh sppageh;
|
17
|
+
typedef struct spvh spvh;
|
18
|
+
|
19
|
+
#define SPEOF 0x00aaeefdL
|
20
|
+
#define SPMAGIC 0x00f0e0d0L
|
21
|
+
|
22
|
+
struct splogh {
|
23
|
+
uint32_t magic;
|
24
|
+
uint8_t version[2];
|
25
|
+
} sppacked;
|
26
|
+
|
27
|
+
struct speofh {
|
28
|
+
uint32_t magic;
|
29
|
+
} sppacked;
|
30
|
+
|
31
|
+
struct sppageh {
|
32
|
+
uint32_t crc;
|
33
|
+
uint64_t id;
|
34
|
+
uint16_t count;
|
35
|
+
uint32_t size;
|
36
|
+
uint32_t bsize;
|
37
|
+
} sppacked;
|
38
|
+
|
39
|
+
struct spvh {
|
40
|
+
uint32_t crc;
|
41
|
+
uint32_t size;
|
42
|
+
uint32_t voffset;
|
43
|
+
uint32_t vsize;
|
44
|
+
uint8_t flags;
|
45
|
+
char key[];
|
46
|
+
} sppacked;
|
47
|
+
|
48
|
+
/* in-memory */
|
49
|
+
|
50
|
+
typedef struct spv spv;
|
51
|
+
typedef struct sppage sppage;
|
52
|
+
|
53
|
+
#define SPSET 1
|
54
|
+
#define SPDEL 2
|
55
|
+
|
56
|
+
struct spv {
|
57
|
+
uint32_t epoch;
|
58
|
+
uint32_t crc; /* key-value crc without header */
|
59
|
+
uint16_t size;
|
60
|
+
uint8_t flags;
|
61
|
+
char key[];
|
62
|
+
/* uint32_t vsize */
|
63
|
+
/* char v[] */
|
64
|
+
} sppacked;
|
65
|
+
|
66
|
+
struct sppage {
|
67
|
+
uint64_t id;
|
68
|
+
uint64_t offset;
|
69
|
+
void *epoch;
|
70
|
+
uint32_t size;
|
71
|
+
spv *min;
|
72
|
+
spv *max;
|
73
|
+
splist link;
|
74
|
+
} sppacked;
|
75
|
+
|
76
|
+
static inline char*
|
77
|
+
sp_vv(spv *v) {
|
78
|
+
return v->key + v->size + sizeof(uint32_t);
|
79
|
+
}
|
80
|
+
|
81
|
+
static inline uint32_t
|
82
|
+
sp_vvsize(spv *v) {
|
83
|
+
register char *p = (char*)(v->key + v->size);
|
84
|
+
return *(uint32_t*)p;
|
85
|
+
}
|
86
|
+
|
87
|
+
#endif
|
@@ -0,0 +1,433 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
* sophia database
|
4
|
+
* sphia.org
|
5
|
+
*
|
6
|
+
* Copyright (c) Dmitry Simonenko
|
7
|
+
* BSD License
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <sp.h>
|
11
|
+
#include <track.h>
|
12
|
+
#include <ctype.h>
|
13
|
+
#include <sys/types.h>
|
14
|
+
#include <sys/stat.h>
|
15
|
+
#include <dirent.h>
|
16
|
+
#include <unistd.h>
|
17
|
+
|
18
|
+
static inline int sp_dircreate(sp *s) {
|
19
|
+
int rc = mkdir(s->e->dir, 0700);
|
20
|
+
if (spunlikely(rc == -1)) {
|
21
|
+
sp_e(s, SPE, "failed to create directory %s (errno: %d, %s)",
|
22
|
+
s->e->dir, errno, strerror(errno));
|
23
|
+
return -1;
|
24
|
+
}
|
25
|
+
return 0;
|
26
|
+
}
|
27
|
+
|
28
|
+
static inline ssize_t
|
29
|
+
sp_epochof(char *s) {
|
30
|
+
size_t v = 0;
|
31
|
+
while (*s && *s != '.') {
|
32
|
+
if (spunlikely(!isdigit(*s)))
|
33
|
+
return -1;
|
34
|
+
v = (v * 10) + *s - '0';
|
35
|
+
s++;
|
36
|
+
}
|
37
|
+
return v;
|
38
|
+
}
|
39
|
+
|
40
|
+
static int sp_diropen(sp *s)
|
41
|
+
{
|
42
|
+
/* read repository and determine states */
|
43
|
+
DIR *d = opendir(s->e->dir);
|
44
|
+
if (spunlikely(d == NULL)) {
|
45
|
+
sp_e(s, SPE, "failed to open directory %s (errno: %d, %s)",
|
46
|
+
s->e->dir, errno, strerror(errno));
|
47
|
+
return -1;
|
48
|
+
}
|
49
|
+
struct dirent *de;
|
50
|
+
while ((de = readdir(d))) {
|
51
|
+
if (*de->d_name == '.')
|
52
|
+
continue;
|
53
|
+
ssize_t epoch = sp_epochof(de->d_name);
|
54
|
+
if (epoch == -1)
|
55
|
+
continue;
|
56
|
+
spepoch *e = sp_repmatch(&s->rep, epoch);
|
57
|
+
if (e == NULL) {
|
58
|
+
e = sp_repalloc(&s->rep, epoch);
|
59
|
+
if (spunlikely(e == NULL)) {
|
60
|
+
closedir(d);
|
61
|
+
sp_e(s, SPEOOM, "failed to allocate repository");
|
62
|
+
return -1;
|
63
|
+
}
|
64
|
+
sp_repattach(&s->rep, e);
|
65
|
+
}
|
66
|
+
char *ext = strstr(de->d_name, ".db");
|
67
|
+
if (ext) {
|
68
|
+
ext = strstr(de->d_name, ".incomplete");
|
69
|
+
e->recover |= (ext? SPRDBI: SPRDB);
|
70
|
+
continue;
|
71
|
+
}
|
72
|
+
ext = strstr(de->d_name, ".log");
|
73
|
+
if (ext) {
|
74
|
+
ext = strstr(de->d_name, ".incomplete");
|
75
|
+
e->recover |= (ext? SPRLOGI: SPRLOG);
|
76
|
+
}
|
77
|
+
continue;
|
78
|
+
}
|
79
|
+
closedir(d);
|
80
|
+
if (s->rep.n == 0)
|
81
|
+
return 0;
|
82
|
+
/* set current and sort by epoch */
|
83
|
+
int rc = sp_repprepare(&s->rep);
|
84
|
+
if (spunlikely(rc == -1))
|
85
|
+
return sp_e(s, SPEOOM, "failed to allocate repository");
|
86
|
+
return 0;
|
87
|
+
}
|
88
|
+
|
89
|
+
static int sp_recoverdb(sp *s, spepoch *x, sptrack *t)
|
90
|
+
{
|
91
|
+
int rc = sp_mapepoch(&x->db, s->e->dir, x->epoch, "db");
|
92
|
+
if (spunlikely(rc == -1))
|
93
|
+
return sp_e(s, SPEIO, "failed to open db file", x->epoch);
|
94
|
+
|
95
|
+
sppageh *h = (sppageh*)(x->db.map);
|
96
|
+
|
97
|
+
for(;;)
|
98
|
+
{
|
99
|
+
if (spunlikely((uint64_t)((char*)h - x->db.map) >= x->db.size))
|
100
|
+
break;
|
101
|
+
|
102
|
+
/* validate header */
|
103
|
+
uint32_t crc = sp_crc32c(0, &h->id, sizeof(sppageh) - sizeof(h->crc));
|
104
|
+
if (crc != h->crc) {
|
105
|
+
sp_mapclose(&x->db);
|
106
|
+
return sp_e(s, SPE, "page crc failed %"PRIu32".db", x->epoch);
|
107
|
+
}
|
108
|
+
assert(h->id > 0);
|
109
|
+
|
110
|
+
x->n++;
|
111
|
+
x->nupdate += h->count;
|
112
|
+
|
113
|
+
/* match page in hash by h.id, skip if matched */
|
114
|
+
if (sp_trackhas(t, h->id)) {
|
115
|
+
/* skip to a next page */
|
116
|
+
h = (sppageh*)((char*)h + sizeof(sppageh) + h->size);
|
117
|
+
x->ngc++;
|
118
|
+
continue;
|
119
|
+
}
|
120
|
+
|
121
|
+
/* track page id */
|
122
|
+
rc = sp_trackset(t, h->id);
|
123
|
+
if (spunlikely(rc == -1)) {
|
124
|
+
sp_mapclose(&x->db);
|
125
|
+
return sp_e(s, SPEOOM, "failed to allocate track item");
|
126
|
+
}
|
127
|
+
|
128
|
+
/* if this is a page delete marker, then skip to
|
129
|
+
* a next page */
|
130
|
+
if (h->count == 0) {
|
131
|
+
h = (sppageh*)((char*)h + sizeof(sppageh) + h->size);
|
132
|
+
continue;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* set page min (first block)*/
|
136
|
+
spvh *minp = (spvh*)((char*)h + sizeof(sppageh));
|
137
|
+
crc = sp_crc32c(0, minp->key, minp->size);
|
138
|
+
crc = sp_crc32c(crc, (char*)h + minp->voffset, minp->vsize);
|
139
|
+
crc = sp_crc32c(crc, (char*)&minp->size, sizeof(spvh) - sizeof(minp->crc));
|
140
|
+
if (crc != minp->crc) {
|
141
|
+
sp_mapclose(&x->db);
|
142
|
+
return sp_e(s, SPE, "page min key crc failed %"PRIu32".db", x->epoch);
|
143
|
+
}
|
144
|
+
assert(minp->flags == SPSET);
|
145
|
+
|
146
|
+
/* set page max (last block) */
|
147
|
+
spvh *maxp = (spvh*)((char*)h + sizeof(sppageh) + h->bsize * (h->count - 1));
|
148
|
+
crc = sp_crc32c(0, maxp->key, maxp->size);
|
149
|
+
crc = sp_crc32c(crc, (char*)h + maxp->voffset, maxp->vsize);
|
150
|
+
crc = sp_crc32c(crc, (char*)&maxp->size, sizeof(spvh) - sizeof(maxp->crc));
|
151
|
+
if (crc != maxp->crc) {
|
152
|
+
sp_mapclose(&x->db);
|
153
|
+
return sp_e(s, SPE, "page max key crc failed %"PRIu32".db", x->epoch);
|
154
|
+
}
|
155
|
+
assert(maxp->flags == SPSET);
|
156
|
+
|
157
|
+
spv *min = sp_vnewh(s, minp);
|
158
|
+
if (spunlikely(min == NULL)) {
|
159
|
+
sp_mapclose(&x->db);
|
160
|
+
return sp_e(s, SPEOOM, "failed to allocate key");
|
161
|
+
}
|
162
|
+
assert(min->flags == SPSET);
|
163
|
+
min->epoch = x->epoch;
|
164
|
+
|
165
|
+
spv *max = sp_vnewh(s, maxp);
|
166
|
+
if (spunlikely(max == NULL)) {
|
167
|
+
sp_free(&s->a, min);
|
168
|
+
sp_mapclose(&x->db);
|
169
|
+
return sp_e(s, SPEOOM, "failed to allocate key");
|
170
|
+
}
|
171
|
+
assert(max->flags == SPSET);
|
172
|
+
max->epoch = x->epoch;
|
173
|
+
|
174
|
+
/* allocate and insert new page */
|
175
|
+
sppage *page = sp_pagenew(s, x);
|
176
|
+
if (spunlikely(page == NULL)) {
|
177
|
+
sp_free(&s->a, min);
|
178
|
+
sp_free(&s->a, max);
|
179
|
+
sp_mapclose(&x->db);
|
180
|
+
return sp_e(s, SPEOOM, "failed to allocate page");
|
181
|
+
}
|
182
|
+
page->id = h->id;
|
183
|
+
page->offset = (char*)h - x->db.map;
|
184
|
+
page->size = sizeof(sppageh) + h->size;
|
185
|
+
page->min = min;
|
186
|
+
page->max = max;
|
187
|
+
|
188
|
+
sppage *o = NULL;
|
189
|
+
rc = sp_catset(&s->s, page, &o);
|
190
|
+
if (spunlikely(rc == -1)) {
|
191
|
+
sp_pagefree(s, page);
|
192
|
+
sp_mapclose(&x->db);
|
193
|
+
return sp_e(s, SPEOOM, "failed to allocate page index page");
|
194
|
+
}
|
195
|
+
assert(o == NULL);
|
196
|
+
|
197
|
+
/* attach page to the source */
|
198
|
+
sp_pageattach(page);
|
199
|
+
|
200
|
+
/* skip to a next page */
|
201
|
+
h = (sppageh*)((char*)h + sizeof(sppageh) + h->size);
|
202
|
+
}
|
203
|
+
|
204
|
+
return 0;
|
205
|
+
}
|
206
|
+
|
207
|
+
static int sp_recoverlog(sp *s, spepoch *x, int incomplete)
|
208
|
+
{
|
209
|
+
/* open and map log file */
|
210
|
+
char *ext = (incomplete ? "log.incomplete" : "log");
|
211
|
+
int rc;
|
212
|
+
rc = sp_mapepoch(&x->log, s->e->dir, x->epoch, ext);
|
213
|
+
if (spunlikely(rc == -1))
|
214
|
+
return sp_e(s, SPEIO, "failed to open log file", x->epoch);
|
215
|
+
|
216
|
+
/* validate log header */
|
217
|
+
if (spunlikely(! sp_mapinbound(&x->log, sizeof(splogh)) ))
|
218
|
+
return sp_e(s, SPE, "bad log file %"PRIu32".log", x->epoch);
|
219
|
+
|
220
|
+
splogh *h = (splogh*)(x->log.map);
|
221
|
+
if (spunlikely(h->magic != SPMAGIC))
|
222
|
+
return sp_e(s, SPE, "log bad magic %"PRIu32".log", x->epoch);
|
223
|
+
if (spunlikely(h->version[0] != SP_VERSION_MAJOR &&
|
224
|
+
h->version[1] != SP_VERSION_MINOR))
|
225
|
+
return sp_e(s, SPE, "unknown file version of %"PRIu32".log", x->epoch);
|
226
|
+
|
227
|
+
uint64_t offset = sizeof(splogh);
|
228
|
+
uint32_t unique = 0;
|
229
|
+
int eof = 0;
|
230
|
+
while (offset < x->log.size)
|
231
|
+
{
|
232
|
+
/* check for a eof */
|
233
|
+
if (spunlikely(offset == (x->log.size - sizeof(speofh)))) {
|
234
|
+
speofh *eofh = (speofh*)(x->log.map + offset);
|
235
|
+
if (eofh->magic != SPEOF) {
|
236
|
+
sp_mapclose(&x->log);
|
237
|
+
return sp_e(s, SPE, "bad log eof magic %"PRIu32".log", x->epoch);
|
238
|
+
}
|
239
|
+
eof++;
|
240
|
+
offset += sizeof(speofh);
|
241
|
+
break;
|
242
|
+
}
|
243
|
+
|
244
|
+
/* validate a record */
|
245
|
+
if (spunlikely(! sp_mapinbound(&x->log, offset + sizeof(spvh)) )) {
|
246
|
+
sp_mapclose(&x->log);
|
247
|
+
return sp_e(s, SPE, "log file corrupted %"PRIu32".log", x->epoch);
|
248
|
+
}
|
249
|
+
spvh *vh = (spvh*)(x->log.map + offset);
|
250
|
+
|
251
|
+
uint32_t crc0, crc1;
|
252
|
+
crc0 = sp_crc32c(0, vh->key, vh->size);
|
253
|
+
crc0 = sp_crc32c(crc0, vh->key + vh->size, vh->vsize);
|
254
|
+
crc1 = sp_crc32c(crc0, &vh->size, sizeof(spvh) - sizeof(vh->crc));
|
255
|
+
if (spunlikely(crc1 != vh->crc)) {
|
256
|
+
sp_mapclose(&x->log);
|
257
|
+
return sp_e(s, SPE, "log record crc failed %"PRIu32".log", x->epoch);
|
258
|
+
}
|
259
|
+
|
260
|
+
int c0 = vh->flags != SPSET && vh->flags != SPDEL;
|
261
|
+
int c1 = vh->voffset != 0;
|
262
|
+
int c2 = !sp_mapinbound(&x->log, offset + sizeof(spvh) + vh->size +
|
263
|
+
vh->vsize);
|
264
|
+
|
265
|
+
if (spunlikely((c0 + c1 + c2) > 0)) {
|
266
|
+
sp_mapclose(&x->log);
|
267
|
+
return sp_e(s, SPE, "bad log record %"PRIu32".log", x->epoch);
|
268
|
+
}
|
269
|
+
|
270
|
+
/* add a key to the key index.
|
271
|
+
*
|
272
|
+
* key index have only actual key, replace should be done
|
273
|
+
* within the same epoch by a newest records only and skipped
|
274
|
+
* in a older epochs.
|
275
|
+
*/
|
276
|
+
spv *v = sp_vnewv(s, vh->key, vh->size, vh->key + vh->size, vh->vsize);
|
277
|
+
if (spunlikely(v == NULL)) {
|
278
|
+
sp_mapclose(&x->log);
|
279
|
+
return sp_e(s, SPEOOM, "failed to allocate key");
|
280
|
+
}
|
281
|
+
v->flags = vh->flags;
|
282
|
+
v->epoch = x->epoch;
|
283
|
+
v->crc = crc0;
|
284
|
+
|
285
|
+
spii pos;
|
286
|
+
switch (sp_isetorget(s->i, v, &pos)) {
|
287
|
+
case 1: {
|
288
|
+
spv *old = sp_ival(&pos);
|
289
|
+
if (old->epoch == x->epoch) {
|
290
|
+
sp_ivalset(&pos, v);
|
291
|
+
sp_free(&s->a, old);
|
292
|
+
} else {
|
293
|
+
sp_free(&s->a, v);
|
294
|
+
}
|
295
|
+
break;
|
296
|
+
}
|
297
|
+
case 0:
|
298
|
+
unique++;
|
299
|
+
break;
|
300
|
+
case -1:
|
301
|
+
sp_mapclose(&x->log);
|
302
|
+
return sp_e(s, SPEOOM, "failed to allocate key index page");
|
303
|
+
}
|
304
|
+
|
305
|
+
offset += sizeof(spvh) + vh->size + vh->vsize;
|
306
|
+
x->nupdate++;
|
307
|
+
}
|
308
|
+
|
309
|
+
if ((offset > x->log.size) || ((offset < x->log.size) && !eof)) {
|
310
|
+
sp_mapclose(&x->log);
|
311
|
+
return sp_e(s, SPE, "log file corrupted %"PRIu32".log", x->epoch);
|
312
|
+
}
|
313
|
+
|
314
|
+
/* unmap file only, unlink-close will ocurre in merge or
|
315
|
+
* during shutdown */
|
316
|
+
rc = sp_mapunmap(&x->log);
|
317
|
+
if (spunlikely(rc == -1))
|
318
|
+
return sp_e(s, SPEIO, "failed to unmap log file", x->epoch);
|
319
|
+
|
320
|
+
/*
|
321
|
+
* if there is eof marker missing, try to add one
|
322
|
+
* (only for incomplete files), otherwise indicate corrupt
|
323
|
+
*/
|
324
|
+
if (incomplete == 0 && !eof)
|
325
|
+
return sp_e(s, SPE, "bad log eof marker %"PRIu32".log", x->epoch);
|
326
|
+
|
327
|
+
if (incomplete) {
|
328
|
+
if (! eof) {
|
329
|
+
rc = sp_logclose(&x->log);
|
330
|
+
if (spunlikely(rc == -1))
|
331
|
+
return sp_e(s, SPEIO, "failed to close log file", x->epoch);
|
332
|
+
rc = sp_logcontinue(&x->log, s->e->dir, x->epoch);
|
333
|
+
if (spunlikely(rc == -1)) {
|
334
|
+
sp_logclose(&x->log);
|
335
|
+
return sp_e(s, SPEIO, "failed to reopen log file", x->epoch);
|
336
|
+
}
|
337
|
+
rc = sp_logeof(&x->log);
|
338
|
+
if (spunlikely(rc == -1)) {
|
339
|
+
sp_logclose(&x->log);
|
340
|
+
return sp_e(s, SPEIO, "failed to add eof marker", x->epoch);
|
341
|
+
}
|
342
|
+
}
|
343
|
+
rc = sp_logcompleteforce(&x->log);
|
344
|
+
if (spunlikely(rc == -1)) {
|
345
|
+
sp_logclose(&x->log);
|
346
|
+
return sp_e(s, SPEIO, "failed to complete log file", x->epoch);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
return 0;
|
350
|
+
}
|
351
|
+
|
352
|
+
static int sp_dirrecover(sp *s)
|
353
|
+
{
|
354
|
+
sptrack t;
|
355
|
+
int rc = sp_trackinit(&t, &s->a, 1024);
|
356
|
+
if (spunlikely(rc == -1))
|
357
|
+
return sp_e(s, SPEOOM, "failed to allocate track");
|
358
|
+
|
359
|
+
/* recover from yongest epochs (biggest numbers) */
|
360
|
+
splist *i;
|
361
|
+
sp_listforeach_reverse(&s->rep.l, i){
|
362
|
+
spepoch *e = spcast(i, spepoch, link);
|
363
|
+
switch (e->recover) {
|
364
|
+
case SPRDB|SPRLOG:
|
365
|
+
case SPRDB:
|
366
|
+
sp_repset(&s->rep, e, SPDB);
|
367
|
+
rc = sp_recoverdb(s, e, &t);
|
368
|
+
if (spunlikely(rc == -1))
|
369
|
+
goto err;
|
370
|
+
if (e->recover == (SPRDB|SPRLOG)) {
|
371
|
+
rc = sp_epochrm(s->e->dir, e->epoch, "log");
|
372
|
+
if (spunlikely(rc == -1))
|
373
|
+
goto err;
|
374
|
+
}
|
375
|
+
break;
|
376
|
+
case SPRLOG|SPRDBI:
|
377
|
+
rc = sp_epochrm(s->e->dir, e->epoch, "db.incomplete");
|
378
|
+
if (spunlikely(rc == -1))
|
379
|
+
goto err;
|
380
|
+
case SPRLOG:
|
381
|
+
sp_repset(&s->rep, e, SPXFER);
|
382
|
+
rc = sp_recoverlog(s, e, 0);
|
383
|
+
if (spunlikely(rc == -1))
|
384
|
+
goto err;
|
385
|
+
break;
|
386
|
+
case SPRLOGI:
|
387
|
+
sp_repset(&s->rep, e, SPXFER);
|
388
|
+
rc = sp_recoverlog(s, e, 1);
|
389
|
+
if (spunlikely(rc == -1))
|
390
|
+
goto err;
|
391
|
+
break;
|
392
|
+
default:
|
393
|
+
/* corrupted states: */
|
394
|
+
/* db.incomplete */
|
395
|
+
/* log.incomplete + db.incomplete */
|
396
|
+
/* log.incomplete + db */
|
397
|
+
sp_trackfree(&t);
|
398
|
+
return sp_e(s, SPE, "repository is corrupted");
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
/*
|
403
|
+
* set maximum loaded psn as current one.
|
404
|
+
*/
|
405
|
+
s->psn = t.max;
|
406
|
+
|
407
|
+
sp_trackfree(&t);
|
408
|
+
return 0;
|
409
|
+
err:
|
410
|
+
sp_trackfree(&t);
|
411
|
+
return -1;
|
412
|
+
}
|
413
|
+
|
414
|
+
int sp_recover(sp *s)
|
415
|
+
{
|
416
|
+
int exists = sp_fileexists(s->e->dir);
|
417
|
+
int rc;
|
418
|
+
if (!exists) {
|
419
|
+
if (! (s->e->flags & SPO_CREAT))
|
420
|
+
return sp_e(s, SPE, "directory doesn't exists and no SPO_CREAT specified");
|
421
|
+
if (s->e->flags & SPO_RDONLY)
|
422
|
+
return sp_e(s, SPE, "directory doesn't exists");
|
423
|
+
rc = sp_dircreate(s);
|
424
|
+
} else {
|
425
|
+
rc = sp_diropen(s);
|
426
|
+
if (spunlikely(rc == -1))
|
427
|
+
return -1;
|
428
|
+
if (s->rep.n == 0)
|
429
|
+
return 0;
|
430
|
+
rc = sp_dirrecover(s);
|
431
|
+
}
|
432
|
+
return rc;
|
433
|
+
}
|