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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +22 -0
  8. data/ext/extconf.rb +13 -0
  9. data/ext/sophia.c +220 -0
  10. data/lib/sophia-ruby.rb +1 -0
  11. data/lib/sophia/version.rb +3 -0
  12. data/sophia-ruby.gemspec +47 -0
  13. data/test/test_sophia.rb +33 -0
  14. data/vendor/sophia/.gitignore +18 -0
  15. data/vendor/sophia/COPYRIGHT +29 -0
  16. data/vendor/sophia/README +5 -0
  17. data/vendor/sophia/db/a.h +58 -0
  18. data/vendor/sophia/db/cat.c +195 -0
  19. data/vendor/sophia/db/cat.h +32 -0
  20. data/vendor/sophia/db/core.h +129 -0
  21. data/vendor/sophia/db/crc.c +343 -0
  22. data/vendor/sophia/db/crc.h +14 -0
  23. data/vendor/sophia/db/cursor.c +551 -0
  24. data/vendor/sophia/db/cursor.h +47 -0
  25. data/vendor/sophia/db/e.c +49 -0
  26. data/vendor/sophia/db/e.h +49 -0
  27. data/vendor/sophia/db/file.c +355 -0
  28. data/vendor/sophia/db/file.h +106 -0
  29. data/vendor/sophia/db/gc.c +71 -0
  30. data/vendor/sophia/db/gc.h +14 -0
  31. data/vendor/sophia/db/i.c +368 -0
  32. data/vendor/sophia/db/i.h +155 -0
  33. data/vendor/sophia/db/list.h +91 -0
  34. data/vendor/sophia/db/lock.h +77 -0
  35. data/vendor/sophia/db/macro.h +20 -0
  36. data/vendor/sophia/db/makefile +44 -0
  37. data/vendor/sophia/db/merge.c +662 -0
  38. data/vendor/sophia/db/merge.h +14 -0
  39. data/vendor/sophia/db/meta.h +87 -0
  40. data/vendor/sophia/db/recover.c +433 -0
  41. data/vendor/sophia/db/recover.h +14 -0
  42. data/vendor/sophia/db/ref.h +111 -0
  43. data/vendor/sophia/db/rep.c +128 -0
  44. data/vendor/sophia/db/rep.h +120 -0
  45. data/vendor/sophia/db/sophia.h +84 -0
  46. data/vendor/sophia/db/sp.c +626 -0
  47. data/vendor/sophia/db/sp.h +50 -0
  48. data/vendor/sophia/db/task.h +70 -0
  49. data/vendor/sophia/db/track.h +99 -0
  50. data/vendor/sophia/db/util.c +105 -0
  51. data/vendor/sophia/db/util.h +25 -0
  52. data/vendor/sophia/makefile +7 -0
  53. data/vendor/sophia/sophia.gyp +30 -0
  54. data/vendor/sophia/test/common.c +870 -0
  55. data/vendor/sophia/test/crash.c +492 -0
  56. data/vendor/sophia/test/i.c +403 -0
  57. data/vendor/sophia/test/limit.c +65 -0
  58. data/vendor/sophia/test/makefile +30 -0
  59. data/vendor/sophia/test/merge.c +890 -0
  60. data/vendor/sophia/test/recover.c +1550 -0
  61. data/vendor/sophia/test/test.h +66 -0
  62. metadata +134 -0
