sophia-ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,155 @@
|
|
1
|
+
#ifndef SP_I_H_
|
2
|
+
#define SP_I_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
typedef struct spipage spipage;
|
13
|
+
typedef struct spi spi;
|
14
|
+
typedef struct spii spii;
|
15
|
+
|
16
|
+
struct spipage {
|
17
|
+
uint16_t count;
|
18
|
+
spv *i[];
|
19
|
+
} sppacked;
|
20
|
+
|
21
|
+
struct spi {
|
22
|
+
spa *a;
|
23
|
+
int pagesize;
|
24
|
+
spipage **i;
|
25
|
+
uint32_t itop;
|
26
|
+
uint32_t icount;
|
27
|
+
uint32_t count;
|
28
|
+
spcmpf cmp;
|
29
|
+
void *cmparg;
|
30
|
+
};
|
31
|
+
|
32
|
+
struct spii {
|
33
|
+
spi *i;
|
34
|
+
long long p, n;
|
35
|
+
};
|
36
|
+
|
37
|
+
int sp_iinit(spi*, spa*, int, spcmpf, void*);
|
38
|
+
void sp_ifree(spi*);
|
39
|
+
int sp_itruncate(spi*);
|
40
|
+
int sp_isetorget(spi *i, spv*, spii*);
|
41
|
+
int sp_idelraw(spi*, char*, int, spv**);
|
42
|
+
spv *sp_igetraw(spi*, char*, int);
|
43
|
+
|
44
|
+
static inline int
|
45
|
+
sp_idel(spi *i, spv *v, spv **old) {
|
46
|
+
return sp_idelraw(i, v->key, v->size, old);
|
47
|
+
}
|
48
|
+
|
49
|
+
static inline spv*
|
50
|
+
sp_iget(spi *i, spv *v) {
|
51
|
+
return sp_igetraw(i, v->key, v->size);
|
52
|
+
}
|
53
|
+
|
54
|
+
static inline void*
|
55
|
+
sp_imax(spi *i) {
|
56
|
+
if (spunlikely(i->count == 0))
|
57
|
+
return NULL;
|
58
|
+
return i->i[i->icount-1]->i[i->i[i->icount-1]->count-1];
|
59
|
+
}
|
60
|
+
|
61
|
+
static inline void
|
62
|
+
sp_ifirst(spii *it) {
|
63
|
+
it->p = 0;
|
64
|
+
it->n = 0;
|
65
|
+
}
|
66
|
+
|
67
|
+
static inline void
|
68
|
+
sp_ilast(spii *it) {
|
69
|
+
it->p = it->i->icount - 1;
|
70
|
+
it->n = it->i->i[it->i->icount - 1]->count - 1;
|
71
|
+
}
|
72
|
+
|
73
|
+
static inline void
|
74
|
+
sp_iopen(spii *it, spi *i) {
|
75
|
+
it->i = i;
|
76
|
+
sp_ifirst(it);
|
77
|
+
}
|
78
|
+
|
79
|
+
static inline int
|
80
|
+
sp_ihas(spii *it) {
|
81
|
+
return (it->p >= 0 && it->n >= 0) &&
|
82
|
+
(it->p < it->i->icount) &&
|
83
|
+
(it->n < it->i->i[it->p]->count);
|
84
|
+
}
|
85
|
+
|
86
|
+
static inline void
|
87
|
+
sp_ivalset(spii *it, spv *v) {
|
88
|
+
it->i->i[it->p]->i[it->n] = v;
|
89
|
+
}
|
90
|
+
|
91
|
+
static inline spv*
|
92
|
+
sp_ival(spii *it) {
|
93
|
+
if (spunlikely(! sp_ihas(it)))
|
94
|
+
return NULL;
|
95
|
+
return it->i->i[it->p]->i[it->n];
|
96
|
+
}
|
97
|
+
|
98
|
+
static inline int
|
99
|
+
sp_inext(spii *it) {
|
100
|
+
if (spunlikely(! sp_ihas(it)))
|
101
|
+
return 0;
|
102
|
+
it->n++;
|
103
|
+
while (it->p < it->i->icount) {
|
104
|
+
spipage *p = it->i->i[it->p];
|
105
|
+
if (spunlikely(it->n >= p->count)) {
|
106
|
+
it->p++;
|
107
|
+
it->n = 0;
|
108
|
+
continue;
|
109
|
+
}
|
110
|
+
return 1;
|
111
|
+
}
|
112
|
+
return 0;
|
113
|
+
}
|
114
|
+
|
115
|
+
static inline int
|
116
|
+
sp_iprev(spii *it) {
|
117
|
+
if (spunlikely(! sp_ihas(it)))
|
118
|
+
return 0;
|
119
|
+
it->n--;
|
120
|
+
while (it->p >= 0) {
|
121
|
+
if (spunlikely(it->n < 0)) {
|
122
|
+
if (it->p == 0)
|
123
|
+
return 0;
|
124
|
+
it->p--;
|
125
|
+
it->n = it->i->i[it->p]->count-1;
|
126
|
+
continue;
|
127
|
+
}
|
128
|
+
return 1;
|
129
|
+
}
|
130
|
+
return 0;
|
131
|
+
}
|
132
|
+
|
133
|
+
static inline void
|
134
|
+
sp_iinv(spi *i, spii *ii) {
|
135
|
+
ii->i = i;
|
136
|
+
ii->p = -1;
|
137
|
+
ii->n = -1;
|
138
|
+
}
|
139
|
+
|
140
|
+
int sp_ilte(spi*, spii*, char*, int);
|
141
|
+
int sp_igte(spi*, spii*, char*, int);
|
142
|
+
|
143
|
+
static inline int
|
144
|
+
sp_iset(spi *i, spv *v, spv **old)
|
145
|
+
{
|
146
|
+
spii pos;
|
147
|
+
int rc = sp_isetorget(i, v, &pos);
|
148
|
+
if (splikely(rc <= 0))
|
149
|
+
return rc;
|
150
|
+
*old = sp_ival(&pos);
|
151
|
+
sp_ivalset(&pos, v);
|
152
|
+
return 1;
|
153
|
+
}
|
154
|
+
|
155
|
+
#endif
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#ifndef SP_LIST_H_
|
2
|
+
#define SP_LIST_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
typedef struct splist splist;
|
13
|
+
|
14
|
+
struct splist {
|
15
|
+
splist *next, *prev;
|
16
|
+
};
|
17
|
+
|
18
|
+
static inline void
|
19
|
+
sp_listinit(splist *h) {
|
20
|
+
h->next = h->prev = h;
|
21
|
+
}
|
22
|
+
|
23
|
+
static inline void
|
24
|
+
sp_listappend(splist *h, splist *n) {
|
25
|
+
n->next = h;
|
26
|
+
n->prev = h->prev;
|
27
|
+
n->prev->next = n;
|
28
|
+
n->next->prev = n;
|
29
|
+
}
|
30
|
+
|
31
|
+
static inline void
|
32
|
+
sp_listunlink(splist *n) {
|
33
|
+
n->prev->next = n->next;
|
34
|
+
n->next->prev = n->prev;
|
35
|
+
}
|
36
|
+
|
37
|
+
static inline void
|
38
|
+
sp_listpush(splist *h, splist *n) {
|
39
|
+
n->next = h->next;
|
40
|
+
n->prev = h;
|
41
|
+
n->prev->next = n;
|
42
|
+
n->next->prev = n;
|
43
|
+
}
|
44
|
+
|
45
|
+
static inline splist*
|
46
|
+
sp_listpop(splist *h) {
|
47
|
+
register splist *pop = h->next;
|
48
|
+
sp_listunlink(pop);
|
49
|
+
return pop;
|
50
|
+
}
|
51
|
+
|
52
|
+
static inline int
|
53
|
+
sp_listempty(splist *l) {
|
54
|
+
return l->next == l && l->prev == l;
|
55
|
+
}
|
56
|
+
|
57
|
+
static inline void
|
58
|
+
sp_listmerge(splist *a, splist *b) {
|
59
|
+
if (spunlikely(sp_listempty(b)))
|
60
|
+
return;
|
61
|
+
register splist *first = b->next;
|
62
|
+
register splist *last = b->prev;
|
63
|
+
first->prev = a->prev;
|
64
|
+
a->prev->next = first;
|
65
|
+
last->next = a;
|
66
|
+
a->prev = last;
|
67
|
+
}
|
68
|
+
|
69
|
+
static inline void
|
70
|
+
sp_listreplace(splist *o, splist *n) {
|
71
|
+
n->next = o->next;
|
72
|
+
n->next->prev = n;
|
73
|
+
n->prev = o->prev;
|
74
|
+
n->prev->next = n;
|
75
|
+
}
|
76
|
+
|
77
|
+
#define sp_listlast(H, N) ((H) == (N))
|
78
|
+
|
79
|
+
#define sp_listforeach(H, I) \
|
80
|
+
for (I = (H)->next; I != H; I = (I)->next)
|
81
|
+
|
82
|
+
#define sp_listforeach_continue(H, I) \
|
83
|
+
for (; I != H; I = (I)->next)
|
84
|
+
|
85
|
+
#define sp_listforeach_safe(H, I, N) \
|
86
|
+
for (I = (H)->next; I != H && (N = I->next); I = N)
|
87
|
+
|
88
|
+
#define sp_listforeach_reverse(H, I) \
|
89
|
+
for (I = (H)->prev; I != H; I = (I)->prev)
|
90
|
+
|
91
|
+
#endif
|
@@ -0,0 +1,77 @@
|
|
1
|
+
#ifndef SP_LOCK_H_
|
2
|
+
#define SP_LOCK_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
#include <unistd.h>
|
13
|
+
|
14
|
+
typedef uint8_t spspinlock;
|
15
|
+
|
16
|
+
#if defined(__x86_64__) || defined(__i386) || defined(_X86_)
|
17
|
+
# define CPU_PAUSE __asm__ ("pause")
|
18
|
+
#else
|
19
|
+
# define CPU_PAUSE do { } while(0)
|
20
|
+
#endif
|
21
|
+
|
22
|
+
static inline void
|
23
|
+
sp_lockinit(volatile spspinlock *l) {
|
24
|
+
*l = 0;
|
25
|
+
}
|
26
|
+
|
27
|
+
static inline void
|
28
|
+
sp_lockfree(volatile spspinlock *l) {
|
29
|
+
*l = 0;
|
30
|
+
}
|
31
|
+
|
32
|
+
static inline void
|
33
|
+
sp_lock(volatile spspinlock *l) {
|
34
|
+
if (__sync_lock_test_and_set(l, 1) != 0) {
|
35
|
+
unsigned int spin_count = 0U;
|
36
|
+
for (;;) {
|
37
|
+
CPU_PAUSE;
|
38
|
+
if (*l == 0U && __sync_lock_test_and_set(l, 1) == 0)
|
39
|
+
break;
|
40
|
+
if (++spin_count > 100U)
|
41
|
+
usleep(0);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
static inline void
|
47
|
+
sp_unlock(volatile spspinlock *l) {
|
48
|
+
__sync_lock_release(l);
|
49
|
+
}
|
50
|
+
|
51
|
+
#if 0
|
52
|
+
#include <pthread.h>
|
53
|
+
|
54
|
+
typedef pthread_spinlock_t spspinlock;
|
55
|
+
|
56
|
+
static inline void
|
57
|
+
sp_lockinit(volatile spspinlock *l) {
|
58
|
+
pthread_spin_init(l, 0);
|
59
|
+
}
|
60
|
+
|
61
|
+
static inline void
|
62
|
+
sp_lockfree(volatile spspinlock *l) {
|
63
|
+
pthread_spin_destroy(l);
|
64
|
+
}
|
65
|
+
|
66
|
+
static inline void
|
67
|
+
sp_lock(volatile spspinlock *l) {
|
68
|
+
pthread_spin_lock(l);
|
69
|
+
}
|
70
|
+
|
71
|
+
static inline void
|
72
|
+
sp_unlock(volatile spspinlock *l) {
|
73
|
+
pthread_spin_unlock(l);
|
74
|
+
}
|
75
|
+
#endif
|
76
|
+
|
77
|
+
#endif
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#ifndef SP_MACRO_H_
|
2
|
+
#define SP_MACRO_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
#define sppacked __attribute__((packed))
|
13
|
+
#define spunused __attribute__((unused))
|
14
|
+
#define sphot __attribute__((hot))
|
15
|
+
#define splikely(EXPR) __builtin_expect(!! (EXPR), 1)
|
16
|
+
#define spunlikely(EXPR) __builtin_expect(!! (EXPR), 0)
|
17
|
+
#define spdiv(a, b) ((a) + (b) - 1) / (b)
|
18
|
+
#define spcast(N, T, F) ((T*)((char*)(N) - __builtin_offsetof(T, F)))
|
19
|
+
|
20
|
+
#endif
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# sophia makefile.
|
4
|
+
#
|
5
|
+
CC ?= gcc
|
6
|
+
RM ?= rm
|
7
|
+
LN ?= ln
|
8
|
+
VERMAJOR = 1
|
9
|
+
VERMINOR = 1
|
10
|
+
TARGET_STATIC = libsophia.a
|
11
|
+
TARGET_DSOLIB = libsophia.so.$(VERMAJOR).$(VERMINOR)
|
12
|
+
TARGET_DSO = libsophia.so
|
13
|
+
CFLAGS ?= -I. -std=c99 -pedantic -Wextra -Wall -pthread -O2 -DNDEBUG -fPIC
|
14
|
+
LDFLAGS ?= -shared -soname libsophia.$(VERMAJOR)
|
15
|
+
|
16
|
+
OBJS = file.o \
|
17
|
+
crc.o \
|
18
|
+
e.o \
|
19
|
+
i.o \
|
20
|
+
cat.o \
|
21
|
+
rep.o \
|
22
|
+
util.o \
|
23
|
+
sp.o \
|
24
|
+
recover.o \
|
25
|
+
merge.o \
|
26
|
+
gc.o \
|
27
|
+
cursor.o
|
28
|
+
|
29
|
+
ALL: $(TARGET_STATIC) $(TARGET_DSO)
|
30
|
+
|
31
|
+
$(TARGET_STATIC): clean $(OBJS)
|
32
|
+
$(AR) cru $(TARGET_STATIC) $(OBJS)
|
33
|
+
|
34
|
+
$(TARGET_DSO): clean $(OBJS)
|
35
|
+
$(LD) $(OBJS) $(LDFLAGS) -o $(TARGET_DSOLIB)
|
36
|
+
$(LN) -s $(TARGET_DSOLIB) $(TARGET_DSO).$(VERMAJOR)
|
37
|
+
$(LN) -s $(TARGET_DSOLIB) $(TARGET_DSO)
|
38
|
+
|
39
|
+
.c.o:
|
40
|
+
$(CC) $(CFLAGS) -c $<
|
41
|
+
|
42
|
+
clean:
|
43
|
+
$(RM) -f $(OBJS) $(TARGET_STATIC)
|
44
|
+
$(RM) -f $(TARGET_DSOLIB) $(TARGET_DSO).$(VERMAJOR) $(TARGET_DSO)
|
@@ -0,0 +1,662 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
* sophia database
|
4
|
+
* sphia.org
|
5
|
+
*
|
6
|
+
* Copyright (c) Dmitry Simonenko
|
7
|
+
* BSD License
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <sp.h>
|
11
|
+
|
12
|
+
typedef struct {
|
13
|
+
uint32_t count;
|
14
|
+
uint32_t psize;
|
15
|
+
uint32_t bsize;
|
16
|
+
} spupdate0;
|
17
|
+
|
18
|
+
static inline void
|
19
|
+
sp_mergeget0(spii *pos, uint32_t n, spupdate0 *u)
|
20
|
+
{
|
21
|
+
memset(u, 0, sizeof(*u));
|
22
|
+
/*
|
23
|
+
* collect n or less versions for scheduled page write,
|
24
|
+
* not marked as delete, calculate page size and the
|
25
|
+
* block size.
|
26
|
+
*/
|
27
|
+
spii i = *pos;
|
28
|
+
while (u->count < n && sp_ihas(&i)) {
|
29
|
+
spv *v = sp_ival(&i);
|
30
|
+
if (v->flags & SPDEL) {
|
31
|
+
sp_inext(&i);
|
32
|
+
continue;
|
33
|
+
}
|
34
|
+
if (v->size > u->bsize)
|
35
|
+
u->bsize = v->size;
|
36
|
+
sp_inext(&i);
|
37
|
+
u->count++;
|
38
|
+
u->psize += sp_vvsize(v);
|
39
|
+
}
|
40
|
+
u->bsize += sizeof(spvh);
|
41
|
+
u->psize += sizeof(sppageh) + u->bsize * u->count;
|
42
|
+
}
|
43
|
+
|
44
|
+
static inline int sp_merge0(sp *s, spepoch *x, spi *index)
|
45
|
+
{
|
46
|
+
spv *max = NULL;
|
47
|
+
spv *min = NULL;
|
48
|
+
int rc;
|
49
|
+
spii i;
|
50
|
+
sp_iopen(&i, index);
|
51
|
+
|
52
|
+
while (sp_active(s))
|
53
|
+
{
|
54
|
+
/* get the new page properties and a data */
|
55
|
+
spupdate0 u;
|
56
|
+
sp_mergeget0(&i, s->e->page, &u);
|
57
|
+
if (spunlikely(u.count == 0))
|
58
|
+
break;
|
59
|
+
|
60
|
+
/* ensure enough space for the page in the file */
|
61
|
+
sp_lock(&x->lock);
|
62
|
+
rc = sp_mapensure(&x->db, u.psize, s->e->dbgrow);
|
63
|
+
if (spunlikely(rc == -1)) {
|
64
|
+
sp_unlock(&x->lock);
|
65
|
+
sp_e(s, SPEIO, "failed to remap db file", x->epoch);
|
66
|
+
goto err;
|
67
|
+
}
|
68
|
+
sp_unlock(&x->lock);
|
69
|
+
|
70
|
+
/* write the page.
|
71
|
+
*
|
72
|
+
* [header] [keys (block sized)] [values]
|
73
|
+
*
|
74
|
+
* Use partly precalculated crc for a version.
|
75
|
+
*/
|
76
|
+
sppageh *h = (sppageh*)(x->db.map + x->db.used);
|
77
|
+
h->id = ++s->psn;
|
78
|
+
h->count = u.count;
|
79
|
+
h->bsize = u.bsize;
|
80
|
+
h->size = u.psize - sizeof(sppageh);
|
81
|
+
h->crc = sp_crc32c(0, &h->id, sizeof(sppageh) - sizeof(h->crc));
|
82
|
+
|
83
|
+
char *ph = x->db.map + x->db.used + sizeof(sppageh);
|
84
|
+
char *pv = ph + u.count * u.bsize;
|
85
|
+
|
86
|
+
uint32_t current = 0;
|
87
|
+
spv *last = NULL;
|
88
|
+
while (sp_active(s) && current < u.count)
|
89
|
+
{
|
90
|
+
spv *v = sp_ival(&i);
|
91
|
+
if (v->flags & SPDEL) {
|
92
|
+
sp_inext(&i);
|
93
|
+
continue;
|
94
|
+
}
|
95
|
+
if (spunlikely(min == NULL)) {
|
96
|
+
min = sp_vdup(s, v);
|
97
|
+
if (spunlikely(min == NULL)) {
|
98
|
+
sp_e(s, SPEOOM, "failed to allocate key");
|
99
|
+
goto err;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
assert(v->size <= u.bsize);
|
103
|
+
spvh *vh = (spvh*)(ph);
|
104
|
+
vh->size = v->size;
|
105
|
+
vh->flags = v->flags;
|
106
|
+
vh->vsize = sp_vvsize(v);
|
107
|
+
vh->voffset = pv - (char*)h;
|
108
|
+
vh->crc = sp_crc32c(v->crc, &vh->size, sizeof(spvh) - sizeof(vh->crc));
|
109
|
+
memcpy(vh->key, v->key, v->size);
|
110
|
+
memcpy(pv, sp_vv(v), vh->vsize);
|
111
|
+
|
112
|
+
ph += u.bsize;
|
113
|
+
pv += vh->vsize;
|
114
|
+
last = v;
|
115
|
+
current++;
|
116
|
+
sp_inext(&i);
|
117
|
+
}
|
118
|
+
|
119
|
+
/* cancellation point check */
|
120
|
+
if (! sp_active(s))
|
121
|
+
goto err;
|
122
|
+
|
123
|
+
/* create in-memory page */
|
124
|
+
sppage *page = sp_pagenew(s, x);
|
125
|
+
if (spunlikely(page == NULL)) {
|
126
|
+
sp_e(s, SPEOOM, "failed to allocate page");
|
127
|
+
goto err;
|
128
|
+
}
|
129
|
+
max = sp_vdup(s, last);
|
130
|
+
if (spunlikely(max == NULL)) {
|
131
|
+
sp_e(s, SPEOOM, "failed to allocate key");
|
132
|
+
goto err;
|
133
|
+
}
|
134
|
+
assert(min != NULL);
|
135
|
+
page->id = s->psn;
|
136
|
+
page->offset = x->db.used;
|
137
|
+
page->size = u.psize;
|
138
|
+
page->min = min;
|
139
|
+
page->max = max;
|
140
|
+
|
141
|
+
/* insert page to the index */
|
142
|
+
sp_lock(&s->locks);
|
143
|
+
sppage *o = NULL;
|
144
|
+
rc = sp_catset(&s->s, page, &o);
|
145
|
+
if (spunlikely(rc == -1)) {
|
146
|
+
sp_unlock(&s->locks);
|
147
|
+
sp_pagefree(s, page);
|
148
|
+
sp_e(s, SPEOOM, "failed to allocate page index page");
|
149
|
+
goto err;
|
150
|
+
}
|
151
|
+
sp_unlock(&s->locks);
|
152
|
+
|
153
|
+
/* attach page to the epoch list */
|
154
|
+
sp_pageattach(page);
|
155
|
+
|
156
|
+
/* advance file buffer */
|
157
|
+
sp_mapuse(&x->db, u.psize);
|
158
|
+
|
159
|
+
min = NULL;
|
160
|
+
max = NULL;
|
161
|
+
}
|
162
|
+
return 0;
|
163
|
+
err:
|
164
|
+
if (min)
|
165
|
+
sp_free(&s->a, min);
|
166
|
+
if (max)
|
167
|
+
sp_free(&s->a, max);
|
168
|
+
return -1;
|
169
|
+
}
|
170
|
+
|
171
|
+
typedef struct {
|
172
|
+
uint32_t pi;
|
173
|
+
sppage *p;
|
174
|
+
spepoch *s; /* p->epoch */
|
175
|
+
uint32_t count;
|
176
|
+
uint32_t bsize;
|
177
|
+
} spupdate;
|
178
|
+
|
179
|
+
typedef struct {
|
180
|
+
/* a is an original page version
|
181
|
+
b is in-memory version */
|
182
|
+
int a_bsize, b_bsize;
|
183
|
+
int a_count, b_count;
|
184
|
+
int A, B;
|
185
|
+
spvh *a;
|
186
|
+
spv *b;
|
187
|
+
spref last;
|
188
|
+
spii i;
|
189
|
+
spepoch *x;
|
190
|
+
} spmerge;
|
191
|
+
|
192
|
+
typedef struct {
|
193
|
+
splist split;
|
194
|
+
int count;
|
195
|
+
} spsplit;
|
196
|
+
|
197
|
+
static inline int
|
198
|
+
sp_mergeget(sp *s, spii *from, spupdate *u)
|
199
|
+
{
|
200
|
+
spii i = *from;
|
201
|
+
if (spunlikely(! sp_ihas(&i)))
|
202
|
+
return 0;
|
203
|
+
memset(u, 0, sizeof(spupdate));
|
204
|
+
/* match the origin page and a associated
|
205
|
+
* range of keys. */
|
206
|
+
sppage *origin = NULL;
|
207
|
+
uint32_t origin_idx = 0;
|
208
|
+
uint32_t n = 0;
|
209
|
+
while (sp_ihas(&i)) {
|
210
|
+
spv *v = sp_ival(&i);
|
211
|
+
if (splikely(origin)) {
|
212
|
+
if (! sp_catown(&s->s, origin_idx, v))
|
213
|
+
break;
|
214
|
+
} else {
|
215
|
+
origin = sp_catroute(&s->s, v->key, v->size, &origin_idx);
|
216
|
+
assert(((spepoch*)origin->epoch)->type == SPDB);
|
217
|
+
}
|
218
|
+
if (v->size > u->bsize)
|
219
|
+
u->bsize = v->size;
|
220
|
+
sp_inext(&i);
|
221
|
+
n++;
|
222
|
+
}
|
223
|
+
assert(n > 0);
|
224
|
+
u->count = n;
|
225
|
+
u->bsize += sizeof(spvh);
|
226
|
+
u->pi = origin_idx;
|
227
|
+
u->p = origin;
|
228
|
+
u->s = origin->epoch;
|
229
|
+
return 1;
|
230
|
+
}
|
231
|
+
|
232
|
+
static inline void
|
233
|
+
sp_mergeinit(spepoch *x, spmerge *m, spupdate *u, spii *from)
|
234
|
+
{
|
235
|
+
sppageh *h = (sppageh*)(u->s->db.map + u->p->offset);
|
236
|
+
uint32_t bsize = u->bsize;
|
237
|
+
if (h->bsize > bsize)
|
238
|
+
bsize = h->bsize;
|
239
|
+
m->a_bsize = h->bsize;
|
240
|
+
m->b_bsize = bsize;
|
241
|
+
memset(&m->last, 0, sizeof(m->last));
|
242
|
+
m->i = *from;
|
243
|
+
m->A = 0;
|
244
|
+
m->B = 0;
|
245
|
+
m->a_count = h->count;
|
246
|
+
m->b_count = u->count;
|
247
|
+
m->a = (spvh*)((char*)h + sizeof(sppageh));
|
248
|
+
m->b = sp_ival(from);
|
249
|
+
m->x = x;
|
250
|
+
}
|
251
|
+
|
252
|
+
static inline int sp_mergenext(sp *s, spmerge *m)
|
253
|
+
{
|
254
|
+
if (m->A < m->a_count && m->B < m->b_count)
|
255
|
+
{
|
256
|
+
register int cmp =
|
257
|
+
s->e->cmp(m->a->key, m->a->size,
|
258
|
+
m->b->key,
|
259
|
+
m->b->size, s->e->cmparg);
|
260
|
+
switch (cmp) {
|
261
|
+
case 0:
|
262
|
+
/* use updated key B */
|
263
|
+
m->last.type = SPREFM;
|
264
|
+
m->last.v.v = m->b;
|
265
|
+
m->A++;
|
266
|
+
m->a = (spvh*)((char*)m->a + m->a_bsize);
|
267
|
+
m->B++;
|
268
|
+
sp_inext(&m->i);
|
269
|
+
m->b = sp_ival(&m->i);
|
270
|
+
return 1;
|
271
|
+
case -1:
|
272
|
+
/* use A */
|
273
|
+
m->last.type = SPREFD;
|
274
|
+
m->last.v.vh = m->a;
|
275
|
+
m->A++;
|
276
|
+
m->a = (spvh*)((char*)m->a + m->a_bsize);
|
277
|
+
return 1;
|
278
|
+
case 1:
|
279
|
+
/* use B */
|
280
|
+
m->last.type = SPREFM;
|
281
|
+
m->last.v.v = m->b;
|
282
|
+
m->B++;
|
283
|
+
sp_inext(&m->i);
|
284
|
+
m->b = sp_ival(&m->i);
|
285
|
+
return 1;
|
286
|
+
}
|
287
|
+
}
|
288
|
+
if (m->A < m->a_count) {
|
289
|
+
/* use A */
|
290
|
+
m->last.type = SPREFD;
|
291
|
+
m->last.v.vh = m->a;
|
292
|
+
m->A++;
|
293
|
+
m->a = (spvh*)((char*)m->a + m->a_bsize);
|
294
|
+
return 1;
|
295
|
+
}
|
296
|
+
if (m->B < m->b_count) {
|
297
|
+
/* use B */
|
298
|
+
m->last.type = SPREFM;
|
299
|
+
m->last.v.v = m->b;
|
300
|
+
m->B++;
|
301
|
+
sp_inext(&m->i);
|
302
|
+
m->b = sp_ival(&m->i);
|
303
|
+
return 1;
|
304
|
+
}
|
305
|
+
return 0;
|
306
|
+
}
|
307
|
+
|
308
|
+
static inline void
|
309
|
+
sp_splitinit(spsplit *l) {
|
310
|
+
sp_listinit(&l->split);
|
311
|
+
l->count = 0;
|
312
|
+
}
|
313
|
+
|
314
|
+
static inline void
|
315
|
+
sp_splitfree(sp *s, spsplit *l) {
|
316
|
+
splist *i, *n;
|
317
|
+
sp_listforeach_safe(&l->split, i, n) {
|
318
|
+
sppage *p = spcast(i, sppage, link);
|
319
|
+
sp_pagefree(s, p);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
static inline int sp_split(sp *s, spupdate *u, spmerge *m, spsplit *l)
|
324
|
+
{
|
325
|
+
int rc;
|
326
|
+
int bsize = m->b_bsize;
|
327
|
+
uint32_t pagesize = sizeof(sppageh);
|
328
|
+
uint32_t count = 0;
|
329
|
+
/*
|
330
|
+
* merge in-memory keys with the origin page keys,
|
331
|
+
* skip any deletes and calculate result
|
332
|
+
* page size.
|
333
|
+
*/
|
334
|
+
sp_refsetreset(&s->refs);
|
335
|
+
while (count < s->e->page && sp_mergenext(s, m)) {
|
336
|
+
if (sp_refisdel(&m->last))
|
337
|
+
continue;
|
338
|
+
sp_refsetadd(&s->refs, &m->last);
|
339
|
+
pagesize += bsize + sp_refvsize(&m->last);
|
340
|
+
count++;
|
341
|
+
}
|
342
|
+
if (spunlikely(count == 0 && l->count > 0))
|
343
|
+
return 0;
|
344
|
+
|
345
|
+
/*
|
346
|
+
* set the origin page id for a first spitted page
|
347
|
+
*/
|
348
|
+
uint32_t psn = (l->count == 0) ? u->p->id : ++s->psn;
|
349
|
+
|
350
|
+
/* ensure enough space for the page in the file */
|
351
|
+
sp_lock(&m->x->lock);
|
352
|
+
rc = sp_mapensure(&m->x->db, pagesize, s->e->dbgrow);
|
353
|
+
if (spunlikely(rc == -1)) {
|
354
|
+
sp_unlock(&m->x->lock);
|
355
|
+
return sp_e(s, SPEIO, "failed to remap db file",
|
356
|
+
m->x->epoch);
|
357
|
+
}
|
358
|
+
sp_unlock(&m->x->lock);
|
359
|
+
|
360
|
+
/* in case if all origin page keys are deleted.
|
361
|
+
*
|
362
|
+
* write special page header without any data, indicating
|
363
|
+
* that page should be skipped during recovery
|
364
|
+
* and not being added to the index.
|
365
|
+
*/
|
366
|
+
if (spunlikely(count == 0 && l->count == 0)) {
|
367
|
+
sppageh *h = (sppageh*)(m->x->db.map + m->x->db.used);
|
368
|
+
h->id = psn;
|
369
|
+
h->count = 0;
|
370
|
+
h->bsize = 0;
|
371
|
+
h->size = 0;
|
372
|
+
h->crc = sp_crc32c(0, &h->id, sizeof(sppageh) - sizeof(h->crc));
|
373
|
+
sp_mapuse(&m->x->db, pagesize);
|
374
|
+
return 0;
|
375
|
+
}
|
376
|
+
|
377
|
+
spref *r = s->refs.r;
|
378
|
+
spref *min = r;
|
379
|
+
spref *max = r + (count - 1);
|
380
|
+
|
381
|
+
/*
|
382
|
+
* write the page
|
383
|
+
*/
|
384
|
+
sppageh *h = (sppageh*)(m->x->db.map + m->x->db.used);
|
385
|
+
h->id = psn;
|
386
|
+
h->count = count;
|
387
|
+
h->bsize = bsize;
|
388
|
+
h->size = pagesize - sizeof(sppageh);
|
389
|
+
h->crc = sp_crc32c(0, &h->id, sizeof(sppageh) - sizeof(h->crc));
|
390
|
+
|
391
|
+
spvh *ptr = (spvh*)(m->x->db.map + m->x->db.used + sizeof(sppageh));
|
392
|
+
char *ptrv = (char*)ptr + count * bsize;
|
393
|
+
|
394
|
+
uint32_t i = 0;
|
395
|
+
while (i < count)
|
396
|
+
{
|
397
|
+
uint32_t voffset = ptrv - (char*)h;
|
398
|
+
switch (r->type) {
|
399
|
+
case SPREFD:
|
400
|
+
memcpy(ptr, r->v.vh, sizeof(spvh) + r->v.vh->size);
|
401
|
+
memcpy(ptrv, u->s->db.map + u->p->offset + r->v.vh->voffset,
|
402
|
+
r->v.vh->vsize);
|
403
|
+
ptr->voffset = voffset;
|
404
|
+
uint32_t crc;
|
405
|
+
crc = sp_crc32c(0, ptr->key, ptr->size);
|
406
|
+
crc = sp_crc32c(crc, ptrv, r->v.vh->vsize);
|
407
|
+
crc = sp_crc32c(crc, &ptr->size, sizeof(spvh) - sizeof(ptr->crc));
|
408
|
+
ptr->crc = crc;
|
409
|
+
ptrv += r->v.vh->vsize;
|
410
|
+
break;
|
411
|
+
case SPREFM:
|
412
|
+
ptr->size = r->v.v->size;
|
413
|
+
ptr->flags = r->v.v->flags;
|
414
|
+
ptr->voffset = voffset;
|
415
|
+
ptr->vsize = sp_vvsize(r->v.v);
|
416
|
+
ptr->crc = sp_crc32c(r->v.v->crc, &ptr->size, sizeof(spvh) -
|
417
|
+
sizeof(ptr->crc));
|
418
|
+
memcpy(ptr->key, r->v.v->key, r->v.v->size);
|
419
|
+
memcpy(ptrv, sp_vv(r->v.v), ptr->vsize);
|
420
|
+
ptrv += ptr->vsize;
|
421
|
+
break;
|
422
|
+
}
|
423
|
+
assert((uint32_t)(ptrv - (char*)h) <= pagesize);
|
424
|
+
ptr = (spvh*)((char*)ptr + bsize);
|
425
|
+
r++;
|
426
|
+
i++;
|
427
|
+
}
|
428
|
+
|
429
|
+
/* create in-memory page */
|
430
|
+
sppage *p = sp_pagenew(s, m->x);
|
431
|
+
if (spunlikely(p == NULL))
|
432
|
+
return sp_e(s, SPEOOM, "failed to allocate page");
|
433
|
+
p->id = psn;
|
434
|
+
p->offset = m->x->db.used;
|
435
|
+
p->size = pagesize;
|
436
|
+
p->min = sp_vdupref(s, min, m->x->epoch);
|
437
|
+
if (spunlikely(p->min == NULL)) {
|
438
|
+
sp_free(&s->a, p);
|
439
|
+
return sp_e(s, SPEOOM, "failed to allocate key");
|
440
|
+
}
|
441
|
+
p->max = sp_vdupref(s, max, m->x->epoch);
|
442
|
+
if (spunlikely(p->max == NULL)) {
|
443
|
+
sp_free(&s->a, p->min);
|
444
|
+
sp_free(&s->a, p);
|
445
|
+
return sp_e(s, SPEOOM, "failed to allocate key");
|
446
|
+
}
|
447
|
+
|
448
|
+
/* add page to split list */
|
449
|
+
sp_listappend(&l->split, &p->link);
|
450
|
+
l->count++;
|
451
|
+
|
452
|
+
/* advance buffer */
|
453
|
+
sp_mapuse(&m->x->db, pagesize);
|
454
|
+
return 1;
|
455
|
+
}
|
456
|
+
|
457
|
+
static inline int sp_splitcommit(sp *s, spupdate *u, spmerge *m, spsplit *l)
|
458
|
+
{
|
459
|
+
sp_lock(&s->locks);
|
460
|
+
/* remove origin page, if there were no page
|
461
|
+
* updates after split */
|
462
|
+
if (spunlikely(l->count == 0)) {
|
463
|
+
sp_pagefree(s, u->p);
|
464
|
+
u->s->ngc++;
|
465
|
+
u->p = NULL;
|
466
|
+
sp_catdel(&s->s, u->pi);
|
467
|
+
sp_unlock(&s->locks);
|
468
|
+
return 0;
|
469
|
+
}
|
470
|
+
splist *i, *n;
|
471
|
+
sp_listforeach_safe(&l->split, i, n)
|
472
|
+
{
|
473
|
+
sppage *p = spcast(i, sppage, link);
|
474
|
+
/* update origin page first */
|
475
|
+
if (spunlikely(p->id == u->p->id)) {
|
476
|
+
sp_listunlink(&p->link);
|
477
|
+
/* relink origin page to new epoch */
|
478
|
+
sppage *origin = u->p;
|
479
|
+
assert(origin->epoch != m->x);
|
480
|
+
sp_listunlink(&origin->link);
|
481
|
+
u->s->ngc++; /* origin db epoch */
|
482
|
+
m->x->n++; /* current db epoch */
|
483
|
+
sp_listappend(&m->x->pages, &origin->link);
|
484
|
+
/* update origin page */
|
485
|
+
origin->offset = p->offset;
|
486
|
+
assert(p->epoch == m->x);
|
487
|
+
origin->epoch = m->x;
|
488
|
+
origin->size = p->size;
|
489
|
+
sp_free(&s->a, origin->min);
|
490
|
+
sp_free(&s->a, origin->max);
|
491
|
+
origin->min = p->min;
|
492
|
+
origin->max = p->max;
|
493
|
+
sp_free(&s->a, p);
|
494
|
+
continue;
|
495
|
+
}
|
496
|
+
/* insert split page */
|
497
|
+
sppage *o = NULL;
|
498
|
+
int rc = sp_catset(&s->s, p, &o);
|
499
|
+
if (spunlikely(rc == -1)) {
|
500
|
+
sp_unlock(&s->locks);
|
501
|
+
return sp_e(s, SPEOOM, "failed to allocate page index page");
|
502
|
+
}
|
503
|
+
assert(o == NULL);
|
504
|
+
sp_pageattach(p);
|
505
|
+
m->x->n++;
|
506
|
+
}
|
507
|
+
sp_unlock(&s->locks);
|
508
|
+
return 0;
|
509
|
+
}
|
510
|
+
|
511
|
+
static inline int sp_mergeN(sp *s, spepoch *x, spi *index)
|
512
|
+
{
|
513
|
+
int rc;
|
514
|
+
spii i;
|
515
|
+
sp_iopen(&i, index);
|
516
|
+
spupdate u;
|
517
|
+
while (sp_mergeget(s, &i, &u))
|
518
|
+
{
|
519
|
+
spmerge m;
|
520
|
+
sp_mergeinit(x, &m, &u, &i);
|
521
|
+
spsplit l;
|
522
|
+
sp_splitinit(&l);
|
523
|
+
while (sp_active(s)) {
|
524
|
+
rc = sp_split(s, &u, &m, &l);
|
525
|
+
if (spunlikely(rc == 0))
|
526
|
+
break;
|
527
|
+
else
|
528
|
+
if (spunlikely(rc == -1)) {
|
529
|
+
sp_splitfree(s, &l);
|
530
|
+
return -1;
|
531
|
+
}
|
532
|
+
}
|
533
|
+
if (spunlikely(! sp_active(s)))
|
534
|
+
return 0;
|
535
|
+
rc = sp_splitcommit(s, &u, &m, &l);
|
536
|
+
if (spunlikely(rc == -1)) {
|
537
|
+
sp_splitfree(s, &l);
|
538
|
+
return -1;
|
539
|
+
}
|
540
|
+
i = m.i;
|
541
|
+
}
|
542
|
+
return 0;
|
543
|
+
}
|
544
|
+
|
545
|
+
int sp_merge(sp *s)
|
546
|
+
{
|
547
|
+
sp_lock(&s->lockr);
|
548
|
+
sp_lock(&s->locki);
|
549
|
+
|
550
|
+
spepoch *x = sp_replive(&s->rep);
|
551
|
+
/* rotate current live epoch */
|
552
|
+
sp_repset(&s->rep, x, SPXFER);
|
553
|
+
int rc = sp_rotate(s);
|
554
|
+
if (spunlikely(rc == -1)) {
|
555
|
+
sp_lock(&s->lockr);
|
556
|
+
sp_lock(&s->locki);
|
557
|
+
return -1;
|
558
|
+
}
|
559
|
+
/* swap index */
|
560
|
+
spi *index = sp_iswap(s);
|
561
|
+
|
562
|
+
sp_unlock(&s->lockr);
|
563
|
+
sp_unlock(&s->locki);
|
564
|
+
|
565
|
+
/* complete old live epoch log */
|
566
|
+
rc = sp_logeof(&x->log);
|
567
|
+
if (spunlikely(rc == -1))
|
568
|
+
return sp_e(s, SPEIO, "failed to write eof marker", x->epoch);
|
569
|
+
rc = sp_logcomplete(&x->log);
|
570
|
+
if (spunlikely(rc == -1))
|
571
|
+
return sp_e(s, SPEIO, "failed to complete log file", x->epoch);
|
572
|
+
|
573
|
+
/* create db file */
|
574
|
+
rc = sp_mapepochnew(&x->db, s->e->dbnewsize, s->e->dir, x->epoch, "db");
|
575
|
+
if (spunlikely(rc == -1))
|
576
|
+
return sp_e(s, SPEIO, "failed to create db file", x->epoch);
|
577
|
+
|
578
|
+
/* merge index */
|
579
|
+
if (splikely(s->s.count > 0))
|
580
|
+
rc = sp_mergeN(s, x, index);
|
581
|
+
else
|
582
|
+
rc = sp_merge0(s, x, index);
|
583
|
+
|
584
|
+
/* check cancellation point */
|
585
|
+
if (! sp_active(s)) {
|
586
|
+
sp_mapunlink(&x->db);
|
587
|
+
sp_mapclose(&x->db);
|
588
|
+
return rc;
|
589
|
+
}
|
590
|
+
if (spunlikely(rc == -1))
|
591
|
+
return -1;
|
592
|
+
|
593
|
+
/* gc */
|
594
|
+
if (s->e->gc) {
|
595
|
+
rc = sp_gc(s, x);
|
596
|
+
if (spunlikely(rc == -1))
|
597
|
+
return -1;
|
598
|
+
}
|
599
|
+
|
600
|
+
/* sync/truncate db file and remap read-only only if
|
601
|
+
* database file is not empty. */
|
602
|
+
if (splikely(x->db.used > 0)) {
|
603
|
+
sp_lock(&x->lock);
|
604
|
+
rc = sp_mapcomplete(&x->db);
|
605
|
+
if (spunlikely(rc == -1)) {
|
606
|
+
sp_unlock(&x->lock);
|
607
|
+
return sp_e(s, SPEIO, "failed to complete db file", x->epoch);
|
608
|
+
}
|
609
|
+
sp_unlock(&x->lock);
|
610
|
+
/* set epoch as db */
|
611
|
+
sp_lock(&s->lockr);
|
612
|
+
sp_repset(&s->rep, x, SPDB);
|
613
|
+
sp_unlock(&s->lockr);
|
614
|
+
/* remove log file */
|
615
|
+
rc = sp_logunlink(&x->log);
|
616
|
+
if (spunlikely(rc == -1))
|
617
|
+
return sp_e(s, SPEIO, "failed to unlink log file", x->epoch);
|
618
|
+
rc = sp_logclose(&x->log);
|
619
|
+
if (spunlikely(rc == -1))
|
620
|
+
return sp_e(s, SPEIO, "failed to close log file", x->epoch);
|
621
|
+
} else {
|
622
|
+
/* there are possible situation when all keys has
|
623
|
+
* been deleted. */
|
624
|
+
rc = sp_mapunlink(&x->db);
|
625
|
+
if (spunlikely(rc == -1))
|
626
|
+
return sp_e(s, SPEIO, "failed to unlink db file", x->epoch);
|
627
|
+
rc = sp_mapclose(&x->db);
|
628
|
+
if (spunlikely(rc == -1))
|
629
|
+
return sp_e(s, SPEIO, "failed to close db file", x->epoch);
|
630
|
+
}
|
631
|
+
|
632
|
+
/* remove all xfer epochs that took part in the merge
|
633
|
+
* including current, if it's database file
|
634
|
+
* is empty. */
|
635
|
+
while (sp_active(s)) {
|
636
|
+
sp_lock(&s->lockr);
|
637
|
+
spepoch *e = sp_repxfer(&s->rep);
|
638
|
+
sp_unlock(&s->lockr);
|
639
|
+
if (e == NULL)
|
640
|
+
break;
|
641
|
+
rc = sp_logunlink(&e->log);
|
642
|
+
if (spunlikely(rc == -1))
|
643
|
+
return sp_e(s, SPEIO, "failed to unlink log file", e->epoch);
|
644
|
+
rc = sp_logclose(&e->log);
|
645
|
+
if (spunlikely(rc == -1))
|
646
|
+
return sp_e(s, SPEIO, "failed to close log file", e->epoch);
|
647
|
+
sp_lock(&s->lockr);
|
648
|
+
sp_repdetach(&s->rep, e);
|
649
|
+
sp_free(&s->a, e);
|
650
|
+
sp_unlock(&s->lockr);
|
651
|
+
}
|
652
|
+
|
653
|
+
/* truncate the index (skip index on a read) */
|
654
|
+
sp_iskipset(s, 1);
|
655
|
+
rc = sp_itruncate(index);
|
656
|
+
if (spunlikely(rc == -1)) {
|
657
|
+
sp_iskipset(s, 0);
|
658
|
+
return sp_e(s, SPE, "failed create index");
|
659
|
+
}
|
660
|
+
sp_iskipset(s, 0);
|
661
|
+
return 0;
|
662
|
+
}
|