sophia-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }