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,47 @@
|
|
1
|
+
#ifndef SP_CURSOR_H_
|
2
|
+
#define SP_CURSOR_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
typedef struct spc spc;
|
13
|
+
|
14
|
+
enum spcsrc {
|
15
|
+
SPCNONE,
|
16
|
+
SPCI0,
|
17
|
+
SPCI1,
|
18
|
+
SPCP
|
19
|
+
};
|
20
|
+
|
21
|
+
#define SPCVDUP 1
|
22
|
+
#define SPCPDUP 2
|
23
|
+
|
24
|
+
typedef enum spcsrc spcsrc;
|
25
|
+
|
26
|
+
struct spc {
|
27
|
+
spmagic m;
|
28
|
+
sporder o;
|
29
|
+
sp *s;
|
30
|
+
spii i0, i1;
|
31
|
+
int dup; /* last iteration duplicate flags */
|
32
|
+
sppageh *ph;
|
33
|
+
sppage *p;
|
34
|
+
int pi; /* page space index */
|
35
|
+
spvh *pv;
|
36
|
+
int pvi; /* version page index */
|
37
|
+
spcsrc vsrc; /* last iteration source */
|
38
|
+
spref r; /* last iteration result */
|
39
|
+
};
|
40
|
+
|
41
|
+
void sp_cursoropen(spc*, sp*, sporder, char*, int);
|
42
|
+
void sp_cursorclose(spc*);
|
43
|
+
|
44
|
+
int sp_iterate(spc*);
|
45
|
+
int sp_match(sp*, void*, size_t, void**, size_t*);
|
46
|
+
|
47
|
+
#endif
|
@@ -0,0 +1,49 @@
|
|
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
|
+
void sp_ve(spe *e, int type, va_list args)
|
13
|
+
{
|
14
|
+
sp_lock(&e->lock);
|
15
|
+
if (e->type != SPENONE) {
|
16
|
+
sp_unlock(&e->lock);
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
e->type = type;
|
20
|
+
switch (type) {
|
21
|
+
case SPE: {
|
22
|
+
char *fmt = va_arg(args, char*);
|
23
|
+
int len = snprintf(e->e, sizeof(e->e), "error: ");
|
24
|
+
vsnprintf(e->e + len, sizeof(e->e) - len, fmt, args);
|
25
|
+
break;
|
26
|
+
}
|
27
|
+
case SPEOOM: {
|
28
|
+
char *msg = va_arg(args, char*);
|
29
|
+
snprintf(e->e, sizeof(e->e), "out-of-memory error: %s", msg);
|
30
|
+
break;
|
31
|
+
}
|
32
|
+
case SPESYS: {
|
33
|
+
e->errno_ = errno;
|
34
|
+
char *msg = va_arg(args, char*);
|
35
|
+
snprintf(e->e, sizeof(e->e), "system error: %s (errno: %d, %s)",
|
36
|
+
msg, e->errno_, strerror(e->errno_));
|
37
|
+
break;
|
38
|
+
}
|
39
|
+
case SPEIO: {
|
40
|
+
e->errno_ = errno;
|
41
|
+
char *msg = va_arg(args, char*);
|
42
|
+
uint32_t epoch = va_arg(args, uint32_t);
|
43
|
+
snprintf(e->e, sizeof(e->e), "io error: [epoch %"PRIu32"] %s (errno: %d, %s)",
|
44
|
+
epoch, msg, e->errno_, strerror(e->errno_));
|
45
|
+
break;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
sp_unlock(&e->lock);
|
49
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#ifndef SP_E_H_
|
2
|
+
#define SP_E_H_
|
3
|
+
|
4
|
+
/*
|
5
|
+
* sophia database
|
6
|
+
* sphia.org
|
7
|
+
*
|
8
|
+
* Copyright (c) Dmitry Simonenko
|
9
|
+
* BSD License
|
10
|
+
*/
|
11
|
+
|
12
|
+
typedef struct spe spe;
|
13
|
+
|
14
|
+
enum {
|
15
|
+
SPENONE,
|
16
|
+
SPE, /* general error (with format) */
|
17
|
+
SPEOOM, /* out of memory */
|
18
|
+
SPESYS, /* system + errno */
|
19
|
+
SPEIO /* system-io + errno */
|
20
|
+
};
|
21
|
+
|
22
|
+
struct spe {
|
23
|
+
spspinlock lock;
|
24
|
+
int type;
|
25
|
+
int errno_;
|
26
|
+
char e[256];
|
27
|
+
};
|
28
|
+
|
29
|
+
static inline void sp_einit(spe *e) {
|
30
|
+
e->lock = 0;
|
31
|
+
e->type = SPENONE;
|
32
|
+
e->e[0] = 0;
|
33
|
+
sp_lockinit(&e->lock);
|
34
|
+
}
|
35
|
+
|
36
|
+
static inline void sp_efree(spe *e) {
|
37
|
+
sp_lockfree(&e->lock);
|
38
|
+
}
|
39
|
+
|
40
|
+
static inline int sp_eis(spe *e) {
|
41
|
+
sp_lock(&e->lock);
|
42
|
+
register int is = e->type != SPENONE;
|
43
|
+
sp_unlock(&e->lock);
|
44
|
+
return is;
|
45
|
+
}
|
46
|
+
|
47
|
+
void sp_ve(spe *e, int type, va_list args);
|
48
|
+
|
49
|
+
#endif
|
@@ -0,0 +1,355 @@
|
|
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 <sys/mman.h>
|
12
|
+
#include <fcntl.h>
|
13
|
+
#include <unistd.h>
|
14
|
+
#include <errno.h>
|
15
|
+
|
16
|
+
int sp_fileexists(char *path) {
|
17
|
+
struct stat st;
|
18
|
+
int rc = lstat(path, &st);
|
19
|
+
return rc == 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
int sp_filerm(char *path) {
|
23
|
+
return unlink(path);
|
24
|
+
}
|
25
|
+
|
26
|
+
static inline ssize_t
|
27
|
+
sp_mapsizeof(char *path) {
|
28
|
+
struct stat st;
|
29
|
+
int rc = lstat(path, &st);
|
30
|
+
if (spunlikely(rc == -1))
|
31
|
+
return -1;
|
32
|
+
return st.st_size;
|
33
|
+
}
|
34
|
+
|
35
|
+
static inline int
|
36
|
+
sp_mapresize(spfile *f, size_t size) {
|
37
|
+
int rc = ftruncate(f->fd, size);
|
38
|
+
if (spunlikely(rc == -1))
|
39
|
+
return -1;
|
40
|
+
f->size = size;
|
41
|
+
return 0;
|
42
|
+
}
|
43
|
+
|
44
|
+
static inline int
|
45
|
+
sp_map(spfile *f, int flags) {
|
46
|
+
void *p = mmap(NULL, f->size, flags, MAP_SHARED, f->fd, 0);
|
47
|
+
if (p == MAP_FAILED)
|
48
|
+
return -1;
|
49
|
+
f->map = p;
|
50
|
+
return 0;
|
51
|
+
}
|
52
|
+
|
53
|
+
static inline int
|
54
|
+
sp_unmap(spfile *f) {
|
55
|
+
int rc;
|
56
|
+
if (f->map) {
|
57
|
+
rc = munmap(f->map, f->size);
|
58
|
+
f->map = NULL;
|
59
|
+
return rc;
|
60
|
+
}
|
61
|
+
return 0;
|
62
|
+
}
|
63
|
+
|
64
|
+
static inline int
|
65
|
+
sp_mapopenof(spfile *f, char *path, int flags, uint64_t size)
|
66
|
+
{
|
67
|
+
f->fd = open(path, flags, 0600);
|
68
|
+
if (spunlikely(f->fd == -1))
|
69
|
+
return -1;
|
70
|
+
f->file = sp_strdup(f->a, path);
|
71
|
+
if (spunlikely(f->file == NULL)) {
|
72
|
+
close(f->fd);
|
73
|
+
f->fd = -1;
|
74
|
+
return -1;
|
75
|
+
}
|
76
|
+
f->used = 0;
|
77
|
+
f->creat = (flags & O_CREAT ? 1 : 0);
|
78
|
+
int rc;
|
79
|
+
if (! f->creat) {
|
80
|
+
ssize_t sz = sp_mapsizeof(path);
|
81
|
+
if (spunlikely(sz == -1))
|
82
|
+
goto err;
|
83
|
+
f->size = sz;
|
84
|
+
rc = sp_map(f, PROT_READ);
|
85
|
+
if (spunlikely(rc == -1))
|
86
|
+
goto err;
|
87
|
+
return 0;
|
88
|
+
}
|
89
|
+
f->size = 0;
|
90
|
+
rc = sp_mapresize(f, size);
|
91
|
+
if (spunlikely(rc == -1))
|
92
|
+
goto err;
|
93
|
+
rc = sp_map(f, PROT_READ|PROT_WRITE);
|
94
|
+
if (spunlikely(rc == -1))
|
95
|
+
goto err;
|
96
|
+
return 0;
|
97
|
+
err:
|
98
|
+
close(f->fd);
|
99
|
+
f->fd = -1;
|
100
|
+
sp_free(f->a, f->file);
|
101
|
+
f->file = NULL;
|
102
|
+
return -1;
|
103
|
+
}
|
104
|
+
|
105
|
+
int sp_mapopen(spfile *f, char *path) {
|
106
|
+
return sp_mapopenof(f, path, O_RDONLY, 0);
|
107
|
+
}
|
108
|
+
|
109
|
+
int sp_mapnew(spfile *f, char *path, uint64_t size) {
|
110
|
+
return sp_mapopenof(f, path, O_RDWR|O_CREAT, size);
|
111
|
+
}
|
112
|
+
|
113
|
+
static inline int
|
114
|
+
sp_mapsync(spfile *f) {
|
115
|
+
return msync(f->map, f->size, MS_SYNC);
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
int sp_mapunlink(spfile *f) {
|
120
|
+
return sp_filerm(f->file);
|
121
|
+
}
|
122
|
+
|
123
|
+
static inline int
|
124
|
+
sp_mapcut(spfile *f)
|
125
|
+
{
|
126
|
+
if (f->creat == 0)
|
127
|
+
return 0;
|
128
|
+
int rc = sp_mapsync(f);
|
129
|
+
if (spunlikely(rc == -1))
|
130
|
+
return -1;
|
131
|
+
rc = sp_unmap(f);
|
132
|
+
if (spunlikely(rc == -1))
|
133
|
+
return -1;
|
134
|
+
rc = sp_mapresize(f, f->used);
|
135
|
+
if (spunlikely(rc == -1))
|
136
|
+
return -1;
|
137
|
+
return 0;
|
138
|
+
}
|
139
|
+
|
140
|
+
static inline int
|
141
|
+
sp_fileclose(spfile *f)
|
142
|
+
{
|
143
|
+
/* leave file incomplete */
|
144
|
+
if (splikely(f->file)) {
|
145
|
+
sp_free(f->a, f->file);
|
146
|
+
f->file = NULL;
|
147
|
+
}
|
148
|
+
int rc;
|
149
|
+
if (spunlikely(f->fd != -1)) {
|
150
|
+
rc = close(f->fd);
|
151
|
+
if (spunlikely(rc == -1))
|
152
|
+
return -1;
|
153
|
+
f->fd = -1;
|
154
|
+
}
|
155
|
+
return 0;
|
156
|
+
}
|
157
|
+
|
158
|
+
static inline int
|
159
|
+
sp_filecomplete(spfile *f)
|
160
|
+
{
|
161
|
+
if (f->creat == 0)
|
162
|
+
return 0;
|
163
|
+
/* remove .incomplete part */
|
164
|
+
f->creat = 0;
|
165
|
+
char path[1024];
|
166
|
+
snprintf(path, sizeof(path), "%s", f->file);
|
167
|
+
char *ext = strrchr(path, '.');
|
168
|
+
assert(ext != NULL);
|
169
|
+
*ext = 0;
|
170
|
+
int rc = rename(f->file, path);
|
171
|
+
if (spunlikely(rc == -1))
|
172
|
+
return -1;
|
173
|
+
char *p = sp_strdup(f->a, path);
|
174
|
+
if (spunlikely(p == NULL))
|
175
|
+
return -1;
|
176
|
+
sp_free(f->a, f->file);
|
177
|
+
f->file = p;
|
178
|
+
return 0;
|
179
|
+
}
|
180
|
+
|
181
|
+
int sp_mapunmap(spfile *f) {
|
182
|
+
return sp_unmap(f);
|
183
|
+
}
|
184
|
+
|
185
|
+
int sp_mapclose(spfile *f)
|
186
|
+
{
|
187
|
+
int rc = sp_mapcut(f);
|
188
|
+
if (spunlikely(rc == -1))
|
189
|
+
return -1;
|
190
|
+
if (f->map) {
|
191
|
+
rc = sp_unmap(f);
|
192
|
+
if (spunlikely(rc == -1))
|
193
|
+
return -1;
|
194
|
+
}
|
195
|
+
return sp_fileclose(f);
|
196
|
+
}
|
197
|
+
|
198
|
+
int sp_mapcomplete(spfile *f)
|
199
|
+
{
|
200
|
+
if (f->creat == 0)
|
201
|
+
return 0;
|
202
|
+
/* sync and truncate file by used size */
|
203
|
+
int rc = sp_mapcut(f);
|
204
|
+
if (spunlikely(rc == -1))
|
205
|
+
return -1;
|
206
|
+
/* remove .incomplete part */
|
207
|
+
rc = sp_filecomplete(f);
|
208
|
+
if (spunlikely(rc == -1))
|
209
|
+
return -1;
|
210
|
+
return sp_map(f, PROT_READ);
|
211
|
+
}
|
212
|
+
|
213
|
+
int sp_mapensure(spfile *f, uint64_t size, float grow)
|
214
|
+
{
|
215
|
+
if (splikely((f->used + size) < f->size))
|
216
|
+
return 0;
|
217
|
+
int rc = sp_unmap(f);
|
218
|
+
if (spunlikely(rc == -1))
|
219
|
+
return -1;
|
220
|
+
long double nsz = f->size * grow;
|
221
|
+
if (spunlikely(nsz < size))
|
222
|
+
nsz = size;
|
223
|
+
rc = sp_mapresize(f, nsz);
|
224
|
+
if (spunlikely(rc == -1))
|
225
|
+
return -1;
|
226
|
+
return sp_map(f, PROT_READ|PROT_WRITE);
|
227
|
+
}
|
228
|
+
|
229
|
+
static inline int
|
230
|
+
sp_logopenof(spfile *f, char *path, int flags)
|
231
|
+
{
|
232
|
+
f->creat = 1;
|
233
|
+
f->fd = open(path, flags, 0600);
|
234
|
+
if (spunlikely(f->fd == -1))
|
235
|
+
return -1;
|
236
|
+
f->file = sp_strdup(f->a, path);
|
237
|
+
if (spunlikely(f->file == NULL)) {
|
238
|
+
close(f->fd);
|
239
|
+
f->fd = -1;
|
240
|
+
return -1;
|
241
|
+
}
|
242
|
+
f->size = 0;
|
243
|
+
f->used = 0;
|
244
|
+
return 0;
|
245
|
+
}
|
246
|
+
|
247
|
+
int sp_lognew(spfile *f, char *dir, uint32_t epoch)
|
248
|
+
{
|
249
|
+
char path[1024];
|
250
|
+
snprintf(path, sizeof(path), "%s/%"PRIu32".log.incomplete",
|
251
|
+
dir, epoch);
|
252
|
+
int rc = sp_logopenof(f, path, O_WRONLY|O_APPEND|O_CREAT);
|
253
|
+
if (spunlikely(rc == -1))
|
254
|
+
return -1;
|
255
|
+
// posix_fadvise(seq)
|
256
|
+
return 0;
|
257
|
+
}
|
258
|
+
|
259
|
+
int sp_logcontinue(spfile *f, char *dir, uint32_t epoch) {
|
260
|
+
char path[1024];
|
261
|
+
snprintf(path, sizeof(path), "%s/%"PRIu32".log.incomplete",
|
262
|
+
dir, epoch);
|
263
|
+
int rc = sp_logopenof(f, path, O_WRONLY|O_APPEND);
|
264
|
+
if (spunlikely(rc == -1))
|
265
|
+
return -1;
|
266
|
+
return 0;
|
267
|
+
}
|
268
|
+
|
269
|
+
int sp_logclose(spfile *f) {
|
270
|
+
return sp_fileclose(f);
|
271
|
+
}
|
272
|
+
|
273
|
+
static inline int
|
274
|
+
sp_logsync(spfile *f) {
|
275
|
+
return (f->creat ? fsync(f->fd) : 0);
|
276
|
+
}
|
277
|
+
|
278
|
+
int sp_logcomplete(spfile *f)
|
279
|
+
{
|
280
|
+
int rc = sp_logsync(f);
|
281
|
+
if (spunlikely(rc == -1))
|
282
|
+
return -1;
|
283
|
+
return sp_filecomplete(f);
|
284
|
+
}
|
285
|
+
|
286
|
+
int sp_logcompleteforce(spfile *f) {
|
287
|
+
int rc = sp_logsync(f);
|
288
|
+
if (spunlikely(rc == -1))
|
289
|
+
return -1;
|
290
|
+
int oldcreat = f->creat;
|
291
|
+
f->creat = 1;
|
292
|
+
rc = sp_filecomplete(f);
|
293
|
+
f->creat = oldcreat;
|
294
|
+
return rc;
|
295
|
+
}
|
296
|
+
|
297
|
+
int sp_logunlink(spfile *f) {
|
298
|
+
return sp_filerm(f->file);
|
299
|
+
}
|
300
|
+
|
301
|
+
int sp_logflush(spfile *f)
|
302
|
+
{
|
303
|
+
register struct iovec *v = f->iov;
|
304
|
+
register uint64_t size = 0;
|
305
|
+
register int n = f->iovc;
|
306
|
+
do {
|
307
|
+
int r;
|
308
|
+
do {
|
309
|
+
r = writev(f->fd, v, n);
|
310
|
+
} while (r == -1 && errno == EINTR);
|
311
|
+
if (r < 0) {
|
312
|
+
f->iovc = 0;
|
313
|
+
return -1;
|
314
|
+
}
|
315
|
+
size += r;
|
316
|
+
while (n > 0) {
|
317
|
+
if (v->iov_len > (size_t)r) {
|
318
|
+
v->iov_base = (char*)v->iov_base + r;
|
319
|
+
v->iov_len -= r;
|
320
|
+
break;
|
321
|
+
} else {
|
322
|
+
r -= v->iov_len;
|
323
|
+
v++;
|
324
|
+
n--;
|
325
|
+
}
|
326
|
+
}
|
327
|
+
} while (n > 0);
|
328
|
+
f->used += size;
|
329
|
+
f->iovc = 0;
|
330
|
+
return 0;
|
331
|
+
}
|
332
|
+
|
333
|
+
int sp_logrlb(spfile *f)
|
334
|
+
{
|
335
|
+
assert(f->iovc == 0);
|
336
|
+
int rc = ftruncate(f->fd, f->svp);
|
337
|
+
if (spunlikely(rc == -1))
|
338
|
+
return -1;
|
339
|
+
f->used = f->svp;
|
340
|
+
f->svp = 0;
|
341
|
+
return lseek(f->fd, f->used, SEEK_SET);
|
342
|
+
}
|
343
|
+
|
344
|
+
int sp_logeof(spfile *f)
|
345
|
+
{
|
346
|
+
sp_filesvp(f);
|
347
|
+
speofh eof = { SPEOF };
|
348
|
+
sp_logadd(f, (char*)&eof, sizeof(eof));
|
349
|
+
int rc = sp_logflush(f);
|
350
|
+
if (spunlikely(rc == -1)) {
|
351
|
+
sp_logrlb(f);
|
352
|
+
return -1;
|
353
|
+
}
|
354
|
+
return 0;
|
355
|
+
}
|