├── AUTHORS
├── .gitignore
├── c_tests
├── data_test.h
├── hash_test.h
├── list_test.h
├── rope_test.h
├── rwlock_test.h
├── stack_test.h
├── changeset_test.h
├── rope_test.c
├── hash_test.c
├── stack_test.c
├── changeset_test.c
├── data_test.c
├── rwlock_test.c
└── list_test.c
├── python_tests
├── __init__.py
├── big_test.py
└── simple_test.py
├── aodbm_test.py
├── aodbm_stack.h
├── aodbm_error.h
├── aodbm_hash.h
├── aodbm_stack.c
├── aodbm_changeset.h
├── aodbm_rwlock.h
├── aodbm_test.c
├── makefile
├── aodbm_data.h
├── aodbm_rope.h
├── aodbm_list.h
├── aodbm_internal.h
├── aodbm.h
├── aodbm_rwlock.c
├── aodbm_changeset.c
├── aodbm_hash.c
├── aodbm_data.c
├── aodbm_rope.c
├── README
├── aodbm_list.c
├── aodbm.py
├── COPYING.lesser
├── aodbm_internal.c
├── COPYING
└── aodbm.c
/AUTHORS:
--------------------------------------------------------------------------------
1 | Daniel Waterworth
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | testdb
2 | *.o
3 | *.pyc
4 | *.so
5 | *.a
6 | run_c_tests
7 |
--------------------------------------------------------------------------------
/c_tests/data_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *data_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/hash_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *hash_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/list_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *list_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/rope_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *rope_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/rwlock_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *rwlock_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/stack_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *stack_test_case();
23 |
--------------------------------------------------------------------------------
/c_tests/changeset_test.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "check.h"
21 |
22 | TCase *changeset_test_case();
23 |
--------------------------------------------------------------------------------
/python_tests/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | '''
19 |
20 | import unittest
21 | import simple_test
22 | import big_test
23 |
24 | tests = unittest.TestSuite([simple_test.tests, big_test.tests])
25 |
--------------------------------------------------------------------------------
/aodbm_test.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | '''
19 |
20 | import unittest, python_tests, os
21 |
22 | if __name__ == '__main__':
23 | unittest.TextTestRunner().run(python_tests.tests)
24 | os.remove("testdb")
25 |
--------------------------------------------------------------------------------
/aodbm_stack.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_STACK_H
21 | #define AODBM_STACK_H
22 |
23 | struct aodbm_stack;
24 | typedef struct aodbm_stack aodbm_stack;
25 |
26 | void aodbm_stack_push(aodbm_stack **, void *);
27 | void *aodbm_stack_pop(aodbm_stack **);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/c_tests/rope_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "rope_test.h"
21 | #include "aodbm_rope.h"
22 |
23 | START_TEST (test_1) {
24 |
25 | } END_TEST
26 |
27 | TCase *rope_test_case() {
28 | TCase *tc = tcase_create("rope");
29 | tcase_add_test(tc, test_1);
30 | return tc;
31 | }
32 |
--------------------------------------------------------------------------------
/aodbm_error.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "stdlib.h"
21 | #include "assert.h"
22 | #include "stdio.h"
23 |
24 | #define AODBM_OS_ERROR() \
25 | do { \
26 | printf("\nfailed at %s:%i\n", __FILE__, __LINE__); \
27 | perror("aodbm"); \
28 | assert(0); \
29 | exit(1); \
30 | } while (0);
31 |
32 | #define AODBM_CUSTOM_ERROR(msg) \
33 | do { \
34 | printf("\nfailed at %s:%i\nwith message: '%s'\n", __FILE__, __LINE__, msg); \
35 | assert(0); \
36 | exit(1); \
37 | } while (0);
38 |
--------------------------------------------------------------------------------
/aodbm_hash.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_HASH_H
21 | #define AODBM_HASH_H
22 |
23 | #include "stdint.h"
24 | #include "stdbool.h"
25 |
26 | struct aodbm_hash;
27 | typedef struct aodbm_hash aodbm_hash;
28 |
29 | aodbm_hash *aodbm_new_hash
30 | (unsigned int, unsigned int (*)(void *), bool (*)(void *, void *));
31 | void aodbm_hash_insert(aodbm_hash *, void *);
32 | void aodbm_hash_del(aodbm_hash *, void *);
33 | void *aodbm_hash_get(aodbm_hash *, void *);
34 | void aodbm_free_hash(aodbm_hash *);
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/aodbm_stack.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "stdlib.h"
21 |
22 | #include "aodbm_stack.h"
23 |
24 | struct aodbm_stack {
25 | aodbm_stack *up;
26 | void *dat;
27 | };
28 |
29 | void aodbm_stack_push(aodbm_stack **stack, void *data) {
30 | aodbm_stack *new = malloc(sizeof(aodbm_stack));
31 | new->dat = data;
32 | new->up = *stack;
33 | *stack = new;
34 | }
35 |
36 | void *aodbm_stack_pop(aodbm_stack **stack) {
37 | if (*stack == NULL) {
38 | return NULL;
39 | }
40 | aodbm_stack *next = (*stack)->up;
41 | void *out = (*stack)->dat;
42 | free(*stack);
43 | *stack = next;
44 | return out;
45 | }
46 |
--------------------------------------------------------------------------------
/c_tests/hash_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "hash_test.h"
21 | #include "aodbm_hash.h"
22 |
23 | unsigned int hash_int(void *item) {
24 | return (unsigned int)item;
25 | }
26 |
27 | bool cmp_int(void *a, void *b) {
28 | return a == b;
29 | }
30 |
31 | START_TEST (test_1) {
32 | aodbm_hash *ht = aodbm_new_hash(0, hash_int, cmp_int);
33 | aodbm_hash_insert(ht, (void *)10);
34 | fail_unless(aodbm_hash_get(ht, (void *)10) == (void *)10, NULL);
35 | aodbm_free_hash(ht);
36 | } END_TEST
37 |
38 | TCase *hash_test_case() {
39 | TCase *tc = tcase_create("hash table");
40 | tcase_add_test(tc, test_1);
41 | return tc;
42 | }
43 |
--------------------------------------------------------------------------------
/c_tests/stack_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "stack_test.h"
21 | #include "aodbm_stack.h"
22 |
23 | START_TEST (test_1) {
24 | aodbm_stack *st = NULL;
25 | aodbm_stack_push(&st, (void *)10);
26 | fail_unless(st != NULL, NULL);
27 | fail_unless(aodbm_stack_pop(&st) == (void *)10, NULL);
28 | fail_unless(st == NULL, NULL);
29 | aodbm_stack_push(&st, (void *)10);
30 | aodbm_stack_push(&st, (void *)20);
31 | aodbm_stack_push(&st, (void *)30);
32 | fail_unless(aodbm_stack_pop(&st) == (void *)30, NULL);
33 | fail_unless(aodbm_stack_pop(&st) == (void *)20, NULL);
34 | fail_unless(aodbm_stack_pop(&st) == (void *)10, NULL);
35 | fail_unless(st == NULL, NULL);
36 | } END_TEST
37 |
38 | TCase *stack_test_case() {
39 | TCase *tc = tcase_create("stack");
40 | tcase_add_test(tc, test_1);
41 | return tc;
42 | }
43 |
--------------------------------------------------------------------------------
/python_tests/big_test.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | '''
19 |
20 | import unittest, aodbm, random
21 |
22 | class TestBig(unittest.TestCase):
23 | def setUp(self):
24 | self.db = aodbm.AODBM('testdb')
25 |
26 | def test_big(self):
27 | ver = aodbm.Version(self.db, 0)
28 | nums = range(500)
29 | random.shuffle(nums)
30 | for n in nums:
31 | ver['hello' + str(n)] = 'world' + str(n)
32 | random.shuffle(nums)
33 | for i in nums:
34 | self.assertEqual(ver['hello' + str(i)], 'world' + str(i))
35 | random.shuffle(nums)
36 | for n in nums:
37 | del ver['hello' + str(n)]
38 | self.assertRaises(KeyError, ver.__getitem__, 'hello' + str(n))
39 |
40 | tests = [TestBig]
41 | tests = map(unittest.TestLoader().loadTestsFromTestCase, tests)
42 | tests = unittest.TestSuite(tests)
43 |
--------------------------------------------------------------------------------
/aodbm_changeset.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_CHANGESET_H
21 | #define AODBM_CHANGESET_H
22 |
23 | #define AODBM_MODIFY 1
24 | #define AODBM_REMOVE 2
25 |
26 | #include "aodbm_list.h"
27 |
28 | struct aodbm_data;
29 |
30 | struct aodbm_change {
31 | unsigned char type;
32 | struct aodbm_data *key;
33 | struct aodbm_data *val;
34 | };
35 | typedef struct aodbm_change aodbm_change;
36 |
37 | struct aodbm_changeset {
38 | aodbm_list *list;
39 | };
40 | typedef struct aodbm_changeset aodbm_changeset;
41 |
42 | aodbm_changeset aodbm_changeset_empty();
43 | void aodbm_changeset_add_modify
44 | (aodbm_changeset, struct aodbm_data *, struct aodbm_data *);
45 | void aodbm_changeset_add_remove(aodbm_changeset, struct aodbm_data *);
46 | aodbm_changeset aodbm_changeset_merge_di(aodbm_changeset, aodbm_changeset);
47 | void aodbm_free_changeset(aodbm_changeset);
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/aodbm_rwlock.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | /*
21 | An implementation of a rwlock that won't stave the writers.
22 | */
23 |
24 | #ifndef AODBM_RWLOCK_H
25 | #define AODBM_RWLOCK_H
26 |
27 | #include "pthread.h"
28 | #include "stdint.h"
29 | #include "stdbool.h"
30 |
31 | struct aodbm_rwlock_t {
32 | pthread_mutex_t mut;
33 | pthread_cond_t cnd;
34 | volatile size_t readers;
35 | volatile size_t writers_waiting;
36 | volatile bool is_writing;
37 | };
38 |
39 | typedef struct aodbm_rwlock_t aodbm_rwlock_t;
40 |
41 | void aodbm_rwlock_init(aodbm_rwlock_t *);
42 | void aodbm_rwlock_destroy(aodbm_rwlock_t *);
43 |
44 | void aodbm_rwlock_rdlock(aodbm_rwlock_t *);
45 | void aodbm_rwlock_wrlock(aodbm_rwlock_t *);
46 | void aodbm_rwlock_unlock(aodbm_rwlock_t *);
47 |
48 | bool aodbm_rwlock_tryrdlock(aodbm_rwlock_t *);
49 | bool aodbm_rwlock_trywrlock(aodbm_rwlock_t *);
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/aodbm_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include
21 |
22 | #include "hash_test.h"
23 | #include "data_test.h"
24 | #include "rope_test.h"
25 | #include "stack_test.h"
26 | #include "rwlock_test.h"
27 | #include "list_test.h"
28 | #include "changeset_test.h"
29 |
30 | int main(void) {
31 | int number_failed;
32 | Suite *s = suite_create("Main");
33 |
34 | suite_add_tcase(s, hash_test_case());
35 | suite_add_tcase(s, data_test_case());
36 | suite_add_tcase(s, rope_test_case());
37 | suite_add_tcase(s, stack_test_case());
38 | suite_add_tcase(s, rwlock_test_case());
39 | suite_add_tcase(s, list_test_case());
40 | suite_add_tcase(s, changeset_test_case());
41 |
42 | SRunner *sr = srunner_create(s);
43 | srunner_run_all(sr, CK_NORMAL);
44 | number_failed = srunner_ntests_failed(sr);
45 | srunner_free(sr);
46 | return (number_failed == 0) ? 0 : 1;
47 | }
48 |
--------------------------------------------------------------------------------
/c_tests/changeset_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "changeset_test.h"
21 | #include "aodbm.h"
22 | #include "aodbm_data.h"
23 |
24 | START_TEST (test_1) {
25 | aodbm_changeset set = aodbm_changeset_empty();
26 | aodbm_data *key = aodbm_data_from_str("hello");
27 | aodbm_data *val = aodbm_data_from_str("world");
28 | aodbm_changeset_add_modify(set, key, val);
29 | aodbm *db = aodbm_open("testdb", 0);
30 | aodbm_version ver = aodbm_apply_di(db, 0, set);
31 | fail_unless(ver != 0);
32 | aodbm_data *r_val = aodbm_get(db, ver, key);
33 | fail_unless(r_val != NULL, NULL);
34 | fail_unless(aodbm_data_eq(r_val, val), NULL);
35 | aodbm_free_data(key);
36 | aodbm_free_data(val);
37 | aodbm_free_data(r_val);
38 | aodbm_close(db);
39 | } END_TEST
40 |
41 | TCase *changeset_test_case() {
42 | TCase *tc = tcase_create("changeset");
43 | tcase_add_test(tc, test_1);
44 | return tc;
45 | }
46 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | # Copyright (C) 2011 aodbm authors,
2 | #
3 | # This file is part of aodbm.
4 | #
5 | # aodbm is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU Lesser General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # aodbm is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU Lesser General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU Lesser General Public License
16 | # along with this program. If not, see .
17 |
18 | srcs = aodbm.c aodbm_data.c aodbm_rope.c aodbm_internal.c aodbm_rwlock.c \
19 | aodbm_stack.c aodbm_hash.c aodbm_list.c aodbm_changeset.c
20 | objs = aodbm.o aodbm_data.o aodbm_rope.o aodbm_internal.o aodbm_rwlock.o \
21 | aodbm_stack.o aodbm_hash.o aodbm_list.o aodbm_changeset.o
22 | flags = -g -fPIC -lpthread -D_FILE_OFFSET_BITS=64 #-DAODBM_USE_MMAP
23 | test_srcs = c_tests/hash_test.c c_tests/data_test.c c_tests/rope_test.c \
24 | c_tests/stack_test.c c_tests/rwlock_test.c c_tests/list_test.c \
25 | c_tests/changeset_test.c
26 |
27 | all:
28 | gcc ${srcs} -c -I./ -D_GNU_SOURCE ${flags}
29 | ar -cq libaodbm.a ${objs}
30 | gcc ${objs} -shared -o libaodbm.so ${flags}
31 |
32 | check: all
33 | gcc ${test_srcs} aodbm_test.c libaodbm.a -o run_c_tests ${flags} -lcheck \
34 | -lpthread -I./c_tests/ -I./
35 | python aodbm_test.py
36 | ./run_c_tests
37 |
38 | clean:
39 | @$(RM) *.o a.out
--------------------------------------------------------------------------------
/c_tests/data_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "data_test.h"
21 | #include "aodbm_data.h"
22 |
23 | START_TEST (test_1) {
24 | aodbm_data *a = aodbm_construct_data("hello", 5);
25 | fail_unless(a->sz == 5);
26 | fail_unless(memcmp("hello", a->dat, 5) == 0);
27 |
28 | aodbm_data *b = aodbm_data_dup(a);
29 | fail_unless(b->sz == 5);
30 | fail_unless(memcmp("hello", b->dat, 5) == 0);
31 |
32 | fail_unless(aodbm_data_eq(a, b));
33 | fail_unless(aodbm_data_cmp(a, b) == 0);
34 | aodbm_free_data(a);
35 |
36 | a = aodbm_data_from_str("hello");
37 | fail_unless(a->sz == 5);
38 | fail_unless(memcmp("hello", a->dat, 5) == 0);
39 |
40 | aodbm_free_data(a);
41 | aodbm_free_data(b);
42 |
43 | a = aodbm_data_empty();
44 | b = aodbm_data_empty();
45 | fail_unless(aodbm_data_eq(a, b));
46 |
47 | aodbm_free_data(a);
48 | aodbm_free_data(b);
49 | } END_TEST
50 |
51 | TCase *data_test_case() {
52 | TCase *tc = tcase_create("data");
53 | tcase_add_test(tc, test_1);
54 | return tc;
55 | }
56 |
--------------------------------------------------------------------------------
/aodbm_data.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_DATA_H
21 | #define AODBM_DATA_H
22 |
23 | #include "stdint.h"
24 | #include "stdbool.h"
25 |
26 | #include "aodbm.h"
27 |
28 | /* NOTE: functions ending in di have destructive input */
29 |
30 | /* aodbm_data functions */
31 | aodbm_data *aodbm_construct_data(const char *, size_t);
32 | aodbm_data *aodbm_data_dup(aodbm_data *);
33 | aodbm_data *aodbm_data_from_str(const char *);
34 | aodbm_data *aodbm_data_from_32(uint32_t);
35 | aodbm_data *aodbm_data_from_64(uint64_t);
36 | aodbm_data *aodbm_cat_data(aodbm_data *, aodbm_data *);
37 | aodbm_data *aodbm_cat_data_di(aodbm_data *, aodbm_data *);
38 | aodbm_data *aodbm_data_empty();
39 | aodbm_data *aodbm_data_dup(aodbm_data *);
40 |
41 | bool aodbm_data_lt(aodbm_data *, aodbm_data *);
42 | bool aodbm_data_gt(aodbm_data *, aodbm_data *);
43 | bool aodbm_data_le(aodbm_data *, aodbm_data *);
44 | bool aodbm_data_ge(aodbm_data *, aodbm_data *);
45 | bool aodbm_data_eq(aodbm_data *, aodbm_data *);
46 | int aodbm_data_cmp(aodbm_data *, aodbm_data *);
47 |
48 | /* data printing */
49 | void aodbm_print_data(aodbm_data *);
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/aodbm_rope.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_ROPE_H
21 | #define AODBM_ROPE_H
22 |
23 | #include "aodbm.h"
24 |
25 | /* this type is used to make merging aodbm_data objects cheaper */
26 | /* implementation note:
27 | internally it is just a list of aodbm_data objects,
28 | rather than the more usual tree of strings */
29 | struct aodbm_rope;
30 | typedef struct aodbm_rope aodbm_rope;
31 |
32 | /* aodbm_rope functions */
33 | aodbm_rope *aodbm_rope_empty();
34 | aodbm_rope *aodbm_data_to_rope_di(aodbm_data *);
35 | aodbm_rope *aodbm_data_to_rope(aodbm_data *);
36 | aodbm_rope *aodbm_data2_to_rope_di(aodbm_data *, aodbm_data *);
37 | aodbm_rope *aodbm_data2_to_rope(aodbm_data *, aodbm_data *);
38 | size_t aodbm_rope_size(aodbm_rope *);
39 | aodbm_data *aodbm_rope_to_data(aodbm_rope *);
40 | aodbm_data *aodbm_rope_to_data_di(aodbm_rope *);
41 | void aodbm_free_rope(aodbm_rope *);
42 |
43 | /* the aodbm_data object is destroyed */
44 | void aodbm_rope_append_di(aodbm_rope *, aodbm_data *);
45 | void aodbm_rope_prepend_di(aodbm_data *, aodbm_rope *);
46 |
47 | void aodbm_rope_append(aodbm_rope *, aodbm_data *);
48 | void aodbm_rope_prepend(aodbm_data *, aodbm_rope *);
49 | aodbm_rope *aodbm_rope_merge_di(aodbm_rope *, aodbm_rope *);
50 |
51 | void aodbm_print_rope(aodbm_rope *);
52 |
53 | #endif
54 |
--------------------------------------------------------------------------------
/python_tests/simple_test.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | '''
19 |
20 | import unittest, aodbm
21 |
22 | class TestSimple(unittest.TestCase):
23 | def setUp(self):
24 | self.db = aodbm.AODBM('testdb')
25 |
26 | def test_simple(self):
27 | # a simple test with one record
28 | ver = aodbm.Version(self.db, 0)
29 | self.assertRaises(KeyError, ver.__getitem__, 'hello')
30 | self.assertFalse(ver.has('test'))
31 | ver['test'] = 'hello'
32 | self.assertEqual(ver['test'], 'hello')
33 | self.assertTrue(ver.has('test'))
34 | del ver['test']
35 | self.assertRaises(KeyError, ver.__getitem__, 'test')
36 | self.assertFalse(ver.has('test'))
37 | del ver['test']
38 | self.assertRaises(KeyError, ver.__getitem__, 'test')
39 | self.assertFalse(ver.has('test'))
40 |
41 | def test_insert_empty(self):
42 | ver = aodbm.Version(self.db, 0)
43 | ver['hello'] = 'world'
44 | # create an empty root node
45 | del ver['hello']
46 | ver['hello'] = 'world'
47 | self.assertTrue(ver.has('hello'))
48 | self.assertEqual(ver['hello'], 'world')
49 |
50 | tests = [TestSimple]
51 | tests = map(unittest.TestLoader().loadTestsFromTestCase, tests)
52 | tests = unittest.TestSuite(tests)
53 |
--------------------------------------------------------------------------------
/c_tests/rwlock_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "rwlock_test.h"
21 | #include "aodbm_rwlock.h"
22 |
23 | #include "stdbool.h"
24 | #include "pthread.h"
25 |
26 | typedef struct {
27 | aodbm_rwlock_t *lock;
28 | volatile bool *locked;
29 | } lock_data;
30 |
31 | static void *obtain_wrlock(void *ptr) {
32 | lock_data *dat = (lock_data *)ptr;
33 |
34 | fail_unless(*dat->locked);
35 | aodbm_rwlock_wrlock(dat->lock);
36 | fail_unless(*dat->locked == false);
37 | aodbm_rwlock_unlock(dat->lock);
38 |
39 | return NULL;
40 | }
41 |
42 | START_TEST (test_1) {
43 | pthread_t thread;
44 | aodbm_rwlock_t lock;
45 | aodbm_rwlock_init(&lock);
46 |
47 | aodbm_rwlock_rdlock(&lock);
48 | fail_unless(aodbm_rwlock_tryrdlock(&lock));
49 | aodbm_rwlock_unlock(&lock);
50 |
51 | volatile bool locked = true;
52 |
53 | lock_data dat;
54 | dat.lock = &lock;
55 | dat.locked = &locked;
56 |
57 | fail_unless(aodbm_rwlock_trywrlock(&lock) == false);
58 |
59 | pthread_create(&thread, NULL, obtain_wrlock, (void *)&dat);
60 | locked = false;
61 | aodbm_rwlock_unlock(&lock);
62 |
63 | aodbm_rwlock_destroy(&lock);
64 | } END_TEST
65 |
66 | TCase *rwlock_test_case() {
67 | TCase *tc = tcase_create("rwlock");
68 | tcase_add_test(tc, test_1);
69 | return tc;
70 | }
71 |
--------------------------------------------------------------------------------
/aodbm_list.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_LIST_H
21 | #define AODBM_LIST_H
22 |
23 | #include "stdbool.h"
24 | #include "stdlib.h"
25 |
26 | struct aodbm_list;
27 | typedef struct aodbm_list aodbm_list;
28 |
29 | struct aodbm_list_iterator;
30 | typedef struct aodbm_list_iterator aodbm_list_iterator;
31 |
32 | aodbm_list *aodbm_list_empty();
33 | void aodbm_free_list(aodbm_list *);
34 |
35 | void aodbm_list_push_front(aodbm_list *, void *);
36 | void aodbm_list_push_back(aodbm_list *, void *);
37 | void *aodbm_list_pop_front(aodbm_list *);
38 | void *aodbm_list_pop_back(aodbm_list *);
39 |
40 | bool aodbm_list_is_empty(aodbm_list *);
41 | size_t aodbm_list_length(aodbm_list *);
42 |
43 | aodbm_list *aodbm_list_merge_di(aodbm_list *, aodbm_list *);
44 |
45 | void aodbm_list_insert(aodbm_list_iterator *, void *);
46 | void aodbm_list_remove(aodbm_list_iterator *);
47 |
48 | aodbm_list_iterator *aodbm_list_begin(aodbm_list *);
49 | aodbm_list_iterator *aodbm_list_end(aodbm_list *);
50 |
51 | void aodbm_list_iterator_next(aodbm_list_iterator *);
52 | void aodbm_list_iterator_prev(aodbm_list_iterator *);
53 | bool aodbm_list_iterator_is_begin(aodbm_list_iterator *);
54 | bool aodbm_list_iterator_is_end(aodbm_list_iterator *);
55 | bool aodbm_list_iterator_is_finished(aodbm_list_iterator *);
56 | void *aodbm_list_iterator_get(aodbm_list_iterator *);
57 |
58 | void aodbm_free_list_iterator(aodbm_list_iterator *);
59 |
60 | #endif
61 |
--------------------------------------------------------------------------------
/aodbm_internal.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #ifndef AODBM_INTERNAL_H
21 | #define AODBM_INTERNAL_H
22 |
23 | #include "aodbm.h"
24 | #include "aodbm_data.h"
25 | #include "aodbm_rope.h"
26 | #include "aodbm_rwlock.h"
27 | #include "aodbm_stack.h"
28 |
29 | struct aodbm {
30 | uint64_t file_size;
31 | FILE *fd;
32 | pthread_mutex_t rw;
33 | volatile uint64_t cur;
34 | pthread_mutex_t version;
35 | #ifdef AODBM_USE_MMAP
36 | volatile void *mapping;
37 | volatile uint64_t mapping_size;
38 | aodbm_rwlock_t mmap_mut;
39 | #endif
40 | };
41 |
42 | void print_hex(unsigned char);
43 | void annotate_data(const char *name, aodbm_data *);
44 | void annotate_rope(const char *name, aodbm_rope *);
45 |
46 | aodbm_rope *make_block(aodbm_data *);
47 | aodbm_rope *make_block_di(aodbm_data *);
48 | aodbm_rope *make_record(aodbm_data *, aodbm_data *);
49 | aodbm_rope *make_record_di(aodbm_data *, aodbm_data *);
50 |
51 | bool aodbm_read_bytes(aodbm *, void *, size_t);
52 | void aodbm_seek(aodbm *, int64_t, int);
53 | uint64_t aodbm_tell(aodbm *);
54 | void aodbm_write_bytes(aodbm *, void *, size_t);
55 | void aodbm_truncate(aodbm *, uint64_t);
56 |
57 | void aodbm_write_data_block(aodbm *db, aodbm_data *data);
58 | void aodbm_write_version(aodbm *db, uint64_t ver);
59 | void aodbm_read(aodbm *db, uint64_t off, size_t sz, void *ptr);
60 | uint32_t aodbm_read32(aodbm *db, uint64_t off);
61 | uint64_t aodbm_read64(aodbm *db, uint64_t off);
62 | aodbm_data *aodbm_read_data(aodbm *db, uint64_t off);
63 |
64 | /* returns the offset of the leaf node that the key belongs in */
65 | uint64_t aodbm_search(aodbm *, aodbm_version, aodbm_data *);
66 |
67 | struct aodbm_path_node {
68 | aodbm_data *key;
69 | uint64_t node;
70 | };
71 |
72 | typedef struct aodbm_path_node aodbm_path_node;
73 |
74 | aodbm_stack *aodbm_search_path(aodbm *, aodbm_version, aodbm_data *);
75 |
76 | #endif
77 |
--------------------------------------------------------------------------------
/c_tests/list_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "list_test.h"
21 | #include "aodbm_list.h"
22 |
23 | START_TEST (test_1) {
24 | aodbm_list *list = aodbm_list_empty();
25 | aodbm_list_push_back(list, (void *)10);
26 | fail_unless(aodbm_list_pop_back(list) == (void *)10, NULL);
27 | aodbm_free_list(list);
28 | } END_TEST
29 |
30 | START_TEST (test_2) {
31 | aodbm_list *list = aodbm_list_empty();
32 | aodbm_list_push_front(list, (void *)10);
33 | aodbm_list_push_front(list, (void *)20);
34 | fail_unless(aodbm_list_pop_back(list) == (void *)10, NULL);
35 | fail_unless(aodbm_list_pop_front(list) == (void *)20, NULL);
36 | aodbm_free_list(list);
37 | } END_TEST
38 |
39 | START_TEST (test_3) {
40 | aodbm_list *list = aodbm_list_empty();
41 | aodbm_list_push_back(list, (void *)10);
42 | aodbm_list_push_back(list, (void *)20);
43 | aodbm_list_push_back(list, (void *)30);
44 |
45 | aodbm_list_iterator *it = aodbm_list_begin(list);
46 | fail_unless(aodbm_list_iterator_get(it) == (void *)10, NULL);
47 | fail_unless(aodbm_list_iterator_is_begin(it), NULL);
48 | fail_if(aodbm_list_iterator_is_end(it), NULL);
49 | aodbm_list_iterator_next(it);
50 | fail_unless(aodbm_list_iterator_get(it) == (void *)20, NULL);
51 | fail_if(aodbm_list_iterator_is_begin(it), NULL);
52 | fail_if(aodbm_list_iterator_is_end(it), NULL);
53 | aodbm_list_iterator_next(it);
54 | fail_unless(aodbm_list_iterator_get(it) == (void *)30, NULL);
55 | fail_if(aodbm_list_iterator_is_begin(it), NULL);
56 | fail_unless(aodbm_list_iterator_is_end(it), NULL);
57 | aodbm_free_list_iterator(it);
58 |
59 | aodbm_list_pop_back(list);
60 | aodbm_list_pop_back(list);
61 | aodbm_list_pop_back(list);
62 | aodbm_free_list(list);
63 | } END_TEST
64 |
65 | TCase *list_test_case() {
66 | TCase *tc = tcase_create("list");
67 | tcase_add_test(tc, test_1);
68 | tcase_add_test(tc, test_2);
69 | tcase_add_test(tc, test_3);
70 | return tc;
71 | }
72 |
--------------------------------------------------------------------------------
/aodbm.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | /* bool __sync_bool_compare_and_swap (type *ptr, type oldval, type newval) */
21 | /* TODO: better support for trees as values */
22 |
23 | #ifndef AODBM
24 | #define AODBM
25 |
26 | #include "aodbm_changeset.h"
27 |
28 | #include
29 | #include
30 |
31 | /* the type of the database object */
32 | struct aodbm;
33 |
34 | /* the main type for data */
35 | struct aodbm_data {
36 | char *dat;
37 | size_t sz;
38 | };
39 |
40 | typedef struct aodbm aodbm;
41 | typedef struct aodbm_data aodbm_data;
42 |
43 | typedef uint64_t aodbm_version;
44 |
45 | aodbm *aodbm_open(const char *, int);
46 | void aodbm_close(aodbm *);
47 |
48 | aodbm_version aodbm_current(aodbm *);
49 | bool aodbm_commit(aodbm *, aodbm_version);
50 |
51 | bool aodbm_has(aodbm *, aodbm_version, aodbm_data *);
52 | aodbm_version aodbm_set(aodbm *, aodbm_version, aodbm_data *, aodbm_data *);
53 | aodbm_data *aodbm_get(aodbm *, aodbm_version, aodbm_data *);
54 | aodbm_version aodbm_del(aodbm *, aodbm_version, aodbm_data *);
55 |
56 | bool aodbm_is_based_on(aodbm *, aodbm_version, aodbm_version);
57 | aodbm_version aodbm_previous_version(aodbm *, aodbm_version);
58 | aodbm_version aodbm_common_ancestor(aodbm *, aodbm_version, aodbm_version);
59 |
60 | aodbm_changeset aodbm_diff_prev(aodbm *, aodbm_version);
61 | aodbm_changeset aodbm_diff_prev_rev(aodbm *, aodbm_version);
62 | aodbm_changeset aodbm_diff(aodbm *, aodbm_version, aodbm_version);
63 | aodbm_version aodbm_apply(aodbm *, aodbm_version, aodbm_changeset);
64 | aodbm_version aodbm_apply_di(aodbm *, aodbm_version, aodbm_changeset);
65 | aodbm_version aodbm_merge(aodbm *, aodbm_version, aodbm_version);
66 |
67 | /* iteration API */
68 | struct aodbm_iterator;
69 | typedef struct aodbm_iterator aodbm_iterator;
70 |
71 | struct aodbm_record {
72 | aodbm_data *key;
73 | aodbm_data *val;
74 | };
75 |
76 | typedef struct aodbm_record aodbm_record;
77 |
78 | aodbm_iterator *aodbm_new_iterator(aodbm *, aodbm_version);
79 | aodbm_iterator *aodbm_iterate_from(aodbm *, aodbm_version, aodbm_data *);
80 | aodbm_record aodbm_iterator_next(aodbm *, aodbm_iterator *);
81 | void aodbm_iterator_goto(aodbm *, aodbm_iterator *it, aodbm_data *);
82 | void aodbm_free_iterator(aodbm_iterator *);
83 |
84 | void aodbm_free_data(aodbm_data *);
85 |
86 | #endif
87 |
--------------------------------------------------------------------------------
/aodbm_rwlock.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "stdio.h"
21 | #include "stdlib.h"
22 | #include "assert.h"
23 |
24 | #include "aodbm_rwlock.h"
25 | #include "aodbm_error.h"
26 |
27 | void aodbm_rwlock_init(aodbm_rwlock_t *lock) {
28 | pthread_mutex_init(&lock->mut, NULL);
29 | pthread_cond_init(&lock->cnd, NULL);
30 | lock->readers = 0;
31 | lock->is_writing = false;
32 | lock->writers_waiting = 0;
33 | }
34 |
35 | void aodbm_rwlock_destroy(aodbm_rwlock_t *lock) {
36 | pthread_mutex_destroy(&lock->mut);
37 | pthread_cond_destroy(&lock->cnd);
38 | }
39 |
40 | void aodbm_rwlock_rdlock(aodbm_rwlock_t *lock) {
41 | pthread_mutex_lock(&lock->mut);
42 | while (lock->is_writing || lock->writers_waiting != 0) {
43 | pthread_cond_wait(&lock->cnd, &lock->mut);
44 | }
45 | lock->readers += 1;
46 | pthread_mutex_unlock(&lock->mut);
47 | }
48 |
49 | void aodbm_rwlock_wrlock(aodbm_rwlock_t *lock) {
50 | pthread_mutex_lock(&lock->mut);
51 | lock->writers_waiting += 1;
52 | while (lock->readers != 0 || lock->is_writing) {
53 | pthread_cond_wait(&lock->cnd, &lock->mut);
54 | }
55 | lock->is_writing = true;
56 | lock->writers_waiting -= 1;
57 | pthread_mutex_unlock(&lock->mut);
58 | }
59 |
60 | void aodbm_rwlock_unlock(aodbm_rwlock_t *lock) {
61 | pthread_mutex_lock(&lock->mut);
62 | if (lock->is_writing) {
63 | lock->is_writing = false;
64 | pthread_cond_broadcast(&lock->cnd);
65 | } else if (lock->readers > 0) {
66 | lock->readers -= 1;
67 | if (lock->readers == 0) {
68 | pthread_cond_broadcast(&lock->cnd);
69 | }
70 | } else {
71 | AODBM_CUSTOM_ERROR("invalid rwlock state");
72 | }
73 | pthread_mutex_unlock(&lock->mut);
74 | }
75 |
76 | bool aodbm_rwlock_tryrdlock(aodbm_rwlock_t *lock) {
77 | bool result;
78 | pthread_mutex_lock(&lock->mut);
79 | result = !lock->is_writing && lock->writers_waiting == 0;
80 | if (result) {
81 | lock->readers += 1;
82 | }
83 | pthread_mutex_unlock(&lock->mut);
84 | return result;
85 | }
86 |
87 | bool aodbm_rwlock_trywrlock(aodbm_rwlock_t *lock) {
88 | bool result;
89 | pthread_mutex_lock(&lock->mut);
90 | result = lock->readers == 0 && !lock->is_writing;
91 | if (result) {
92 | lock->is_writing = true;
93 | }
94 | pthread_mutex_unlock(&lock->mut);
95 | return result;
96 | }
97 |
--------------------------------------------------------------------------------
/aodbm_changeset.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "aodbm_changeset.h"
21 | #include "aodbm_data.h"
22 | #include "aodbm_error.h"
23 |
24 | static aodbm_change *create_remove_di(aodbm_data *key) {
25 | aodbm_change *c = malloc(1 + sizeof(aodbm_data *));
26 | c->type = AODBM_REMOVE;
27 | c->key = key;
28 | return c;
29 | }
30 |
31 | static aodbm_change *create_remove(aodbm_data *key) {
32 | return create_remove_di(aodbm_data_dup(key));
33 | }
34 |
35 | static aodbm_change *create_modify_di(aodbm_data *key, aodbm_data *val) {
36 | aodbm_change *c = malloc(sizeof(aodbm_change));
37 | c->type = AODBM_MODIFY;
38 | c->key = key;
39 | c->val = val;
40 | return c;
41 | }
42 |
43 | static aodbm_change *create_modify(aodbm_data *key, aodbm_data *val) {
44 | return create_modify_di(aodbm_data_dup(key), aodbm_data_dup(val));
45 | }
46 |
47 | static void free_change(aodbm_change *c) {
48 | switch (c->type) {
49 | case AODBM_REMOVE:
50 | break;
51 | case AODBM_MODIFY:
52 | aodbm_free_data(c->val);
53 | break;
54 | default:
55 | AODBM_CUSTOM_ERROR("unknown change type");
56 | };
57 | aodbm_free_data(c->key);
58 | free(c);
59 | }
60 |
61 | aodbm_changeset aodbm_changeset_empty() {
62 | aodbm_changeset result;
63 | result.list = aodbm_list_empty();
64 | return result;
65 | }
66 |
67 | void aodbm_changeset_add_modify_di(aodbm_changeset changeset,
68 | aodbm_data *key,
69 | aodbm_data *val) {
70 | aodbm_change *c = create_modify_di(key, val);
71 | aodbm_list_push_back(changeset.list, c);
72 | }
73 |
74 | void aodbm_changeset_add_modify(aodbm_changeset changeset,
75 | aodbm_data *key,
76 | aodbm_data *val) {
77 | aodbm_change *c = create_modify(key, val);
78 | aodbm_list_push_back(changeset.list, c);
79 | }
80 |
81 | void aodbm_changeset_add_remove_di(aodbm_changeset changeset, aodbm_data *key) {
82 | aodbm_change *c = create_remove_di(key);
83 | aodbm_list_push_back(changeset.list, c);
84 | }
85 |
86 | void aodbm_changeset_add_remove(aodbm_changeset changeset, aodbm_data *key) {
87 | aodbm_change *c = create_remove(key);
88 | aodbm_list_push_back(changeset.list, c);
89 | }
90 |
91 | aodbm_changeset aodbm_changeset_merge_di(aodbm_changeset a, aodbm_changeset b) {
92 | aodbm_changeset result;
93 | result.list = aodbm_list_merge_di(a.list, b.list);
94 | /* TODO: remove unneeded changes */
95 | return result;
96 | }
97 |
98 | void aodbm_free_changeset(aodbm_changeset c) {
99 | while (!aodbm_list_is_empty(c.list)) {
100 | free_change(aodbm_list_pop_back(c.list));
101 | }
102 | aodbm_free_list(c.list);
103 | }
104 |
--------------------------------------------------------------------------------
/aodbm_hash.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #define AODBM_HASH_BUCKETS 5
21 |
22 | #include "aodbm_hash.h"
23 |
24 | #include "stdlib.h"
25 |
26 | struct aodbm_hash {
27 | void **data;
28 | unsigned int sz;
29 | unsigned int (*hash_function)(void *);
30 | bool (*eq)(void *, void *);
31 | };
32 |
33 | static uint32_t hash(uint32_t a){
34 | a = (a+0x7ed55d16) + (a<<12);
35 | a = (a^0xc761c23c) ^ (a>>19);
36 | a = (a+0x165667b1) + (a<<5);
37 | a = (a+0xd3a2646c) ^ (a<<9);
38 | a = (a+0xfd7046c5) + (a<<3);
39 | a = (a^0xb55a4f09) ^ (a>>16);
40 | return a;
41 | }
42 |
43 | aodbm_hash *aodbm_new_hash(unsigned int sz,
44 | unsigned int (*hash_function)(void *),
45 | bool (*eq)(void *, void *)) {
46 | if (sz == 0) {
47 | sz = 16;
48 | }
49 | aodbm_hash *hash = malloc(sizeof(aodbm_hash));
50 | hash->sz = sz;
51 | hash->hash_function = hash_function;
52 | hash->eq = eq;
53 | hash->data = malloc(sizeof(void *) * sz);
54 | unsigned int i;
55 | for (i = 0; i < sz; ++i) {
56 | hash->data[i] = NULL;
57 | }
58 | return hash;
59 | }
60 |
61 | void aodbm_hash_insert(aodbm_hash *ht, void *val) {
62 | unsigned int key = ht->hash_function(val);
63 | unsigned int orig_key = key;
64 | unsigned int i;
65 | for (i = 0; i < AODBM_HASH_BUCKETS; ++i) {
66 | void **b = &ht->data[key % ht->sz];
67 | if (*b == NULL) {
68 | *b = val;
69 | return;
70 | }
71 | key = hash(key);
72 | }
73 | void **old = ht->data;
74 | ht->data = malloc(sizeof(void *) * ht->sz * 2);
75 | unsigned int old_sz = ht->sz;
76 | ht->sz = ht->sz * 2;
77 | for (i = 0; i < ht->sz; ++i) {
78 | ht->data[i] = NULL;
79 | }
80 | for (i = 0; i < old_sz; ++i) {
81 | void *b = old[i];
82 | if (b != NULL) {
83 | aodbm_hash_insert(ht, b);
84 | }
85 | }
86 | free(old);
87 | }
88 |
89 | void aodbm_hash_del(aodbm_hash *ht, void *data) {
90 | unsigned int key = ht->hash_function(data);
91 | unsigned int orig_key = key;
92 | unsigned int i;
93 | for (i = 0; i < AODBM_HASH_BUCKETS; ++i) {
94 | void **b = &ht->data[key % ht->sz];
95 | if (ht->eq(data, *b)) {
96 | *b = NULL;
97 | return;
98 | }
99 | key = hash(key);
100 | }
101 | }
102 |
103 | void *aodbm_hash_get(aodbm_hash *ht, void *data) {
104 | unsigned int key = ht->hash_function(data);
105 | unsigned int orig_key = key;
106 | unsigned int i;
107 | for (i = 0; i < AODBM_HASH_BUCKETS; ++i) {
108 | void *b = ht->data[key % ht->sz];
109 | if (ht->eq(data, b)) {
110 | return b;
111 | }
112 | key = hash(key);
113 | }
114 | return NULL;
115 | }
116 |
117 | void aodbm_free_hash(aodbm_hash *ht) {
118 | free(ht->data);
119 | free(ht);
120 | }
121 |
--------------------------------------------------------------------------------
/aodbm_data.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 |
23 | #include
24 |
25 | #define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) |\
26 | ntohl( ((uint32_t)(x >> 32)) ) )
27 | #define htonll(x) ntohll(x)
28 |
29 | #include "aodbm.h"
30 | #include "aodbm_data.h"
31 | #include "aodbm_rope.h"
32 |
33 | aodbm_data *aodbm_construct_data(const char *dat, size_t sz) {
34 | aodbm_data *ptr = malloc(sizeof(aodbm_data));
35 | ptr->sz = sz;
36 | ptr->dat = malloc(sz);
37 | memcpy(ptr->dat, dat, sz);
38 | return ptr;
39 | }
40 |
41 | aodbm_data *aodbm_cat_data(aodbm_data *a, aodbm_data *b) {
42 | aodbm_data *dat = malloc(sizeof(aodbm_data));
43 | dat->sz = a->sz + b->sz;
44 | dat->dat = malloc(dat->sz);
45 | memcpy(dat->dat, a->dat, a->sz);
46 | memcpy(dat->dat + a->sz, b->dat, b->sz);
47 | return dat;
48 | }
49 |
50 | aodbm_data *aodbm_cat_data_di(aodbm_data *a, aodbm_data *b) {
51 | aodbm_data *res = aodbm_cat_data(a, b);
52 | aodbm_free_data(a);
53 | aodbm_free_data(b);
54 | return res;
55 | }
56 |
57 | aodbm_data *aodbm_data_from_str(const char *dat) {
58 | return aodbm_construct_data(dat, strlen(dat));
59 | }
60 |
61 | aodbm_data *aodbm_data_from_32(uint32_t n) {
62 | n = htonl(n);
63 | return aodbm_construct_data((const char*)&n, 4);
64 | }
65 |
66 | aodbm_data *aodbm_data_from_64(uint64_t n) {
67 | n = htonll(n);
68 | return aodbm_construct_data((const char*)&n, 8);
69 | }
70 |
71 | aodbm_data *aodbm_data_empty() {
72 | aodbm_data *dat = malloc(sizeof(aodbm_data));
73 | dat->sz = 0;
74 | dat->dat = NULL;
75 | return dat;
76 | }
77 |
78 | bool aodbm_data_lt(aodbm_data *a, aodbm_data *b) {
79 | int p;
80 | if (a->sz < b->sz) {
81 | return true;
82 | } else if (a->sz > b->sz) {
83 | return false;
84 | } else {
85 | for (p = 0; p < a->sz; ++p) {
86 | if (a->dat[p] < b->dat[p])
87 | return true;
88 | if (a->dat[p] > b->dat[p])
89 | return false;
90 | }
91 | return false;
92 | }
93 | }
94 |
95 | bool aodbm_data_gt(aodbm_data *a, aodbm_data *b) {
96 | return aodbm_data_lt(b, a);
97 | }
98 |
99 | bool aodbm_data_le(aodbm_data *a, aodbm_data *b) {
100 | return !aodbm_data_gt(a, b);
101 | }
102 |
103 | bool aodbm_data_ge(aodbm_data *a, aodbm_data *b) {
104 | return !aodbm_data_lt(a, b);
105 | }
106 |
107 | bool aodbm_data_eq(aodbm_data *a, aodbm_data *b) {
108 | if (a->sz != b->sz) {
109 | return false;
110 | }
111 | uint32_t i;
112 | for (i = 0; i < a->sz; ++i) {
113 | if (a->dat[i] != b->dat[i]) {
114 | return false;
115 | }
116 | }
117 | return true;
118 | }
119 |
120 | int aodbm_data_cmp(aodbm_data *a, aodbm_data *b) {
121 | if (aodbm_data_eq(a, b)) {
122 | return 0;
123 | }
124 | if (aodbm_data_lt(a, b)) {
125 | return -1;
126 | }
127 | return 1;
128 | }
129 |
130 | aodbm_data *aodbm_data_dup(aodbm_data *v) {
131 | return aodbm_construct_data(v->dat, v->sz);
132 | }
133 |
134 | void aodbm_free_data(aodbm_data *dat) {
135 | free(dat->dat);
136 | free(dat);
137 | }
138 |
--------------------------------------------------------------------------------
/aodbm_rope.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 |
23 | #include "aodbm.h"
24 | #include "aodbm_data.h"
25 | #include "aodbm_rope.h"
26 |
27 | struct aodbm_rope_node {
28 | aodbm_data *dat;
29 | struct aodbm_rope_node *next;
30 | };
31 |
32 | typedef struct aodbm_rope_node aodbm_rope_node;
33 |
34 | struct aodbm_rope {
35 | aodbm_rope_node *first;
36 | aodbm_rope_node *last;
37 | };
38 |
39 | aodbm_rope_node *aodbm_data_to_rope_node_di(aodbm_data *dat) {
40 | aodbm_rope_node *node = malloc(sizeof(aodbm_rope_node));
41 | node->dat = aodbm_data_dup(dat);
42 | node->next = NULL;
43 | return node;
44 | }
45 |
46 | aodbm_rope_node *aodbm_data_to_rope_node(aodbm_data *dat) {
47 | return aodbm_data_to_rope_node_di(aodbm_data_dup(dat));
48 | }
49 |
50 | aodbm_rope *aodbm_data_to_rope_di(aodbm_data *dat) {
51 | aodbm_rope *result = malloc(sizeof(aodbm_rope));
52 | aodbm_rope_node *node = aodbm_data_to_rope_node_di(dat);
53 | result->first = node;
54 | result->last = node;
55 | return result;
56 | }
57 |
58 | aodbm_rope *aodbm_data_to_rope(aodbm_data *dat) {
59 | return aodbm_data_to_rope_di(aodbm_data_dup(dat));
60 | }
61 |
62 | aodbm_rope *aodbm_rope_empty() {
63 | return aodbm_data_to_rope_di(aodbm_data_empty());
64 | }
65 |
66 | size_t aodbm_rope_size(aodbm_rope *rope) {
67 | aodbm_rope_node *it;
68 | size_t sz = 0;
69 | for (it = rope->first; it != NULL; it = it->next) {
70 | sz += it->dat->sz;
71 | }
72 | return sz;
73 | }
74 |
75 | aodbm_data *aodbm_rope_to_data(aodbm_rope *rope) {
76 | size_t sz = aodbm_rope_size(rope);
77 |
78 | aodbm_data *result = malloc(sizeof(aodbm_data));
79 | result->dat = malloc(sz);
80 | result->sz = sz;
81 |
82 | size_t pos = 0;
83 | aodbm_rope_node *it;
84 | for (it = rope->first; it != NULL; it = it->next) {
85 | memcpy(&result->dat[pos], it->dat->dat, it->dat->sz);
86 | pos += it->dat->sz;
87 | }
88 |
89 | return result;
90 | }
91 |
92 | aodbm_data *aodbm_rope_to_data_di(aodbm_rope *rope) {
93 | aodbm_data *dat = aodbm_rope_to_data(rope);
94 | aodbm_free_rope(rope);
95 | return dat;
96 | }
97 |
98 | void aodbm_free_rope(aodbm_rope *rope) {
99 | aodbm_rope_node *it;
100 | for (it = rope->first; it != NULL;) {
101 | aodbm_free_data(it->dat);
102 | aodbm_rope_node *next = it->next;
103 | free(it);
104 | it = next;
105 | }
106 | free(rope);
107 | }
108 |
109 | void aodbm_rope_append_di(aodbm_rope *rope, aodbm_data *dat) {
110 | aodbm_rope_node *node = aodbm_data_to_rope_node_di(dat);
111 | rope->last->next = node;
112 | rope->last = node;
113 | }
114 |
115 | void aodbm_rope_prepend_di(aodbm_data *dat, aodbm_rope *rope) {
116 | aodbm_rope_node *node = aodbm_data_to_rope_node_di(dat);
117 | node->next = rope->first;
118 | rope->first = node;
119 | }
120 |
121 | void aodbm_rope_append(aodbm_rope *rope, aodbm_data *dat) {
122 | aodbm_rope_append_di(rope, aodbm_data_dup(dat));
123 | }
124 |
125 | void aodbm_rope_prepend(aodbm_data *dat, aodbm_rope *rope) {
126 | aodbm_rope_prepend_di(aodbm_data_dup(dat), rope);
127 | }
128 |
129 | aodbm_rope *aodbm_rope_merge_di(aodbm_rope *a, aodbm_rope *b) {
130 | a->last->next = b->first;
131 | a->last = b->last;
132 | free(b);
133 | return a;
134 | }
135 |
136 | aodbm_rope *aodbm_data2_to_rope_di(aodbm_data *a, aodbm_data *b) {
137 | aodbm_rope *dat = aodbm_data_to_rope_di(a);
138 | aodbm_rope_append_di(dat, b);
139 | return dat;
140 | }
141 |
142 | aodbm_rope *aodbm_data2_to_rope(aodbm_data *a, aodbm_data *b) {
143 | return aodbm_data2_to_rope_di(aodbm_data_dup(a), aodbm_data_dup(b));
144 | }
145 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | aodbm - Append Only Database Manager
2 | ====================================
3 |
4 | An append only database manager in the style of dbm. It has both a C and a
5 | Python interface and is ACID compliant. Internally it uses a B+ Tree. (Being
6 | append only doesn't mean that you can't replace records or delete keys).
7 |
8 | Getting Started
9 | ===============
10 |
11 | $ make
12 |
13 | This will build a static and a shared library.
14 |
15 | Python interface
16 | ================
17 |
18 | # import the module
19 | >>> import aodbm
20 | # create a database object
21 | >>> db = aodbm.AODBM('testdb')
22 | # get the current version of the database
23 | >>> version = db.current_version()
24 | # versions updated either in place or by creating new versions
25 | # in place:
26 | >>> version['hello'] = 'world'
27 | >>> version['hello']
28 | "world"
29 | >>> list(version)
30 | [('hello', 'world')]
31 | >>> del version['hello']
32 | # new versions
33 | >>> new_version = version.set_record('hello', 'world')
34 | >>> new_version['hello']
35 | "world"
36 | >>> version['hello']
37 | Traceback (most recent call last):
38 | File "", line 1, in
39 | File "aodbm.py", line 56, in __getitem__
40 | raise KeyError()
41 | KeyError
42 | >>> newest_version = new_version.del_key('hello')
43 | # commiting a new version is simple
44 | >>> db.commit(new_version)
45 | # it returns whether the operation was successful
46 | True
47 | # the operation may fail if you try to commit a version that isn't based on the
48 | # the current version.
49 |
50 | C interface
51 | ===========
52 |
53 | You'll need to link against either the static or shared library and include the
54 | header file aodbm.h in order to use the C API.
55 |
56 | Before you can do anything, you will need a handle for a database. This is
57 | simple to acquire, simply call aodbm_open passing the filename as a NULL
58 | terminated string, the second argument is for flags. There are no flags at the
59 | moment so just pass 0. This will return an "aodbm *", when you are done with
60 | the handle then close the database using aodbm_close. These functions do not do
61 | any filelocking so ensure that only one handle exists for a given database file
62 | at any time.
63 |
64 | Once you have a handle, the next step is to obtain a reference to the most
65 | current version of the database. Versions are represented as "aodbm_version"s.
66 | Under the hood these are just "uint64_t"s, so don't worry about freeing them.
67 | The most current version can be found using aodbm_current.
68 |
69 | By explicitly dealing with versions of the database, you can be sure that other
70 | threads will not interfere during database operations.
71 |
72 | There are four database operations: get, set, delete and has. They appear in
73 | the respective functions aodbm_get, aodbm_get, aodbm_del and aodbm_has. Each
74 | deals with "aodbm_data *"s. The aodbm_data structure represents a piece of data
75 | and is defined like so:
76 |
77 | struct aodbm_data {
78 | char *dat;
79 | size_t sz;
80 | };
81 |
82 | Each of the operations' function's first three arguments are the database
83 | handle, the version of the database on which to operate on and the key to which
84 | the operation relates to. aodbm_get return a "aodbm_data *" which is populated
85 | with the value at the key or NULL if the record doesn't exist. When you have
86 | finished using the value from this operation, you should free it with
87 | aodbm_free_data. aodbm_set takes one extra argument, the value to store at the
88 | given key. aodbm_set and aodbm_del both return the new version of the database
89 | that you have created.
90 |
91 | The aodbm_data objects that you provide are not modified in any way.
92 |
93 | Iteration is also possible. First you must create an iterator using
94 | aodbm_new_iterator, passing in the database handle and the version to iterate
95 | over. Then call aodbm_iterator_next, passing in the database handle and the
96 | iterator. This call is not thread-safe. It returns an aodbm_record that will be
97 | filled with data (a key and a value) that you should free using aodbm_free_data
98 | when you are finished using them. The key and value will be set to NULL when
99 | the end of the database is reached. When you are finished using an iterator,
100 | whether you have reached the end of the database or not, you should free the
101 | iterator with aodbm_free_iterator. The records will be given in the order they
102 | are stored in. The less than operator is defined like so:
103 |
104 | Given 2 keys, a and b.
105 | if a is shorter than b return true,
106 | if b is shorter than a return false,
107 | return the lexicographic ordering
108 |
109 | Having modified the database, you will likely want to commit the changes.
110 | Commiting the changes means that when future requests for the current version
111 | are made, your new version of the database will be returned. To commit your
112 | changes, pass your new version as the second argument to aodbm_commit. This
113 | will return a boolean value which indicates whether the commit was successful.
114 | A commit will fail if you try to commit a version that is not based on the
115 | current latest version.
116 |
117 | This only leaves two functions that haven't been covered in the public API.
118 | aodbm_is_based_on and aodbm_previous_version. They both do exactly what you
119 | think they'd do. aodbm_is_based_on takes two arguments in addition to the
120 | database handle and they are both aodbm_versions. It returns whether the first
121 | is based on the second.
122 |
123 | Documentation
124 | =============
125 |
126 | You can find more information at https://sourceforge.net/apps/mediawiki/aodbm
127 |
128 | Current Progress
129 | ================
130 |
131 | It is not yet suitable for production usage. There are a few known bugs in the
132 | delete function and I'm going to be refactoring much of the code. I consider it
133 | to be of (early) beta quality.
134 |
135 | The goal of the project is to write a storage backend for a future DBMS. It
136 | should therefore be:
137 |
138 | * Fast,
139 | * ACID compliant,
140 | * As simple as possible.
141 |
142 | Reporting Bugs
143 | ==============
144 |
145 | If you find a bug then please write a unit test (in Python if possible) that
146 | fails and send it to me (Daniel) at Da.Waterworth@gmail.com .
147 |
148 | Thanks
149 |
--------------------------------------------------------------------------------
/aodbm_list.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "aodbm_list.h"
21 | #include "aodbm_error.h"
22 |
23 | #include "stdlib.h"
24 |
25 | struct list_node {
26 | struct list_node *next, *prev;
27 | void *item;
28 | };
29 |
30 | typedef struct list_node list_node;
31 |
32 | struct aodbm_list {
33 | list_node *head;
34 | list_node *tail;
35 | size_t len;
36 | };
37 |
38 | struct aodbm_list_iterator {
39 | list_node *cur;
40 | aodbm_list *list;
41 | };
42 |
43 | static list_node *create_list_node(void *item) {
44 | list_node *node = malloc(sizeof(list_node));
45 | node->item = item;
46 | return node;
47 | }
48 |
49 | aodbm_list *aodbm_list_empty() {
50 | aodbm_list *list = malloc(sizeof(aodbm_list));
51 | list->head = NULL;
52 | list->tail = NULL;
53 | list->len = 0;
54 | return list;
55 | }
56 |
57 | void aodbm_free_list(aodbm_list *list) {
58 | while(!aodbm_list_is_empty(list)) {
59 | void *item = aodbm_list_pop_back(list);
60 | if (item != NULL) {
61 | free(item);
62 | }
63 | }
64 | free(list);
65 | }
66 |
67 | void aodbm_list_push_front(aodbm_list *list, void *item) {
68 | list_node *node = create_list_node(item);
69 | if (list->head == NULL) {
70 | node->next = NULL;
71 | node->prev = NULL;
72 | list->head = node;
73 | list->tail = node;
74 | } else {
75 | list->head->prev = node;
76 | node->next = list->head;
77 | node->prev = NULL;
78 | list->head = node;
79 | }
80 | list->len += 1;
81 | }
82 |
83 | void aodbm_list_push_back(aodbm_list *list, void *item) {
84 | list_node *node = create_list_node(item);
85 | if (list->head == NULL) {
86 | node->next = NULL;
87 | node->prev = NULL;
88 | list->head = node;
89 | list->tail = node;
90 | } else {
91 | list->tail->next = node;
92 | node->prev = list->tail;
93 | node->next = NULL;
94 | list->tail = node;
95 | }
96 | list->len += 1;
97 | }
98 |
99 | void *aodbm_list_pop_front(aodbm_list *list) {
100 | list_node *head = list->head;
101 | if (head == NULL) {
102 | return NULL;
103 | }
104 | void *out = head->item;
105 | list->head = head->next;
106 | if (list->head != NULL) {
107 | list->head->prev = NULL;
108 | } else {
109 | list->tail = NULL;
110 | }
111 | free(head);
112 | list->len -= 1;
113 | return out;
114 | }
115 |
116 | void *aodbm_list_pop_back(aodbm_list *list) {
117 | list_node *tail = list->tail;
118 | if (tail == NULL) {
119 | return NULL;
120 | }
121 | void *out = tail->item;
122 | list->tail = tail->prev;
123 | if (list->tail != NULL) {
124 | list->tail->next = NULL;
125 | } else {
126 | list->head = NULL;
127 | }
128 | free(tail);
129 | list->len -= 1;
130 | return out;
131 | }
132 |
133 | bool aodbm_list_is_empty(aodbm_list *list) {
134 | return list->head == NULL;
135 | }
136 |
137 | size_t aodbm_list_length(aodbm_list *list) {
138 | return list->len;
139 | }
140 |
141 | aodbm_list *aodbm_list_merge_di(aodbm_list *a, aodbm_list *b) {
142 | if (a->tail != NULL) {
143 | a->tail->next = b->head;
144 | }
145 | if (b->head != NULL) {
146 | b->head->prev = a->tail;
147 | }
148 | if (a->head == NULL) {
149 | a->head = b->head;
150 | }
151 | if (b->tail != NULL) {
152 | a->tail = b->tail;
153 | }
154 | a->len += b->len;
155 | free(b);
156 | return a;
157 | }
158 |
159 | aodbm_list_iterator *aodbm_list_begin(aodbm_list *list) {
160 | aodbm_list_iterator *it = malloc(sizeof(aodbm_list_iterator));
161 |
162 | it->list = list;
163 | it->cur = list->head;
164 |
165 | return it;
166 | }
167 |
168 | aodbm_list_iterator *aodbm_list_back(aodbm_list *list) {
169 | aodbm_list_iterator *it = malloc(sizeof(aodbm_list_iterator));
170 |
171 | it->list = list;
172 | it->cur = list->tail;
173 |
174 | return it;
175 | }
176 |
177 | void aodbm_list_iterator_next(aodbm_list_iterator *it) {
178 | if (it->cur == NULL) {
179 | return;
180 | }
181 | it->cur = it->cur->next;
182 | }
183 |
184 | void aodbm_list_iterator_prev(aodbm_list_iterator *it) {
185 | if (it->cur == NULL) {
186 | return;
187 | }
188 | it->cur = it->cur->prev;
189 | }
190 |
191 | bool aodbm_list_iterator_is_begin(aodbm_list_iterator *it) {
192 | return it->cur == it->list->head;
193 | }
194 |
195 | bool aodbm_list_iterator_is_end(aodbm_list_iterator *it) {
196 | return it->cur == it->list->tail;
197 | }
198 |
199 | bool aodbm_list_iterator_is_finished(aodbm_list_iterator *it) {
200 | return it->cur == NULL;
201 | }
202 |
203 | void *aodbm_list_iterator_get(aodbm_list_iterator *it) {
204 | return it->cur->item;
205 | }
206 |
207 | void aodbm_list_insert(aodbm_list_iterator *it, void *item) {
208 | list_node *node = create_list_node(item);
209 | if (it->cur != NULL) {
210 | list_node *next = it->cur->next;
211 | list_node *prev = it->cur;
212 | if (next != NULL) {
213 | next->prev = node;
214 | }
215 | node->next = next;
216 | node->prev = prev;
217 | prev->next = node;
218 | } else {
219 | if (it->list->head != NULL) {
220 | AODBM_CUSTOM_ERROR("unknown location");
221 | } else {
222 | it->list->head = node;
223 | it->list->tail = node;
224 | node->next = NULL;
225 | node->prev = NULL;
226 | }
227 | }
228 | it->list->len += 1;
229 | }
230 |
231 | void aodbm_list_remove(aodbm_list_iterator *it) {
232 | if (it->cur != NULL) {
233 | list_node *next = it->cur->next;
234 | list_node *prev = it->cur->prev;
235 | if (prev != NULL) {
236 | prev->next = next;
237 | } else {
238 | it->list->head = next;
239 | }
240 | if (next != NULL) {
241 | next->prev = prev;
242 | } else {
243 | it->list->tail = prev;
244 | }
245 | free(it->cur);
246 | if (next != NULL) {
247 | it->cur = next;
248 | } else {
249 | it->cur = prev;
250 | }
251 | it->list->len -= 1;
252 | }
253 | }
254 |
255 | void aodbm_free_list_iterator(aodbm_list_iterator *it) {
256 | free(it);
257 | }
258 |
--------------------------------------------------------------------------------
/aodbm.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | '''
19 |
20 | import ctypes
21 |
22 | class Data(ctypes.Structure):
23 | _fields_ = [("dat", ctypes.c_char_p),
24 | ("sz", ctypes.c_size_t)]
25 |
26 | data_ptr = ctypes.POINTER(Data)
27 |
28 | class Record(ctypes.Structure):
29 | _fields_ = [("key", data_ptr),
30 | ("val", data_ptr)]
31 |
32 | def str_to_data(st):
33 | return Data(st, len(st))
34 |
35 | def data_to_str(dat):
36 | return ctypes.string_at(dat.dat, dat.sz)
37 |
38 | aodbm_lib = ctypes.CDLL("./libaodbm.so")
39 |
40 | aodbm_lib.aodbm_open.argtypes = [ctypes.c_char_p, ctypes.c_int]
41 | aodbm_lib.aodbm_open.restype = ctypes.c_void_p
42 |
43 | aodbm_lib.aodbm_close.argtypes = [ctypes.c_void_p]
44 | aodbm_lib.aodbm_close.restype = None
45 |
46 | aodbm_lib.aodbm_current.argtypes = [ctypes.c_void_p]
47 | aodbm_lib.aodbm_current.restype = ctypes.c_uint64
48 |
49 | aodbm_lib.aodbm_commit.argtypes = [ctypes.c_void_p, ctypes.c_uint64]
50 | aodbm_lib.aodbm_commit.restype = ctypes.c_bool
51 |
52 | aodbm_lib.aodbm_has.argtypes = [ctypes.c_void_p, ctypes.c_uint64, data_ptr]
53 | aodbm_lib.aodbm_has.restype = ctypes.c_bool
54 |
55 | aodbm_lib.aodbm_get.argtypes = [ctypes.c_void_p, ctypes.c_uint64, data_ptr]
56 | aodbm_lib.aodbm_get.restype = data_ptr
57 |
58 | aodbm_lib.aodbm_set.argtypes = [ctypes.c_void_p, ctypes.c_uint64, data_ptr, data_ptr]
59 | aodbm_lib.aodbm_set.restype = ctypes.c_uint64
60 |
61 | aodbm_lib.aodbm_del.argtypes = [ctypes.c_void_p, ctypes.c_uint64, data_ptr]
62 | aodbm_lib.aodbm_del.restype = ctypes.c_uint64
63 |
64 | aodbm_lib.aodbm_is_based_on.argtypes = [ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64]
65 | aodbm_lib.aodbm_is_based_on.restype = ctypes.c_bool
66 |
67 | aodbm_lib.aodbm_previous_version.argtypes = [ctypes.c_void_p, ctypes.c_uint64]
68 | aodbm_lib.aodbm_previous_version.restype = ctypes.c_uint64
69 |
70 | aodbm_lib.aodbm_new_iterator.argtypes = [ctypes.c_void_p, ctypes.c_uint64]
71 | aodbm_lib.aodbm_new_iterator.restype = ctypes.c_void_p
72 |
73 | aodbm_lib.aodbm_iterate_from.argtypes = [ctypes.c_void_p, ctypes.c_uint64, data_ptr]
74 | aodbm_lib.aodbm_iterate_from.restype = ctypes.c_void_p
75 |
76 | aodbm_lib.aodbm_iterator_goto.argtypes = [ctypes.c_void_p, ctypes.c_void_p, data_ptr]
77 | aodbm_lib.aodbm_iterator_goto.restype = None
78 |
79 | aodbm_lib.aodbm_iterator_next.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
80 | aodbm_lib.aodbm_iterator_next.restype = Record
81 |
82 | aodbm_lib.aodbm_free_iterator.argtypes = [ctypes.c_void_p]
83 | aodbm_lib.aodbm_free_iterator.restype = None
84 |
85 | aodbm_lib.aodbm_free_data.argtypes = [ctypes.c_void_p]
86 | aodbm_lib.aodbm_free_data.restype = None
87 |
88 | class VersionIterator(object):
89 | def __init__(self, version, it=None):
90 | self.version = version
91 | if it:
92 | self.it = it
93 | else:
94 | self.it = aodbm_lib.aodbm_new_iterator(version.db.db, version.version)
95 |
96 | def __del__(self):
97 | aodbm_lib.aodbm_free_iterator(self.it)
98 |
99 | def __iter__(self):
100 | return self
101 |
102 | def next(self):
103 | rec = aodbm_lib.aodbm_iterator_next(self.version.db.db, self.it)
104 | if rec.key:
105 | key = data_to_str(rec.key.contents)
106 | val = data_to_str(rec.val.contents)
107 | aodbm_lib.aodbm_free_data(rec.key)
108 | aodbm_lib.aodbm_free_data(rec.val)
109 | return key, val
110 | raise StopIteration()
111 |
112 | def goto(self, key):
113 | self.it = aodbm_lib.aodbm_iterator_goto(self.version.db.db, self.it, str_to_data(key))
114 |
115 | class Version(object):
116 | '''Represents a version of the database'''
117 | def __init__(self, db, version):
118 | '''Don't use this method directly'''
119 | self.db = db
120 | self.version = version
121 |
122 | def has(self, key):
123 | '''Doesn't this version have key?'''
124 | return aodbm_lib.aodbm_has(self.db.db, self.version, str_to_data(key))
125 |
126 | def __getitem__(self, key):
127 | '''Queries the version for a key'''
128 | ptr = aodbm_lib.aodbm_get(self.db.db, self.version, str_to_data(key))
129 | if ptr:
130 | out = data_to_str(ptr.contents)
131 | aodbm_lib.aodbm_free_data(ptr)
132 | return out
133 | raise KeyError()
134 |
135 | def __setitem__(self, key, val):
136 | '''Set a record, changing the version in place'''
137 | key = str_to_data(key)
138 | val = str_to_data(val)
139 | self.version = aodbm_lib.aodbm_set(self.db.db, self.version, key, val)
140 |
141 | def __delitem__(self, key):
142 | '''Delete a key, changing the version in place'''
143 | key = str_to_data(key)
144 | self.version = aodbm_lib.aodbm_del(self.db.db, self.version, key)
145 |
146 | def del_key(self, key):
147 | '''Delete a key, returning the new database version object'''
148 | key = str_to_data(key)
149 | return Version(self.db, aodbm_lib.aodbm_del(self.db.db, self.version, key))
150 |
151 | def set_record(self, key, val):
152 | '''Set a record, returning the new database version object'''
153 | key = str_to_data(key)
154 | val = str_to_data(val)
155 | return Version(self.db, aodbm_lib.aodbm_set(self.db.db, self.version, key, val))
156 |
157 | def previous(self):
158 | '''Get the previous version object'''
159 | return Version(self.db, aodbm_lib.aodbm_previous_version(self.db.db, self.version))
160 |
161 | def is_based_on(self, other):
162 | '''Is this object based on other?'''
163 | assert self.db == other.db
164 | return aodbm_lib.aodbm_is_based_on(self.db.db, self.version, other.version)
165 |
166 | def __iter__(self):
167 | return VersionIterator(self)
168 |
169 | def iterate_from(self, key):
170 | return VersionIterator(self, aodbm_lib.aodbm_iterate_from(self.db.db, self.version, str_to_data(key)))
171 |
172 | class AODBM(object):
173 | '''Represents a Database'''
174 | def __init__(self, filename, flags=0):
175 | '''Open a new database'''
176 | self.db = aodbm_lib.aodbm_open(filename, flags)
177 |
178 | def __del__(self):
179 | aodbm_lib.aodbm_close(self.db)
180 |
181 | def current_version(self):
182 | '''Get the current version object'''
183 | return Version(self, aodbm_lib.aodbm_current(self.db))
184 |
185 | def commit(self, version):
186 | '''Commits the version object to the database.'''
187 | assert self == version.db
188 | return aodbm_lib.aodbm_commit(self.db, version.version)
189 |
--------------------------------------------------------------------------------
/COPYING.lesser:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/aodbm_internal.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | #include "stdio.h"
21 | #include "stdlib.h"
22 | #include "assert.h"
23 | #include "string.h"
24 |
25 | #include "pthread.h"
26 |
27 | #include "aodbm_internal.h"
28 | #include "aodbm_error.h"
29 |
30 | #include
31 |
32 | #define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) |\
33 | ntohl( ((uint32_t)(x >> 32)) ) )
34 | #define htonll(x) ntohll(x)
35 |
36 | #ifdef AODBM_USE_MMAP
37 | #include
38 | #include
39 | #endif
40 |
41 | void print_hex(unsigned char c) {
42 | printf("\\x%.2x", c);
43 | }
44 |
45 | /* python style string printing */
46 | void aodbm_print_data(aodbm_data *dat) {
47 | size_t i;
48 | for (i = 0; i < dat->sz; ++i) {
49 | char c = dat->dat[i];
50 | if (c == '\n') {
51 | printf("\\n");
52 | } else if (c >= 127 || c < 32) {
53 | print_hex(c);
54 | } else {
55 | putchar(c);
56 | }
57 | }
58 | }
59 |
60 | void annotate_data(const char *name, aodbm_data *val) {
61 | printf("%s: ", name);
62 | aodbm_print_data(val);
63 | putchar('\n');
64 | }
65 |
66 | void aodbm_print_rope(aodbm_rope *rope) {
67 | aodbm_data *dat = aodbm_rope_to_data(rope);
68 | aodbm_print_data(dat);
69 | aodbm_free_data(dat);
70 | }
71 |
72 | void annotate_rope(const char *name, aodbm_rope *val) {
73 | printf("%s: ", name);
74 | aodbm_print_rope(val);
75 | putchar('\n');
76 | }
77 |
78 | /*
79 | data format:
80 | v - v + 8 = prev version
81 | v + 8 = root node
82 | node - node + 1 = type (leaf of branch)
83 | node + 1 - node + 5 = node size
84 | branch:
85 | node + 5 ... = offset (key, offset)+
86 | leaf:
87 | node + 5 ... = (key, val)+
88 | */
89 |
90 | aodbm_rope *make_block(aodbm_data *dat) {
91 | aodbm_rope *result = aodbm_data_to_rope_di(aodbm_data_from_32(dat->sz));
92 | aodbm_rope_append(result, dat);
93 | return result;
94 | }
95 |
96 | aodbm_rope *make_block_di(aodbm_data *dat) {
97 | return aodbm_data2_to_rope_di(aodbm_data_from_32(dat->sz), dat);
98 | }
99 |
100 | aodbm_rope *make_record(aodbm_data *key, aodbm_data *val) {
101 | return aodbm_rope_merge_di(make_block(key), make_block(val));
102 | }
103 |
104 | aodbm_rope *make_record_di(aodbm_data *key, aodbm_data *val) {
105 | return aodbm_rope_merge_di(make_block_di(key), make_block_di(val));
106 | }
107 |
108 | bool aodbm_read_bytes(aodbm *db, void *ptr, size_t sz) {
109 | if (fread(ptr, 1, sz, db->fd) != sz) {
110 | if (feof(db->fd)) {
111 | return false;
112 | }
113 | AODBM_OS_ERROR();
114 | }
115 | return true;
116 | }
117 |
118 | void aodbm_seek(aodbm *db, int64_t off, int startpoint) {
119 | if (fseeko(db->fd, off, startpoint) != 0) {
120 | AODBM_OS_ERROR();
121 | }
122 | }
123 |
124 | uint64_t aodbm_tell(aodbm *db) {
125 | return ftello(db->fd);
126 | }
127 |
128 | void aodbm_write_bytes(aodbm *db, void *ptr, size_t sz) {
129 | if (fwrite(ptr, 1, sz, db->fd) != sz) {
130 | AODBM_OS_ERROR();
131 | }
132 | db->file_size += sz;
133 | }
134 |
135 | void aodbm_truncate(aodbm *db, uint64_t sz) {
136 | if (ftruncate(fileno(db->fd), sz) != 0) {
137 | AODBM_OS_ERROR();
138 | }
139 | db->file_size = sz;
140 | }
141 |
142 | void aodbm_write_data_block(aodbm *db, aodbm_data *data) {
143 | pthread_mutex_lock(&db->rw);
144 | aodbm_write_bytes(db, "d", 1);
145 | /* ensure size fits in 32bits */
146 | uint32_t sz = htonl(data->sz);
147 | aodbm_write_bytes(db, &sz, 4);
148 | aodbm_write_bytes(db, data->dat, data->sz);
149 | pthread_mutex_unlock(&db->rw);
150 | }
151 |
152 | void aodbm_write_version(aodbm *db, uint64_t ver) {
153 | pthread_mutex_lock(&db->rw);
154 | aodbm_write_bytes(db, "v", 1);
155 | uint64_t off = htonll(ver);
156 | aodbm_write_bytes(db, &off, 8);
157 | fflush(db->fd);
158 | pthread_mutex_unlock(&db->rw);
159 | }
160 |
161 | void aodbm_read(aodbm *db, uint64_t off, size_t sz, void *ptr) {
162 | #ifdef AODBM_USE_MMAP
163 | aodbm_rwlock_rdlock(&db->mmap_mut);
164 |
165 | if (db->mapping_size < off + (uint64_t)sz) {
166 | long page_size = sysconf(_SC_PAGE_SIZE);
167 | size_t new_size = db->file_size - (db->file_size % page_size);
168 |
169 | if (new_size < off + (uint64_t)sz) {
170 | aodbm_rwlock_unlock(&db->mmap_mut);
171 |
172 | pthread_mutex_lock(&db->rw);
173 | aodbm_seek(db, off, SEEK_SET);
174 | aodbm_read_bytes(db, ptr, sz);
175 | pthread_mutex_unlock(&db->rw);
176 | return;
177 | }
178 |
179 | aodbm_rwlock_unlock(&db->mmap_mut);
180 | aodbm_rwlock_wrlock(&db->mmap_mut);
181 | if (db->mapping == NULL) {
182 | db->mapping = mmap(NULL,
183 | new_size,
184 | PROT_READ,
185 | MAP_SHARED,
186 | fileno(db->fd),
187 | 0);
188 | if (db->mapping == MAP_FAILED) {
189 | AODBM_OS_ERROR();
190 | }
191 | db->mapping_size = new_size;
192 | } else {
193 | if (db->mapping_size < new_size) {
194 | db->mapping = mremap((void *)db->mapping,
195 | db->mapping_size,
196 | new_size,
197 | MREMAP_MAYMOVE);
198 | if (db->mapping == MAP_FAILED) {
199 | AODBM_OS_ERROR();
200 | }
201 | db->mapping_size = new_size;
202 | }
203 | }
204 | aodbm_rwlock_unlock(&db->mmap_mut);
205 | aodbm_rwlock_rdlock(&db->mmap_mut);
206 | }
207 |
208 | memcpy(ptr, (void *)db->mapping + (size_t)off, sz);
209 | aodbm_rwlock_unlock(&db->mmap_mut);
210 | #else
211 | pthread_mutex_lock(&db->rw);
212 | aodbm_seek(db, off, SEEK_SET);
213 | aodbm_read_bytes(db, ptr, sz);
214 | pthread_mutex_unlock(&db->rw);
215 | #endif
216 | }
217 |
218 | uint32_t aodbm_read32(aodbm *db, uint64_t off) {
219 | uint32_t sz;
220 | aodbm_read(db, off, 4, &sz);
221 | return ntohl(sz);
222 | }
223 |
224 | uint64_t aodbm_read64(aodbm *db, uint64_t off) {
225 | uint64_t sz;
226 | aodbm_read(db, off, 8, &sz);
227 | return ntohll(sz);
228 | }
229 |
230 | aodbm_data *aodbm_read_data(aodbm *db, uint64_t off) {
231 | uint32_t sz = aodbm_read32(db, off);
232 | aodbm_data *out = malloc(sizeof(aodbm_data));
233 | out->sz = sz;
234 | out->dat = malloc(sz);
235 | aodbm_read(db, off+4, sz, out->dat);
236 | return out;
237 | }
238 |
239 | uint64_t aodbm_search_recursive(aodbm *db, uint64_t node, aodbm_data *key) {
240 | char type;
241 | aodbm_read(db, node, 1, &type);
242 | if (type == 'l') {
243 | return node;
244 | }
245 | if (type == 'b') {
246 | uint32_t sz = aodbm_read32(db, node + 1);
247 | uint64_t pos = node + 5;
248 | /* node begins with an offset */
249 | uint64_t off = aodbm_read64(db, pos);
250 | pos += 8;
251 | uint32_t i;
252 | for (i = 0; i < sz; ++i) {
253 | aodbm_data *dat = aodbm_read_data(db, pos);
254 | pos += dat->sz + 4;
255 | bool lt = aodbm_data_lt(key, dat);
256 | aodbm_free_data(dat);
257 | if (lt) {
258 | return aodbm_search_recursive(db, off, key);
259 | }
260 | off = aodbm_read64(db, pos);
261 | pos += 8;
262 | }
263 | return aodbm_search_recursive(db, off, key);
264 | } else {
265 | AODBM_CUSTOM_ERROR("unknown node type");
266 | }
267 | }
268 |
269 | /* returns the offset of the leaf node that the key belongs in */
270 | uint64_t aodbm_search(aodbm *db, aodbm_version version, aodbm_data *key) {
271 | if (version == 0) {
272 | AODBM_CUSTOM_ERROR("error, given the 0 version for a search");
273 | }
274 | return aodbm_search_recursive(db, version + 8, key);
275 | }
276 |
277 | void aodbm_search_path_recursive(aodbm *db,
278 | uint64_t node,
279 | aodbm_data *node_key,
280 | aodbm_data *key,
281 | aodbm_stack **path) {
282 | assert (aodbm_data_le(node_key, key));
283 | aodbm_path_node *path_node = malloc(sizeof(aodbm_path_node));
284 | path_node->key = node_key;
285 | path_node->node = node;
286 | aodbm_stack_push(path, (void *)path_node);
287 |
288 | char type;
289 | aodbm_read(db, node, 1, &type);
290 | if (type == 'l') {
291 | return;
292 | }
293 | if (type == 'b') {
294 | aodbm_data *prev_key = aodbm_data_dup(node_key);
295 | uint32_t sz = aodbm_read32(db, node + 1);
296 | uint64_t pos = node + 5;
297 | /* node begins with an offset */
298 | uint64_t off = aodbm_read64(db, pos);
299 | pos += 8;
300 | uint32_t i;
301 | aodbm_data *dat;
302 | for (i = 0; i < sz; ++i) {
303 | dat = aodbm_read_data(db, pos);
304 | pos += dat->sz + 4;
305 | if (aodbm_data_lt(key, dat)) {
306 | aodbm_free_data(dat);
307 | aodbm_search_path_recursive(db, off, prev_key, key, path);
308 | return;
309 | }
310 | aodbm_free_data(prev_key);
311 | prev_key = dat;
312 | off = aodbm_read64(db, pos);
313 | pos += 8;
314 | }
315 | aodbm_search_path_recursive(db, off, prev_key, key, path);
316 | return;
317 | } else {
318 | AODBM_CUSTOM_ERROR("unknown node type");
319 | }
320 | }
321 |
322 | aodbm_stack *aodbm_search_path(aodbm *db, aodbm_version ver, aodbm_data *key) {
323 | if (ver == 0) {
324 | AODBM_CUSTOM_ERROR("error, given the 0 version for a search");
325 | }
326 | aodbm_stack *path = NULL;
327 | aodbm_search_path_recursive(db, ver + 8, aodbm_data_empty(), key, &path);
328 | return path;
329 | }
330 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
--------------------------------------------------------------------------------
/aodbm.c:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (C) 2011 aodbm authors,
3 |
4 | This file is part of aodbm.
5 |
6 | aodbm is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | aodbm is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Lesser General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | /* IMPORTANT: this number must be even and >= 4
21 | a higher number means bigger files, longer writes, faster reads (to a point)
22 | */
23 | #define MAX_NODE_SIZE 4
24 |
25 | #include "string.h"
26 | #include "stdio.h"
27 | #include "stdlib.h"
28 | #include "pthread.h"
29 | #include "assert.h"
30 |
31 | #include
32 |
33 | #define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) |\
34 | ntohl( ((uint32_t)(x >> 32)) ) )
35 | #define htonll(x) ntohll(x)
36 |
37 | #ifdef AODBM_USE_MMAP
38 | #include
39 | #include
40 | #endif
41 |
42 | #include "aodbm.h"
43 | #include "aodbm_internal.h"
44 |
45 | #include "aodbm_error.h"
46 |
47 | uint64_t aodbm_file_size(aodbm *);
48 |
49 | aodbm *aodbm_open(const char *filename, int flags) {
50 | aodbm *ptr = malloc(sizeof(aodbm));
51 | ptr->file_size = 0;
52 | ptr->fd = fopen(filename, "a+b");
53 | if (ptr->fd == NULL) {
54 | AODBM_CUSTOM_ERROR("couldn't open file");
55 | }
56 |
57 | pthread_mutexattr_t rec;
58 | pthread_mutexattr_init(&rec);
59 | pthread_mutexattr_settype(&rec, PTHREAD_MUTEX_RECURSIVE);
60 |
61 | pthread_mutex_init(&ptr->rw, &rec);
62 | pthread_mutex_init(&ptr->version, NULL);
63 |
64 | pthread_mutexattr_destroy(&rec);
65 |
66 | aodbm_seek(ptr, 0, SEEK_END);
67 | uint64_t actual_size = aodbm_tell(ptr);
68 |
69 | aodbm_seek(ptr, 0, SEEK_SET);
70 | ptr->cur = 0;
71 | while(1) {
72 | char type;
73 | uint64_t block_begin = ptr->file_size;
74 | if (!aodbm_read_bytes(ptr, &type, 1)) {
75 | break;
76 | }
77 | ptr->file_size += 1;
78 | if (type == 'v') {
79 | /* update version */
80 | uint64_t ver;
81 | if (!aodbm_read_bytes(ptr, &ver, 8)) {
82 | aodbm_truncate(ptr, block_begin);
83 | break;
84 | }
85 | ptr->cur = ntohll(ver);
86 | ptr->file_size += 8;
87 | } else if (type == 'd') {
88 | /* traverse data */
89 | uint32_t sz;
90 | if (!aodbm_read_bytes(ptr, &sz, 4)) {
91 | aodbm_truncate(ptr, block_begin);
92 | break;
93 | }
94 | ptr->file_size += 4;
95 | sz = ntohl(sz);
96 | if (ptr->file_size + sz > actual_size) {
97 | aodbm_truncate(ptr, block_begin);
98 | break;
99 | }
100 | aodbm_seek(ptr, sz, SEEK_CUR);
101 | ptr->file_size += sz;
102 | } else {
103 | AODBM_CUSTOM_ERROR("error, unknown block type");
104 | }
105 | }
106 |
107 | #ifdef AODBM_USE_MMAP
108 | aodbm_rwlock_init(&ptr->mmap_mut);
109 | /* create mapping */
110 | long page_size = sysconf(_SC_PAGE_SIZE);
111 |
112 | size_t sz = ptr->file_size - (ptr->file_size % page_size);
113 | if (sz != 0) {
114 | ptr->mapping = mmap(NULL, sz, PROT_READ, MAP_SHARED, fileno(ptr->fd), 0);
115 | if (ptr->mapping == MAP_FAILED) {
116 | AODBM_OS_ERROR();
117 | }
118 | ptr->mapping_size = sz;
119 | } else {
120 | ptr->mapping = NULL;
121 | ptr->mapping_size = 0;
122 | }
123 | #endif
124 |
125 | return ptr;
126 | }
127 |
128 | void aodbm_close(aodbm *db) {
129 | fclose(db->fd);
130 | pthread_mutex_destroy(&db->rw);
131 | pthread_mutex_destroy(&db->version);
132 | #ifdef AODBM_USE_MMAP
133 | aodbm_rwlock_destroy(&db->mmap_mut);
134 | munmap((void *)db->mapping, db->mapping_size);
135 | #endif
136 | free(db);
137 | }
138 |
139 | uint64_t aodbm_file_size(aodbm *db) {
140 | return db->file_size;
141 | }
142 |
143 | uint64_t aodbm_current(aodbm *db) {
144 | uint64_t result;
145 | pthread_mutex_lock(&db->version);
146 | result = db->cur;
147 | pthread_mutex_unlock(&db->version);
148 | return result;
149 | }
150 |
151 | bool aodbm_commit(aodbm *db, uint64_t version) {
152 | bool result;
153 | pthread_mutex_lock(&db->version);
154 | result = aodbm_is_based_on(db, version, db->cur);
155 | if (result) {
156 | /* write the new head */
157 | aodbm_write_version(db, version);
158 | db->cur = version;
159 | }
160 | pthread_mutex_unlock(&db->version);
161 | return result;
162 | }
163 |
164 | bool aodbm_commit_init(aodbm *db, uint64_t version) {
165 | pthread_mutex_lock(&db->version);
166 | return aodbm_is_based_on(db, version, db->cur);
167 | }
168 |
169 | void aodbm_commit_finish(aodbm *db, uint64_t version) {
170 | aodbm_write_version(db, version);
171 | db->cur = version;
172 | pthread_mutex_unlock(&db->version);
173 | }
174 |
175 | void aodbm_commit_abort(aodbm *db) {
176 | pthread_mutex_unlock(&db->version);
177 | }
178 |
179 | aodbm_rope *aodbm_branch_di(uint64_t a, aodbm_data *key, uint64_t b) {
180 | aodbm_rope *br = aodbm_data2_to_rope_di(aodbm_data_from_str("b"),
181 | aodbm_data_from_32(1));
182 | aodbm_rope_append_di(br, aodbm_data_from_64(a));
183 | br = aodbm_rope_merge_di(br, make_block_di(key));
184 | aodbm_rope_append_di(br, aodbm_data_from_64(b));
185 | return br;
186 | }
187 |
188 | aodbm_rope *aodbm_leaf_node(aodbm_data *key, aodbm_data *val) {
189 | aodbm_rope *node = aodbm_data2_to_rope_di(aodbm_data_from_str("l"),
190 | aodbm_data_from_32(1));
191 | return aodbm_rope_merge_di(node, make_record(key, val));
192 | }
193 |
194 | typedef struct {
195 | aodbm_rope *node;
196 | aodbm_data *key;
197 | uint64_t end_pos;
198 | uint32_t sz;
199 | bool inserted;
200 | } range_result;
201 |
202 | range_result add_header(range_result result) {
203 | aodbm_rope *header = aodbm_data2_to_rope_di(aodbm_data_from_str("l"),
204 | aodbm_data_from_32(result.sz));
205 | result.node = aodbm_rope_merge_di(header, result.node);
206 | return result;
207 | }
208 |
209 | range_result duplicate_leaf_range(aodbm *db,
210 | uint64_t start_pos,
211 | uint32_t num) {
212 | aodbm_rope *data = aodbm_rope_empty();
213 | aodbm_data *key1;
214 | uint64_t pos = start_pos;
215 | uint32_t i;
216 | for (i = 0; i < num; ++i) {
217 | aodbm_data *d_key = aodbm_read_data(db, pos);
218 | pos += d_key->sz + 4;
219 | aodbm_data *d_val = aodbm_read_data(db, pos);
220 | pos += d_val->sz + 4;
221 |
222 | if (i == 0) {
223 | key1 = aodbm_data_dup(d_key);
224 | }
225 | data = aodbm_rope_merge_di(data, make_record_di(d_key, d_val));
226 | }
227 |
228 | range_result result;
229 | result.node = data;
230 | result.key = key1;
231 | result.end_pos = pos;
232 | result.sz = num;
233 | result.inserted = false;
234 | return result;
235 | }
236 |
237 | range_result insert_into_leaf_range(aodbm *db,
238 | aodbm_data *key,
239 | aodbm_data *val,
240 | uint64_t start_pos,
241 | uint32_t num,
242 | bool insert_end) {
243 | bool inserted;
244 | aodbm_rope *data = aodbm_rope_empty();
245 | aodbm_data *key1 = NULL;
246 | aodbm_rope *i_rec = make_record(key, val);
247 | uint64_t pos = start_pos;
248 | uint32_t i;
249 | for (i = 0; i < num; ++i) {
250 | aodbm_data *d_key = aodbm_read_data(db, pos);
251 | pos += d_key->sz + 4;
252 | aodbm_data *d_val = aodbm_read_data(db, pos);
253 | pos += d_val->sz + 4;
254 |
255 | int cmp = aodbm_data_cmp(key, d_key);
256 | if (cmp == -1) {
257 | inserted = true;
258 | }
259 | if (cmp == 0) {
260 | inserted = false;
261 | }
262 | if (cmp != 1) {
263 | data = aodbm_rope_merge_di(data, i_rec);
264 | if (i == 0) {
265 | key1 = aodbm_data_dup(key);
266 | }
267 | }
268 | if (cmp != 0) {
269 | if (key1 == NULL && i == 0) {
270 | key1 = aodbm_data_dup(d_key);
271 | }
272 | data = aodbm_rope_merge_di(data, make_record_di(d_key, d_val));
273 | } else {
274 | aodbm_free_data(d_key);
275 | aodbm_free_data(d_val);
276 | }
277 | if (cmp != 1) {
278 | break;
279 | }
280 | }
281 | range_result result;
282 | result.key = key1;
283 | result.inserted = true;
284 | if (i < num) {
285 | /* the loop was broken */
286 | if (num - i != 1) {
287 | range_result dup = duplicate_leaf_range(db, pos, num - i - 1);
288 | aodbm_free_data(dup.key);
289 |
290 | result.node = aodbm_rope_merge_di(data, dup.node);
291 | result.end_pos = dup.end_pos;
292 | } else {
293 | result.node = data;
294 | result.end_pos = pos;
295 | }
296 | result.sz = num + (inserted?1:0);
297 | } else {
298 | if (insert_end) {
299 | result.node = aodbm_rope_merge_di(data, i_rec);
300 | result.sz = num + 1;
301 | } else {
302 | aodbm_free_rope(i_rec);
303 | result.node = data;
304 | result.inserted = false;
305 | result.sz = num;
306 | }
307 | result.end_pos = pos;
308 | }
309 | return result;
310 | }
311 |
312 | typedef struct {
313 | aodbm_rope *a_node;
314 | aodbm_data *a_key;
315 | aodbm_rope *b_node;
316 | aodbm_data *b_key;
317 | } modify_result;
318 |
319 | /* pos is positioned just after the type byte */
320 | modify_result insert_into_leaf(aodbm *db,
321 | aodbm_data *key,
322 | aodbm_data *val,
323 | uint64_t pos) {
324 | uint32_t sz = aodbm_read32(db, pos);
325 | pos += 4;
326 | if (sz == MAX_NODE_SIZE) {
327 | range_result a_range =
328 | add_header(
329 | insert_into_leaf_range(db, key, val, pos, MAX_NODE_SIZE/2, false));
330 | range_result b_range;
331 | if (a_range.inserted) {
332 | b_range =
333 | add_header(
334 | duplicate_leaf_range(db, a_range.end_pos, MAX_NODE_SIZE/2));
335 | } else {
336 | b_range = add_header(insert_into_leaf_range(db,
337 | key,
338 | val,
339 | a_range.end_pos,
340 | MAX_NODE_SIZE/2,
341 | true));
342 | }
343 | modify_result result;
344 | result.a_node = a_range.node;
345 | result.a_key = a_range.key;
346 | result.b_node = b_range.node;
347 | result.b_key = b_range.key;
348 | return result;
349 | } else if (sz == 0) {
350 | modify_result result;
351 | result.a_node = aodbm_leaf_node(key, val);
352 | result.a_key = aodbm_data_dup(key);
353 | result.b_node = NULL;
354 | result.b_key = NULL;
355 | return result;
356 | } else if (sz < MAX_NODE_SIZE) {
357 | range_result range =
358 | add_header(insert_into_leaf_range(db, key, val, pos, sz, true));
359 | modify_result result;
360 | result.a_node = range.node;
361 | result.a_key = range.key;
362 | result.b_node = NULL;
363 | result.b_key = NULL;
364 | return result;
365 | } else {
366 | AODBM_CUSTOM_ERROR("found a node with a size beyond MAX_NODE_SIZE");
367 | }
368 | }
369 |
370 | modify_result remove_from_leaf(aodbm *db,
371 | aodbm_data *key,
372 | uint64_t pos) {
373 | modify_result result;
374 | result.a_key = NULL;
375 | result.b_key = NULL;
376 | result.b_node = NULL;
377 | aodbm_rope *data = aodbm_rope_empty();
378 | uint32_t sz = aodbm_read32(db, pos);
379 | pos += 4;
380 |
381 | uint32_t i;
382 | bool removed = false;
383 | for (i = 0; i < sz; ++i) {
384 | aodbm_data *r_key = aodbm_read_data(db, pos);
385 | pos += 4 + r_key->sz;
386 | aodbm_data *r_val = aodbm_read_data(db, pos);
387 | pos += 4 + r_val->sz;
388 |
389 | if (!removed) {
390 | if (!aodbm_data_eq(r_key, key)) {
391 | if (result.a_key == NULL) {
392 | result.a_key = aodbm_data_dup(r_key);
393 | }
394 | data = aodbm_rope_merge_di(data, make_record_di(r_key, r_val));
395 | } else {
396 | removed = true;
397 | aodbm_free_data(r_key);
398 | aodbm_free_data(r_val);
399 | }
400 | } else {
401 | if (result.a_key == NULL) {
402 | result.a_key = aodbm_data_dup(r_key);
403 | }
404 | data = aodbm_rope_merge_di(data, make_record_di(r_key, r_val));
405 | }
406 | }
407 |
408 | aodbm_rope *header =
409 | aodbm_data2_to_rope_di(aodbm_data_from_str("l"),
410 | aodbm_data_from_32(sz - (removed?1:0)));
411 |
412 | result.a_node = aodbm_rope_merge_di(header, data);
413 | return result;
414 | }
415 |
416 | typedef struct {
417 | aodbm_rope *data;
418 | aodbm_data *key;
419 | uint32_t sz;
420 | } branch;
421 |
422 | void branch_init(branch *br) {
423 | br->data = NULL;
424 | br->key = NULL;
425 | br->sz = 0;
426 | }
427 |
428 | void add_to_branch_di(branch *node, aodbm_data *key, uint64_t off) {
429 | aodbm_data *d_off = aodbm_data_from_64(off);
430 | if (node->key == NULL) {
431 | node->key = key;
432 | node->data = aodbm_data_to_rope_di(d_off);
433 | } else {
434 | aodbm_rope *rec = make_block_di(key);
435 | aodbm_rope_append_di(rec, d_off);
436 | node->data = aodbm_rope_merge_di(node->data, rec);
437 | }
438 | node->sz += 1;
439 | }
440 |
441 | void add_to_branch(branch *node, aodbm_data *key, uint64_t off) {
442 | add_to_branch_di(node, aodbm_data_dup(key), off);
443 | }
444 |
445 | void add_to_branches_di(branch *a, branch *b, aodbm_data *key, uint64_t off) {
446 | if (a->sz < MAX_NODE_SIZE/2) {
447 | add_to_branch_di(a, key, off);
448 | } else {
449 | add_to_branch_di(b, key, off);
450 | }
451 | }
452 |
453 | void add_to_branches(branch *a, branch *b, aodbm_data *key, uint64_t off) {
454 | add_to_branches_di(a, b, aodbm_data_dup(key), off);
455 | }
456 |
457 | void merge_branches(branch *a, branch *b) {
458 | if (b->sz > 0) {
459 | a->sz += b->sz;
460 | a->data = aodbm_rope_merge_di(a->data, make_block_di(b->key));
461 | a->data = aodbm_rope_merge_di(a->data, b->data);
462 | b->sz = 0;
463 | }
464 | }
465 |
466 | aodbm_rope *branch_to_rope(branch *br) {
467 | aodbm_rope *header = aodbm_data2_to_rope_di(aodbm_data_from_str("b"),
468 | aodbm_data_from_32(br->sz - 1));
469 | return aodbm_rope_merge_di(header, br->data);
470 | }
471 |
472 | modify_result modify_branch(aodbm *db,
473 | uint64_t node,
474 | aodbm_data *node_key,
475 | uint64_t node_a,
476 | aodbm_data *a_key,
477 | uint64_t node_b,
478 | aodbm_data *b_key,
479 | uint64_t rm_a,
480 | uint64_t rm_b) {
481 | branch a, b;
482 | branch_init(&a);
483 | branch_init(&b);
484 |
485 | uint64_t pos = node + 1;
486 | uint32_t sz = aodbm_read32(db, pos);
487 | pos += 4;
488 |
489 | uint64_t off = aodbm_read64(db, pos);
490 | pos += 8;
491 |
492 | uint32_t i;
493 | bool a_placed = a_key == NULL;
494 | bool b_placed = b_key == NULL;
495 |
496 | if (off != rm_a && off != rm_b) {
497 | add_to_branches(&a, &b, node_key, off);
498 | }
499 |
500 | for (i = 0; i < sz; ++i) {
501 | aodbm_data *key = aodbm_read_data(db, pos);
502 | pos += 4 + key->sz;
503 | off = aodbm_read64(db, pos);
504 | pos += 8;
505 |
506 | if (!a_placed) {
507 | if (aodbm_data_lt(a_key, key)) {
508 | a_placed = true;
509 | add_to_branches(&a, &b, a_key, node_a);
510 | }
511 | if (!b_placed) {
512 | if (aodbm_data_lt(b_key, key)) {
513 | b_placed = true;
514 | add_to_branches(&a, &b, b_key, node_b);
515 | }
516 | }
517 | } else {
518 | if (!b_placed) {
519 | if (aodbm_data_lt(b_key, key)) {
520 | b_placed = true;
521 | add_to_branches(&a, &b, b_key, node_b);
522 | }
523 | }
524 | }
525 |
526 | if (off != rm_a && off != rm_b) {
527 | add_to_branches_di(&a, &b, key, off);
528 | } else {
529 | aodbm_free_data(key);
530 | }
531 | }
532 |
533 | if (!a_placed) {
534 | add_to_branches(&a, &b, a_key, node_a);
535 | }
536 | if (!b_placed) {
537 | add_to_branches(&a, &b, b_key, node_b);
538 | }
539 |
540 | modify_result result;
541 | if (b.sz < MAX_NODE_SIZE/2) {
542 | merge_branches(&a, &b);
543 | if (a.sz == 0) {
544 | result.a_node = NULL;
545 | result.a_key = NULL;
546 | result.b_node = NULL;
547 | result.b_key = NULL;
548 | } /*else if (a.sz == 1) {
549 | printf("error, special case 2\n");
550 | exit(1);
551 | } */ else {
552 | result.a_node = branch_to_rope(&a);
553 | result.a_key = a.key;
554 | result.b_node = NULL;
555 | result.b_key = NULL;
556 | }
557 | } else {
558 | result.a_node = branch_to_rope(&a);
559 | result.b_node = branch_to_rope(&b);
560 | result.a_key = a.key;
561 | result.b_key = b.key;
562 | }
563 | return result;
564 | }
565 |
566 | typedef struct {
567 | aodbm_data *dat;
568 | uint64_t root;
569 | } root_result;
570 |
571 | root_result construct_root_di(uint64_t prev,
572 | uint64_t append_pos,
573 | aodbm_rope *data,
574 | size_t data_sz,
575 | modify_result nodes) {
576 | root_result result;
577 | aodbm_data *root = aodbm_data_from_64(prev);
578 |
579 | if (nodes.a_key != NULL) {
580 | aodbm_free_data(nodes.a_key);
581 | }
582 | if (nodes.b_key == NULL) {
583 | if (nodes.a_key == NULL) {
584 | aodbm_rope_append_di(data, root);
585 | aodbm_rope_append_di(data, aodbm_data_from_str("l"));
586 | aodbm_rope_append_di(data, aodbm_data_from_32(0));
587 |
588 | result.root = append_pos + data_sz;
589 | } else {
590 | aodbm_rope_prepend_di(root, nodes.a_node);
591 | data = aodbm_rope_merge_di(data, nodes.a_node);
592 |
593 | result.root = data_sz + append_pos;
594 | }
595 | } else {
596 | uint64_t a_sz, b_sz;
597 | uint64_t a, b;
598 | a_sz = aodbm_rope_size(nodes.a_node);
599 | a = data_sz + append_pos;
600 | data = aodbm_rope_merge_di(data, nodes.a_node);
601 | data_sz += a_sz;
602 |
603 | b_sz = aodbm_rope_size(nodes.b_node);
604 | b = data_sz + append_pos;
605 | data = aodbm_rope_merge_di(data, nodes.b_node);
606 | data_sz += b_sz;
607 |
608 | /* create a new branch node */
609 | aodbm_rope *br = aodbm_branch_di(a, nodes.b_key, b);
610 |
611 | aodbm_rope_prepend_di(root, br);
612 |
613 | result.root = data_sz + append_pos;
614 |
615 | data = aodbm_rope_merge_di(data, br);
616 | }
617 |
618 | result.dat = aodbm_rope_to_data_di(data);
619 |
620 | return result;
621 | }
622 |
623 | aodbm_version aodbm_set(aodbm *db,
624 | aodbm_version ver,
625 | aodbm_data *key,
626 | aodbm_data *val) {
627 | /* it has to be locked to prevent the append_pos going astray */
628 | pthread_mutex_lock(&db->rw);
629 | /* find the position of the amendment (filesize + data block header) */
630 | uint64_t append_pos = aodbm_file_size(db) + 5;
631 | root_result result;
632 |
633 | if (ver == 0) {
634 | aodbm_rope *node = aodbm_leaf_node(key, val);
635 | aodbm_rope_prepend_di(aodbm_data_from_64(ver), node);
636 |
637 | result.dat = aodbm_rope_to_data_di(node);
638 | result.root = append_pos;
639 | } else {
640 | char type;
641 | aodbm_read(db, ver + 8, 1, &type);
642 | if (type == 'l') {
643 | modify_result leaf = insert_into_leaf(db, key, val, ver + 9);
644 | result = construct_root_di(ver,
645 | append_pos,
646 | aodbm_rope_empty(),
647 | 0,
648 | leaf);
649 | } else if (type = 'b') {
650 | aodbm_rope *data = aodbm_rope_empty();
651 | uint32_t data_sz = 0;
652 | aodbm_stack *path = aodbm_search_path(db, ver, key);
653 | /* pop the leaf node */
654 | aodbm_path_node *ptr = aodbm_stack_pop(&path);
655 | aodbm_path_node node = *ptr;
656 | free(ptr);
657 | modify_result nodes = insert_into_leaf(db, key, val, node.node + 1);
658 | uint64_t prev_node = node.node;
659 |
660 | uint64_t a, b;
661 |
662 | while (path != NULL) {
663 | ptr = aodbm_stack_pop(&path);
664 | node = *ptr;
665 | free(ptr);
666 |
667 | uint64_t a_sz, b_sz;
668 | a_sz = aodbm_rope_size(nodes.a_node);
669 | a = data_sz + append_pos;
670 | data = aodbm_rope_merge_di(data, nodes.a_node);
671 | data_sz += a_sz;
672 | if (nodes.b_node == NULL) {
673 | b = 0;
674 | } else {
675 | b_sz = aodbm_rope_size(nodes.b_node);
676 | b = data_sz + append_pos;
677 | data = aodbm_rope_merge_di(data, nodes.b_node);
678 | data_sz += b_sz;
679 | }
680 |
681 | nodes = modify_branch(db,
682 | node.node,
683 | node.key,
684 | a,
685 | nodes.a_key,
686 | b,
687 | nodes.b_key,
688 | prev_node,
689 | 0);
690 | aodbm_free_data(node.key);
691 |
692 | prev_node = node.node;
693 | }
694 |
695 | result = construct_root_di(ver, append_pos, data, data_sz, nodes);
696 | } else {
697 | AODBM_CUSTOM_ERROR("unknown node type");
698 | }
699 | }
700 |
701 | aodbm_write_data_block(db, result.dat);
702 | aodbm_free_data(result.dat);
703 |
704 | pthread_mutex_lock(&db->rw);
705 |
706 | return result.root;
707 | }
708 |
709 | aodbm_version aodbm_del(aodbm *db, aodbm_version ver, aodbm_data *key) {
710 | if (ver == 0) {
711 | return 0;
712 | }
713 | if (!aodbm_has(db, ver, key)) {
714 | return ver;
715 | }
716 | pthread_mutex_lock(&db->rw);
717 | /* find the position of the appendment (filesize + data block header) */
718 | uint64_t append_pos = aodbm_file_size(db) + 5;
719 |
720 | root_result result;
721 |
722 | char type;
723 | aodbm_read(db, ver + 8, 1, &type);
724 | if (type == 'l') {
725 | modify_result res = remove_from_leaf(db, key, ver + 9);
726 | result = construct_root_di(ver, append_pos, aodbm_rope_empty(), 0, res);
727 | } else if (type == 'b') {
728 | /* TODO: modify to merge nodes */
729 | aodbm_rope *data = aodbm_rope_empty();
730 | uint64_t data_sz = 0;
731 | aodbm_stack *path = aodbm_search_path(db, ver, key);
732 |
733 | /* pop the leaf node */
734 | aodbm_path_node *ptr = aodbm_stack_pop(&path);
735 | aodbm_path_node node = *ptr;
736 | free(ptr);
737 | modify_result nodes = remove_from_leaf(db, key, node.node + 1);
738 | uint64_t prev_node = node.node;
739 |
740 | uint64_t a, b;
741 |
742 | while (path != NULL) {
743 | ptr = aodbm_stack_pop(&path);
744 | node = *ptr;
745 | free(ptr);
746 |
747 | if (nodes.a_key == NULL) {
748 | a = 0;
749 | } else {
750 | uint64_t a_sz;
751 | a_sz = aodbm_rope_size(nodes.a_node);
752 | a = data_sz + append_pos;
753 | data = aodbm_rope_merge_di(data, nodes.a_node);
754 | data_sz += a_sz;
755 | }
756 | if (nodes.b_node == NULL) {
757 | b = 0;
758 | } else {
759 | uint64_t b_sz;
760 | b_sz = aodbm_rope_size(nodes.b_node);
761 | b = data_sz + append_pos;
762 | data = aodbm_rope_merge_di(data, nodes.b_node);
763 | data_sz += b_sz;
764 | }
765 |
766 | nodes = modify_branch(db,
767 | node.node,
768 | node.key,
769 | a,
770 | nodes.a_key,
771 | b,
772 | nodes.b_key,
773 | prev_node,
774 | 0);
775 | aodbm_free_data(node.key);
776 |
777 | prev_node = node.node;
778 | }
779 |
780 | result = construct_root_di(ver, append_pos, data, data_sz, nodes);
781 | } else {
782 | AODBM_CUSTOM_ERROR("unknown node type");
783 | }
784 |
785 | aodbm_write_data_block(db, result.dat);
786 | aodbm_free_data(result.dat);
787 |
788 | pthread_mutex_unlock(&db->rw);
789 | return result.root;
790 | }
791 |
792 | bool aodbm_has(aodbm *db, aodbm_version ver, aodbm_data *key) {
793 | if (ver == 0) {
794 | return false;
795 | }
796 | uint64_t leaf_node = aodbm_search(db, ver, key);
797 | uint32_t sz = aodbm_read32(db, leaf_node + 1);
798 | uint32_t i;
799 | uint64_t pos = leaf_node + 5;
800 | for (i = 0; i < sz; ++i) {
801 | aodbm_data *r_key = aodbm_read_data(db, pos);
802 | pos += r_key->sz + 4;
803 | aodbm_data *r_val = aodbm_read_data(db, pos);
804 | pos += r_val->sz + 4;
805 |
806 | bool eq = aodbm_data_eq(key, r_key);
807 |
808 | aodbm_free_data(r_key);
809 | aodbm_free_data(r_val);
810 |
811 | if (eq) {
812 | return true;
813 | }
814 | }
815 | return false;
816 | }
817 |
818 | aodbm_data *aodbm_get(aodbm *db, aodbm_version ver, aodbm_data *key) {
819 | if (ver == 0) {
820 | return NULL;
821 | }
822 | uint64_t leaf_node = aodbm_search(db, ver, key);
823 | uint32_t sz = aodbm_read32(db, leaf_node + 1);
824 | uint32_t i;
825 | uint64_t pos = leaf_node + 5;
826 | for (i = 0; i < sz; ++i) {
827 | aodbm_data *r_key = aodbm_read_data(db, pos);
828 | pos += r_key->sz + 4;
829 | aodbm_data *r_val = aodbm_read_data(db, pos);
830 | pos += r_val->sz + 4;
831 |
832 | bool eq = aodbm_data_eq(key, r_key);
833 |
834 | aodbm_free_data(r_key);
835 |
836 | if (eq) {
837 | return r_val;
838 | }
839 |
840 | aodbm_free_data(r_val);
841 | }
842 | return NULL;
843 | }
844 |
845 | bool aodbm_is_based_on(aodbm *db, aodbm_version a, aodbm_version b) {
846 | /* is a based on b? */
847 | if (b == 0) {
848 | /* everything is based on version 0 */
849 | return true;
850 | }
851 | if (a == 0) {
852 | /* version 0 is based on nothing */
853 | return false;
854 | }
855 | if (a < b) {
856 | /* a can't be based on a version that is further on in the file */
857 | return false;
858 | }
859 | if (a == b) {
860 | return true;
861 | }
862 | return aodbm_is_based_on(db, aodbm_previous_version(db, a), b);
863 | }
864 |
865 | aodbm_version aodbm_previous_version(aodbm *db, aodbm_version ver) {
866 | return aodbm_read64(db, ver);
867 | }
868 |
869 | aodbm_version aodbm_common_ancestor(aodbm *db,
870 | aodbm_version a,
871 | aodbm_version b) {
872 | if (a == b) {
873 | return a;
874 | }
875 | if (a == 0 || b == 0) {
876 | return 0;
877 | }
878 | if (a > b) {
879 | return aodbm_common_ancestor(db, aodbm_previous_version(db, a), b);
880 | }
881 | if (b > a) {
882 | return aodbm_common_ancestor(db, a, aodbm_previous_version(db, b));
883 | }
884 | }
885 |
886 | struct aodbm_iterator {
887 | aodbm_stack *path;
888 | aodbm_version ver;
889 | };
890 |
891 | typedef struct {
892 | uint64_t pos;
893 | uint32_t n;
894 | uint32_t sz;
895 | } it_node_info;
896 |
897 | void construct_iterator(aodbm *db, aodbm_iterator *it, uint64_t node) {
898 | char type;
899 | aodbm_read(db, node, 1, &type);
900 |
901 | uint32_t size = aodbm_read32(db, node + 1);
902 |
903 | it_node_info *info = malloc(sizeof(it_node_info));
904 | info->sz = size;
905 | info->n = 0;
906 |
907 | if (type == 'l') {
908 | info->pos = node + 5;
909 | aodbm_stack_push(&it->path, info);
910 | } else if (type == 'b') {
911 | uint64_t n = aodbm_read64(db, node + 5);
912 |
913 | info->pos = node + 13;
914 | aodbm_stack_push(&it->path, info);
915 |
916 | construct_iterator(db, it, n);
917 | } else {
918 | AODBM_CUSTOM_ERROR("unknown node type");
919 | }
920 | }
921 |
922 | aodbm_iterator *aodbm_new_iterator(aodbm *db, aodbm_version ver) {
923 | /* create the path of the first record */
924 | aodbm_iterator *it = malloc(sizeof(aodbm_iterator));
925 | it->path = NULL;
926 | it->ver = ver;
927 |
928 | if (ver != 0) {
929 | construct_iterator(db, it, ver + 8);
930 | }
931 |
932 | return it;
933 | }
934 |
935 | void aodbm_iterator_goto_recursive(aodbm *db,
936 | aodbm_iterator *it,
937 | aodbm_data *key,
938 | uint64_t node) {
939 | char type;
940 | aodbm_read(db, node, 1, &type);
941 |
942 | uint32_t size = aodbm_read32(db, node + 1);
943 |
944 | it_node_info *info = malloc(sizeof(it_node_info));
945 | info->sz = size;
946 |
947 | uint32_t n;
948 | uint64_t pos = node + 5;
949 |
950 | if (type == 'l') {
951 | for (n = 0; n < size; ++n) {
952 | aodbm_data *s_key = aodbm_read_data(db, pos);
953 |
954 | if (aodbm_data_le(key, s_key)) {
955 | aodbm_free_data(s_key);
956 | break;
957 | }
958 |
959 | pos += 4 + s_key->sz;
960 | aodbm_free_data(s_key);
961 | aodbm_data *s_val = aodbm_read_data(db, pos);
962 | pos += 4 + s_val->sz;
963 | aodbm_free_data(s_val);
964 | }
965 |
966 | info->pos = pos;
967 | info->n = n;
968 | aodbm_stack_push(&it->path, info);
969 | } else if (type == 'b') {
970 | uint64_t off = aodbm_read64(db, pos);
971 | pos += 8;
972 |
973 | for (n = 0; n < size; ++n) {
974 | aodbm_data *s_key = aodbm_read_data(db, pos);
975 |
976 | if (aodbm_data_lt(key, s_key)) {
977 | aodbm_free_data(s_key);
978 | break;
979 | }
980 |
981 | pos += 4 + s_key->sz;
982 | aodbm_free_data(s_key);
983 | off = aodbm_read64(db, pos);
984 | pos += 8;
985 | }
986 |
987 | info->pos = pos;
988 | info->n = n;
989 | aodbm_stack_push(&it->path, info);
990 |
991 | aodbm_iterator_goto_recursive(db, it, key, off);
992 | } else {
993 | AODBM_CUSTOM_ERROR("unknown node type");
994 | }
995 | }
996 |
997 | void aodbm_iterator_goto(aodbm *db,
998 | aodbm_iterator *it,
999 | aodbm_data *key) {
1000 | while (it->path != NULL) {
1001 | free(aodbm_stack_pop(&it->path));
1002 | }
1003 | aodbm_iterator_goto_recursive(db, it, key, it->ver + 8);
1004 | }
1005 |
1006 | aodbm_iterator *aodbm_iterate_from(aodbm *db,
1007 | aodbm_version ver,
1008 | aodbm_data *key) {
1009 | aodbm_iterator *it = malloc(sizeof(aodbm_iterator));
1010 | it->path = NULL;
1011 | it->ver = ver;
1012 |
1013 | aodbm_iterator_goto(db, it, key);
1014 |
1015 | return it;
1016 | }
1017 |
1018 | void aodbm_free_iterator(aodbm_iterator *it) {
1019 | while (it->path != NULL) {
1020 | free(aodbm_stack_pop(&it->path));
1021 | }
1022 | free(it);
1023 | }
1024 |
1025 | aodbm_record aodbm_iterator_next(aodbm *db, aodbm_iterator *it) {
1026 | aodbm_record output;
1027 |
1028 | if (it->path == NULL) {
1029 | output.key = NULL;
1030 | output.val = NULL;
1031 | return output;
1032 | }
1033 |
1034 | it_node_info *leaf = aodbm_stack_pop(&it->path);
1035 |
1036 | if (leaf->n == leaf->sz) {
1037 | /* advance to the next leaf node */
1038 | while (it->path != NULL) {
1039 | it_node_info *branch = aodbm_stack_pop(&it->path);
1040 |
1041 | if (branch->n < branch->sz) {
1042 | /* advance the branch and construct the stack */
1043 | aodbm_data *key = aodbm_read_data(db, branch->pos);
1044 | branch->pos += 4 + key->sz;
1045 | aodbm_free_data(key);
1046 |
1047 | uint64_t node = aodbm_read64(db, branch->pos);
1048 | branch->pos += 8;
1049 |
1050 | branch->n += 1;
1051 |
1052 | aodbm_stack_push(&it->path, branch);
1053 |
1054 | /* travel back down the stack */
1055 | construct_iterator(db, it, node);
1056 |
1057 | free(leaf);
1058 | leaf = aodbm_stack_pop(&it->path);
1059 | break;
1060 | }
1061 |
1062 | free(branch);
1063 | }
1064 | if (it->path == NULL) {
1065 | output.key = NULL;
1066 | output.val = NULL;
1067 | return output;
1068 | }
1069 | }
1070 |
1071 | output.key = aodbm_read_data(db, leaf->pos);
1072 | leaf->pos += 4 + output.key->sz;
1073 | output.val = aodbm_read_data(db, leaf->pos);
1074 | leaf->pos += 4 + output.val->sz;
1075 | leaf->n += 1;
1076 |
1077 | aodbm_stack_push(&it->path, leaf);
1078 |
1079 | return output;
1080 | }
1081 |
1082 | /* Find the changeset that you would apply to the prev to get to ver */
1083 | aodbm_changeset aodbm_diff_prev(aodbm *db, aodbm_version ver) {
1084 | assert(0);
1085 | }
1086 |
1087 | /* Find the changeset that you would apply to ver to get to the prev */
1088 | aodbm_changeset aodbm_diff_prev_rev(aodbm *db, aodbm_version ver) {
1089 | assert(0);
1090 | }
1091 |
1092 | /* Find the changeset that you would apply to go from a to b */
1093 | aodbm_changeset aodbm_diff(aodbm *db, aodbm_version a, aodbm_version b) {
1094 | aodbm_version c = aodbm_common_ancestor(db, a, b);
1095 | if (c != a && c != b) {
1096 | aodbm_changeset cb = aodbm_diff(db, c, b);
1097 | aodbm_changeset ac = aodbm_diff(db, a, c);
1098 | return aodbm_changeset_merge_di(ac, cb);
1099 | }
1100 | aodbm_changeset res;
1101 |
1102 | if (a < b) {
1103 | while (b != a) {
1104 | res = aodbm_changeset_merge_di(res, aodbm_diff_prev(db, b));
1105 | b = aodbm_previous_version(db, b);
1106 | }
1107 | } else if (b < a) {
1108 | while (a != b) {
1109 | res = aodbm_changeset_merge_di(res, aodbm_diff_prev_rev(db, a));
1110 | a = aodbm_previous_version(db, a);
1111 | }
1112 | }
1113 |
1114 | return res;
1115 | }
1116 |
1117 | aodbm_version aodbm_apply(aodbm *db, aodbm_version ver, aodbm_changeset ch) {
1118 | aodbm_list_iterator *it;
1119 | for (it = aodbm_list_begin(ch.list);
1120 | !aodbm_list_iterator_is_finished(it);
1121 | aodbm_list_iterator_next(it)) {
1122 | aodbm_change *change = aodbm_list_iterator_get(it);
1123 | if (change->type == AODBM_MODIFY) {
1124 | ver = aodbm_set(db, ver, change->key, change->val);
1125 | } else if (change->type = AODBM_REMOVE) {
1126 | ver = aodbm_del(db, ver, change->key);
1127 | } else {
1128 | AODBM_CUSTOM_ERROR("unknown change type");
1129 | }
1130 | }
1131 | aodbm_free_list_iterator(it);
1132 | return ver;
1133 | }
1134 |
1135 | aodbm_version aodbm_apply_di(aodbm *db, aodbm_version ver, aodbm_changeset ch) {
1136 | aodbm_version result = aodbm_apply(db, ver, ch);
1137 | aodbm_free_changeset(ch);
1138 | return result;
1139 | }
1140 |
1141 | aodbm_version aodbm_merge(aodbm *db, aodbm_version a, aodbm_version b) {
1142 | aodbm_version c = aodbm_common_ancestor(db, a, b);
1143 | if (c == a) {
1144 | return b;
1145 | }
1146 | if (c == b) {
1147 | return a;
1148 | }
1149 | return aodbm_apply_di(db, a, aodbm_diff(db, c, b));
1150 | }
1151 |
--------------------------------------------------------------------------------