@@ -0,0 +1,106 @@
1
+ #ifndef SP_FILE_H_
2
+ #define SP_FILE_H_
3
+
4
+ /*
5
+ * sophia database
6
+ * sphia.org
7
+ *
8
+ * Copyright (c) Dmitry Simonenko
9
+ * BSD License
10
+ */
11
+
12
+ typedef struct spfile spfile;
13
+
14
+ struct spfile {
15
+ spa *a;
16
+ int creat;
17
+ uint64_t used;
18
+ uint64_t size;
19
+ uint64_t svp;
20
+ char *file;
21
+ int fd;
22
+ char *map;
23
+ struct iovec iov[8];
24
+ int iovc;
25
+ };
26
+
27
+ int sp_fileexists(char*);
28
+ int sp_filerm(char*);
29
+
30
+ static inline void
31
+ sp_fileinit(spfile *f, spa *a) {
32
+ memset(f, 0, sizeof(*f));
33
+ f->a = a;
34
+ f->fd = -1;
35
+ }
36
+
37
+ static inline void
38
+ sp_filesvp(spfile *f) {
39
+ f->svp = f->used;
40
+ }
41
+
42
+ int sp_mapopen(spfile*, char*);
43
+ int sp_mapnew(spfile*, char*, uint64_t);
44
+ int sp_mapclose(spfile*);
45
+ int sp_mapcomplete(spfile*);
46
+ int sp_mapunmap(spfile*);
47
+ int sp_mapunlink(spfile*);
48
+ int sp_mapensure(spfile*, uint64_t, float);
49
+
50
+ static inline int
51
+ sp_mapepoch(spfile *f, char *dir, uint32_t epoch, char *ext) {
52
+ char path[1024];
53
+ snprintf(path, sizeof(path), "%s/%"PRIu32".%s", dir, epoch, ext);
54
+ return sp_mapopen(f, path);
55
+ }
56
+
57
+ static inline int
58
+ sp_mapepochnew(spfile *f, uint64_t size,
59
+ char *dir, uint32_t epoch, char *ext) {
60
+ char path[1024];
61
+ snprintf(path, sizeof(path), "%s/%"PRIu32".%s.incomplete", dir, epoch, ext);
62
+ return sp_mapnew(f, path, size);
63
+ }
64
+
65
+ static inline void
66
+ sp_mapuse(spfile *f, size_t size) {
67
+ f->used += size;
68
+ assert(f->used <= f->size);
69
+ }
70
+
71
+ static inline void
72
+ sp_maprlb(spfile *f) {
73
+ f->used = f->svp;
74
+ }
75
+
76
+ static inline int
77
+ sp_mapinbound(spfile *f, size_t off) {
78
+ return off <= f->size;
79
+ }
80
+
81
+ int sp_lognew(spfile*, char*, uint32_t);
82
+ int sp_logcontinue(spfile*, char*, uint32_t);
83
+ int sp_logclose(spfile*);
84
+ int sp_logcomplete(spfile*);
85
+ int sp_logcompleteforce(spfile*);
86
+ int sp_logunlink(spfile*);
87
+ int sp_logflush(spfile*);
88
+ int sp_logrlb(spfile*);
89
+ int sp_logeof(spfile*);
90
+
91
+ static inline void
92
+ sp_logadd(spfile *f, const void *buf, int size) {
93
+ assert(f->iovc < 8);
94
+ f->iov[f->iovc].iov_base = (void*)buf;
95
+ f->iov[f->iovc].iov_len = size;
96
+ f->iovc++;
97
+ }
98
+
99
+ static inline int
100
+ sp_epochrm(char *dir, uint32_t epoch, char *ext) {
101
+ char path[1024];
102
+ snprintf(path, sizeof(path), "%s/%"PRIu32".%s", dir, epoch, ext);
103
+ return sp_filerm(path);
104
+ }
105
+
106
+ #endif
@@ -0,0 +1,71 @@
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
+ int sp_gc(sp *s, spepoch *x)
13
+ {
14
+ /*
15
+ * copy all yet active pages from a epoch's
16
+ * databases picked for the garbage
17
+ * collecting.
18
+ */
19
+ for (;;)
20
+ {
21
+ sp_lock(&s->lockr);
22
+ spepoch *g = sp_repgc(&s->rep, s->e->gcfactor);
23
+ sp_unlock(&s->lockr);
24
+ if (g == NULL)
25
+ break;
26
+
27
+ int rc;
28
+ splist *i, *n;
29
+ sp_listforeach_safe(&g->pages, i, n) {
30
+ sppage *p = spcast(i, sppage, link);
31
+
32
+ /* map origin page and copy to db file */
33
+ sppageh *h = (sppageh*)(g->db.map + p->offset);
34
+ sp_lock(&x->lock);
35
+ rc = sp_mapensure(&x->db, sizeof(sppageh) + h->size, s->e->dbgrow);
36
+ if (spunlikely(rc == -1)) {
37
+ sp_unlock(&x->lock);
38
+ return sp_e(s, SPEIO, "failed to remap db file", x->epoch);
39
+ }
40
+ sp_unlock(&x->lock);
41
+ memcpy(x->db.map + x->db.used, h, sizeof(sppageh) + h->size);
42
+
43
+ /* update page location */
44
+ sp_lock(&s->locks);
45
+ sp_listunlink(&p->link);
46
+ sp_listappend(&x->pages, &p->link);
47
+ p->epoch = x;
48
+ p->offset = x->db.used;
49
+ sp_unlock(&s->locks);
50
+
51
+ /* advance file pointer */
52
+ sp_mapuse(&x->db, sizeof(sppageh) + h->size);
53
+ }
54
+
55
+ /*
56
+ * remove old files and unlink the epoch
57
+ * from the repository.
58
+ */
59
+ rc = sp_mapunlink(&g->db);
60
+ if (spunlikely(rc == -1))
61
+ return sp_e(s, SPEIO, "failed to unlink db file", g->epoch);
62
+ rc = sp_mapclose(&g->db);
63
+ if (spunlikely(rc == -1))
64
+ return sp_e(s, SPEIO, "failed to close db file", g->epoch);
65
+ sp_lock(&s->lockr);
66
+ sp_repdetach(&s->rep, g);
67
+ sp_free(&s->a, g);
68
+ sp_unlock(&s->lockr);
69
+ }
70
+ return 0;
71
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef SP_GC_H_
2
+ #define SP_GC_H_
3
+
4
+ /*
5
+ * sophia database
6
+ * sphia.org
7
+ *
8
+ * Copyright (c) Dmitry Simonenko
9
+ * BSD License
10
+ */
11
+
12
+ int sp_gc(sp*, spepoch*);
13
+
14
+ #endif
@@ -0,0 +1,368 @@
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
+ static inline int sp_iensure(spi *i) {
13
+ if (splikely((i->icount + 1) < i->itop))
14
+ return 0;
15
+ i->itop *= 2;
16
+ i->i = sp_realloc(i->a, i->i, i->itop * sizeof(spipage*));
17
+ if (spunlikely(i->i == NULL))
18
+ return -1;
19
+ return 0;
20
+ }
21
+
22
+ static inline int
23
+ sp_ipagesize(spi *i) {
24
+ return sizeof(spipage) + sizeof(spv*) * i->pagesize;
25
+ }
26
+
27
+ static inline spipage*
28
+ sp_ipagealloc(spi *i) {
29
+ spipage *p = sp_malloc(i->a, sp_ipagesize(i));
30
+ if (spunlikely(p == NULL))
31
+ return NULL;
32
+ p->count = 0;
33
+ return p;
34
+ }
35
+
36
+ int sp_iinit(spi *i, spa *a, int pagesize, spcmpf cmp, void *cmparg)
37
+ {
38
+ i->a = a;
39
+ i->cmp = cmp;
40
+ i->cmparg = cmparg;
41
+ i->count = 0;
42
+ i->pagesize = pagesize;
43
+ /* start from 4 pages vector */
44
+ i->itop = 2;
45
+ i->icount = 1;
46
+ i->i = NULL;
47
+ int rc = sp_iensure(i);
48
+ if (spunlikely(rc == -1))
49
+ return -1;
50
+ /* allocate first page */
51
+ i->i[0] = sp_ipagealloc(i);
52
+ if (spunlikely(i->i[0] == NULL)) {
53
+ sp_free(i->a, i->i);
54
+ i->i = NULL;
55
+ return -1;
56
+ }
57
+ return 0;
58
+ }
59
+
60
+ void sp_ifree(spi *i)
61
+ {
62
+ uint32_t p = 0;
63
+ while (p < i->icount) {
64
+ uint32_t k = 0;
65
+ while (k < i->i[p]->count) {
66
+ sp_free(i->a, i->i[p]->i[k]);
67
+ k++;
68
+ }
69
+ sp_free(i->a, i->i[p]);
70
+ p++;
71
+ }
72
+ sp_free(i->a, i->i);
73
+ i->i = NULL;
74
+ }
75
+
76
+ int sp_itruncate(spi *i)
77
+ {
78
+ sp_ifree(i);
79
+ return sp_iinit(i, i->a, i->pagesize, i->cmp, i->cmparg);
80
+ }
81
+
82
+ static inline void*
83
+ sp_iminof(spi *i, spipage *p, char *rkey, int size, uint32_t *idx)
84
+ {
85
+ register int min = 0;
86
+ register int max = p->count - 1;
87
+ while (max >= min) {
88
+ register int mid = min + ((max - min) >> 1);
89
+ register int rc =
90
+ i->cmp(p->i[mid]->key,
91
+ p->i[mid]->size, rkey, size, i->cmparg);
92
+ switch (rc) {
93
+ case -1: min = mid + 1;
94
+ continue;
95
+ case 1: max = mid - 1;
96
+ continue;
97
+ default: *idx = mid;
98
+ return p->i[mid];
99
+ }
100
+ }
101
+ *idx = min;
102
+ return NULL;
103
+ }
104
+
105
+ static inline void*
106
+ sp_imaxof(spi *i, spipage *p, char *rkey, int size, uint32_t *idx)
107
+ {
108
+ register int min = 0;
109
+ register int max = p->count - 1;
110
+ while (max >= min) {
111
+ register int mid = min + ((max - min) >> 1);
112
+ register int rc =
113
+ i->cmp(p->i[mid]->key,
114
+ p->i[mid]->size,
115
+ rkey, size, i->cmparg);
116
+ switch (rc) {
117
+ case -1: min = mid + 1;
118
+ continue;
119
+ case 1: max = mid - 1;
120
+ continue;
121
+ default: *idx = mid;
122
+ return p->i[mid];
123
+ }
124
+ }
125
+ *idx = max;
126
+ return NULL;
127
+ }
128
+
129
+ static inline int
130
+ sp_ipagecmp(spi *i, spipage *p, char *rkey, int size)
131
+ {
132
+ if (spunlikely(p->count == 0))
133
+ return 0;
134
+ register int l =
135
+ i->cmp(p->i[0]->key, p->i[0]->size, rkey, size, i->cmparg);
136
+ register int r =
137
+ i->cmp(p->i[p->count-1]->key, p->i[p->count-1]->size,
138
+ rkey, size, i->cmparg);
139
+ /* inside page range */
140
+ if (l <= 0 && r >= 0)
141
+ return 0;
142
+ /* page min < key */
143
+ if (l == -1)
144
+ return -1;
145
+ /* page max > key */
146
+ assert(r == 1);
147
+ return 1;
148
+ }
149
+
150
+ static inline spipage*
151
+ sp_ipageof(spi *i, char *rkey, int size, uint32_t *idx)
152
+ {
153
+ register int min = 0;
154
+ register int max = i->icount - 1;
155
+ while (max >= min) {
156
+ register int mid = min + ((max - min) >> 1);
157
+ switch (sp_ipagecmp(i, i->i[mid], rkey, size)) {
158
+ case -1: min = mid + 1;
159
+ continue;
160
+ case 1: max = mid - 1;
161
+ continue;
162
+ default:
163
+ *idx = mid;
164
+ return i->i[mid];
165
+ }
166
+ }
167
+ *idx = min;
168
+ return NULL;
169
+ }
170
+
171
+ int sp_isetorget(spi *i, spv *v, spii *old)
172
+ {
173
+ /* 1. do binary search on the vector and find usable
174
+ * page for a key */
175
+ spipage *p = i->i[0];
176
+ uint32_t a = 0;
177
+ if (splikely(i->icount > 1)) {
178
+ p = sp_ipageof(i, v->key, v->size, &a);
179
+ if (spunlikely(p == NULL)) {
180
+ if (a >= i->icount)
181
+ a = i->icount-1;
182
+ p = i->i[a];
183
+ assert(a < i->icount);
184
+ }
185
+ assert(p != NULL);
186
+ }
187
+
188
+ /* 2. if page is full, split it and insert new one:
189
+ * copy second half of the keys from first page to second */
190
+ /* 2.1. insert page to vector, by moving pointers forward */
191
+ if (spunlikely(p->count == i->pagesize)) {
192
+ int rc = sp_iensure(i);
193
+ if (spunlikely(rc == -1))
194
+ return -1;
195
+ /* split page */
196
+ spipage *n = sp_ipagealloc(i);
197
+ if (spunlikely(n == NULL))
198
+ return -1;
199
+ int half = p->count >> 1;
200
+ memcpy(&n->i[0], &p->i[half], sizeof(void*) * (half));
201
+ n->count = half;
202
+ p->count = half;
203
+ /* split page i and insert new page */
204
+ memmove(&i->i[a + 1], &i->i[a], sizeof(spipage*) * (i->icount - a));
205
+ i->i[a] = p;
206
+ i->i[a+1] = n;
207
+ i->icount++;
208
+ /* choose which part to use */
209
+ if (sp_ipagecmp(i, n, v->key, v->size) <= 0) {
210
+ p = n;
211
+ a++;
212
+ }
213
+ }
214
+
215
+ /* 3. if page is not full, do nothing */
216
+ /* 4. do binary search on a page and match room, move
217
+ * pointers forward */
218
+ /* 5. insert key, increment counters */
219
+ assert(p->count < i->pagesize);
220
+
221
+ uint32_t j;
222
+ void *o = sp_iminof(i, p, v->key, v->size, &j);
223
+ if (spunlikely(o)) {
224
+ old->i = i;
225
+ old->p = a;
226
+ old->n = j;
227
+ assert(sp_ival(old) == o);
228
+ return 1;
229
+ }
230
+ if (j >= p->count) {
231
+ p->i[p->count] = v;
232
+ } else {
233
+ memmove(&p->i[j + 1], &p->i[j], sizeof(spv*) * (p->count - j));
234
+ p->i[j] = v;
235
+ }
236
+ i->count++;
237
+ p->count++;
238
+ return 0;
239
+ }
240
+
241
+ int sp_idelraw(spi *i, char *rkey, int size, spv **old)
242
+ {
243
+ spipage *p = i->i[0];
244
+ uint32_t a = 0;
245
+ if (splikely(i->icount > 1))
246
+ p = sp_ipageof(i, rkey, size, &a);
247
+ if (spunlikely(p == NULL))
248
+ return 0;
249
+ uint32_t j;
250
+ *old = sp_iminof(i, p, rkey, size, &j);
251
+ if (spunlikely(*old == NULL))
252
+ return 0;
253
+ if (splikely(j != (uint32_t)(p->count-1)))
254
+ memmove(&p->i[j], &p->i[j + 1], sizeof(spv*) * (p->count - j - 1));
255
+ p->count--;
256
+ i->count--;
257
+ if (splikely(p->count > 0))
258
+ return 1;
259
+ /* do not touch last page */
260
+ if (spunlikely(i->icount == 1))
261
+ return 1;
262
+ /* remove empty page */
263
+ sp_free(i->a, i->i[a]);
264
+ if (splikely(a != (i->icount - 1)))
265
+ memmove(&i->i[a], &i->i[a + 1], sizeof(spipage*) * (i->icount - a - 1));
266
+ i->icount--;
267
+ return 1;
268
+ }
269
+
270
+ spv *sp_igetraw(spi *i, char *rkey, int size)
271
+ {
272
+ spipage *p = i->i[0];
273
+ uint32_t a = 0;
274
+ if (splikely(i->icount > 1))
275
+ p = sp_ipageof(i, rkey, size, &a);
276
+ if (p == NULL)
277
+ return NULL;
278
+ uint32_t j;
279
+ return sp_iminof(i, p, rkey, size, &j);
280
+ }
281
+
282
+ static inline int
283
+ sp_iworldcmp(spi *i, char *rkey, int size)
284
+ {
285
+ register spipage *last = i->i[i->icount-1];
286
+ register int l =
287
+ i->cmp(i->i[0]->i[0]->key,
288
+ i->i[0]->i[0]->size, rkey, size, i->cmparg);
289
+ register int r =
290
+ i->cmp(last->i[last->count-1]->key,
291
+ last->i[last->count-1]->size,
292
+ rkey, size, i->cmparg);
293
+ /* inside index range */
294
+ if (l <= 0 && r >= 0)
295
+ return 0;
296
+ /* index min < key */
297
+ if (l == -1)
298
+ return -1;
299
+ /* index max > key */
300
+ assert(r == 1);
301
+ return 1;
302
+ }
303
+
304
+ int sp_ilte(spi *i, spii *ii, char *k, int size)
305
+ {
306
+ if (spunlikely(i->count == 0)) {
307
+ sp_iinv(i, ii);
308
+ return 0;
309
+ }
310
+ spipage *p = i->i[0];
311
+ uint32_t a = 0;
312
+ if (splikely(i->icount > 1))
313
+ p = sp_ipageof(i, k, size, &a);
314
+ if (p == NULL) {
315
+ switch (sp_iworldcmp(i, k, size)) {
316
+ case -1:
317
+ sp_iinv(i, ii);
318
+ break;
319
+ case 1:
320
+ ii->i = i;
321
+ ii->p = i->icount - 1;
322
+ ii->n = i->i[i->icount - 1]->count - 1;
323
+ break;
324
+ case 0:
325
+ assert(0);
326
+ }
327
+ return 0;
328
+ }
329
+ uint32_t j;
330
+ int eq = sp_iminof(i, p, k, size, &j) != NULL;
331
+ ii->i = i;
332
+ ii->p = a;
333
+ ii->n = j;
334
+ return eq;
335
+ }
336
+
337
+ int sp_igte(spi *i, spii *ii, char *k, int size)
338
+ {
339
+ if (spunlikely(i->count == 0)) {
340
+ sp_iinv(i, ii);
341
+ return 0;
342
+ }
343
+ spipage *p = i->i[0];
344
+ uint32_t a = 0;
345
+ if (splikely(i->icount > 1))
346
+ p = sp_ipageof(i, k, size, &a);
347
+ if (p == NULL) {
348
+ switch (sp_iworldcmp(i, k, size)) {
349
+ case -1:
350
+ ii->i = i;
351
+ ii->p = i->icount - 1;
352
+ ii->n = i->i[i->icount - 1]->count - 1;
353
+ break;
354
+ case 1:
355
+ sp_iinv(i, ii);
356
+ break;
357
+ case 0:
358
+ assert(0);
359
+ }
360
+ return 0;
361
+ }
362
+ uint32_t j;
363
+ int eq = sp_imaxof(i, p, k, size, &j) != NULL;
364
+ ii->i = i;
365
+ ii->p = a;
366
+ ii->n = j;
367
+ return eq;
368
+ }