ruby_odeum 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +504 -0
- data/LICENSE +504 -0
- data/README +50 -0
- data/bin/odeum_mgr +106 -0
- data/doc/rdoc/classes/Odeum.html +235 -0
- data/doc/rdoc/classes/Odeum.src/M000010.html +25 -0
- data/doc/rdoc/classes/Odeum.src/M000011.html +22 -0
- data/doc/rdoc/classes/Odeum.src/M000012.html +27 -0
- data/doc/rdoc/classes/Odeum.src/M000013.html +27 -0
- data/doc/rdoc/classes/Odeum.src/M000014.html +28 -0
- data/doc/rdoc/classes/Odeum/Document.html +382 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000040.html +25 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000041.html +22 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000042.html +23 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000043.html +23 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000044.html +24 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000045.html +32 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000046.html +22 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000047.html +22 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000048.html +22 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000049.html +22 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000050.html +24 -0
- data/doc/rdoc/classes/Odeum/Document.src/M000051.html +27 -0
- data/doc/rdoc/classes/Odeum/Index.html +662 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000015.html +46 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000016.html +33 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000017.html +35 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000018.html +23 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000019.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000020.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000021.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000022.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000023.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000024.html +29 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000025.html +23 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000026.html +24 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000027.html +23 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000028.html +26 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000029.html +24 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000030.html +20 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000031.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000032.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000033.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000034.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000035.html +20 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000036.html +20 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000037.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000038.html +22 -0
- data/doc/rdoc/classes/Odeum/Index.src/M000039.html +22 -0
- data/doc/rdoc/classes/OdeumTest.html +257 -0
- data/doc/rdoc/classes/OdeumTest.src/M000001.html +18 -0
- data/doc/rdoc/classes/OdeumTest.src/M000002.html +19 -0
- data/doc/rdoc/classes/OdeumTest.src/M000003.html +27 -0
- data/doc/rdoc/classes/OdeumTest.src/M000004.html +25 -0
- data/doc/rdoc/classes/OdeumTest.src/M000005.html +44 -0
- data/doc/rdoc/classes/OdeumTest.src/M000006.html +20 -0
- data/doc/rdoc/classes/OdeumTest.src/M000007.html +39 -0
- data/doc/rdoc/classes/OdeumTest.src/M000008.html +59 -0
- data/doc/rdoc/classes/OdeumTest.src/M000009.html +41 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/COPYING.html +756 -0
- data/doc/rdoc/files/LICENSE.html +756 -0
- data/doc/rdoc/files/README.html +175 -0
- data/doc/rdoc/files/ext/odeum_index/odeum_index_c.html +101 -0
- data/doc/rdoc/files/test/test_odeum_rb.html +109 -0
- data/doc/rdoc/fr_class_index.html +30 -0
- data/doc/rdoc/fr_file_index.html +31 -0
- data/doc/rdoc/fr_method_index.html +77 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/ext/odeum_index/cabin.c +2735 -0
- data/ext/odeum_index/cabin.h +1040 -0
- data/ext/odeum_index/curia.c +1114 -0
- data/ext/odeum_index/curia.h +430 -0
- data/ext/odeum_index/depot.c +1910 -0
- data/ext/odeum_index/depot.h +439 -0
- data/ext/odeum_index/extconf.rb +10 -0
- data/ext/odeum_index/myconf.c +668 -0
- data/ext/odeum_index/myconf.h +523 -0
- data/ext/odeum_index/odeum.c +1743 -0
- data/ext/odeum_index/odeum.h +541 -0
- data/ext/odeum_index/odeum_index.c +991 -0
- data/ext/odeum_index/villa.c +1923 -0
- data/ext/odeum_index/villa.h +470 -0
- data/ext/odeum_index/vista.c +159 -0
- data/ext/odeum_index/vista.h +111 -0
- data/test/test_odeum.rb +174 -0
- metadata +138 -0
@@ -0,0 +1,430 @@
|
|
1
|
+
/*************************************************************************************************
|
2
|
+
* The extended API of QDBM
|
3
|
+
* Copyright (C) 2000-2005 Mikio Hirabayashi
|
4
|
+
* This file is part of QDBM, Quick Database Manager.
|
5
|
+
* QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
|
6
|
+
* Lesser General Public License as published by the Free Software Foundation; either version
|
7
|
+
* 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
|
8
|
+
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
9
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
10
|
+
* details.
|
11
|
+
* You should have received a copy of the GNU Lesser General Public License along with QDBM; if
|
12
|
+
* not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
13
|
+
* 02111-1307 USA.
|
14
|
+
*************************************************************************************************/
|
15
|
+
|
16
|
+
|
17
|
+
#ifndef _CURIA_H /* duplication check */
|
18
|
+
#define _CURIA_H
|
19
|
+
|
20
|
+
#if defined(__cplusplus) /* export for C++ */
|
21
|
+
extern "C" {
|
22
|
+
#endif
|
23
|
+
|
24
|
+
|
25
|
+
#include <depot.h>
|
26
|
+
#include <stdlib.h>
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
/*************************************************************************************************
|
31
|
+
* API
|
32
|
+
*************************************************************************************************/
|
33
|
+
|
34
|
+
|
35
|
+
typedef struct { /* type of structure for the database handle */
|
36
|
+
char *name; /* name of the database directory */
|
37
|
+
int wmode; /* whether writable or not */
|
38
|
+
int inode; /* inode of the database directory */
|
39
|
+
DEPOT *attr; /* database handle for attributes */
|
40
|
+
DEPOT **depots; /* handles of the record database */
|
41
|
+
int dnum; /* number of record database handles */
|
42
|
+
int inum; /* number of the database of the using iterator */
|
43
|
+
int lrnum; /* number of large objects */
|
44
|
+
} CURIA;
|
45
|
+
|
46
|
+
enum { /* enumeration for open modes */
|
47
|
+
CR_OREADER = 1 << 0, /* open as a reader */
|
48
|
+
CR_OWRITER = 1 << 1, /* open as a writer */
|
49
|
+
CR_OCREAT = 1 << 2, /* a writer creating */
|
50
|
+
CR_OTRUNC = 1 << 3, /* a writer truncating */
|
51
|
+
CR_ONOLCK = 1 << 4, /* open without locking */
|
52
|
+
CR_OSPARSE = 1 << 5 /* create as sparse files */
|
53
|
+
};
|
54
|
+
|
55
|
+
enum { /* enumeration for write modes */
|
56
|
+
CR_DOVER, /* overwrite an existing value */
|
57
|
+
CR_DKEEP, /* keep an existing value */
|
58
|
+
CR_DCAT /* concatenate values */
|
59
|
+
};
|
60
|
+
|
61
|
+
|
62
|
+
/* Get a database handle.
|
63
|
+
`name' specifies the name of a database directory.
|
64
|
+
`omode' specifies the connection mode: `CR_OWRITER' as a writer, `CR_OREADER' as a reader.
|
65
|
+
If the mode is `CR_OWRITER', the following may be added by bitwise or: `CR_OCREAT', which
|
66
|
+
means it creates a new database if not exist, `CR_OTRUNC', which means it creates a new
|
67
|
+
database regardless if one exists. Both of `CR_OREADER' and `CR_OWRITER' can be added to by
|
68
|
+
bitwise or: `CR_ONOLCK', which means it opens a database directory without file locking.
|
69
|
+
`CR_OCREAT' can be added to by bitwise or: `CR_OSPARSE', which means it creates database
|
70
|
+
files as sparse files.
|
71
|
+
`bnum' specifies the number of elements of each bucket array. If it is not more than 0,
|
72
|
+
the default value is specified. The size of each bucket array is determined on creating,
|
73
|
+
and can not be changed except for by optimization of the database. Suggested size of each
|
74
|
+
bucket array is about from 0.5 to 4 times of the number of all records to store.
|
75
|
+
`dnum' specifies the number of division of the database. If it is not more than 0, the
|
76
|
+
default value is specified. The number of division can not be changed from the initial value.
|
77
|
+
The max number of division is 512.
|
78
|
+
The return value is the database handle or `NULL' if it is not successful.
|
79
|
+
While connecting as a writer, an exclusive lock is invoked to the database directory.
|
80
|
+
While connecting as a reader, a shared lock is invoked to the database directory.
|
81
|
+
The thread blocks until the lock is achieved. If `CR_ONOLCK' is used, the application is
|
82
|
+
responsible for exclusion control. */
|
83
|
+
CURIA *cropen(const char *name, int omode, int bnum, int dnum);
|
84
|
+
|
85
|
+
|
86
|
+
/* Close a database handle.
|
87
|
+
`curia' specifies a database handle.
|
88
|
+
If successful, the return value is true, else, it is false.
|
89
|
+
Because the region of a closed handle is released, it becomes impossible to use the handle.
|
90
|
+
Updating a database is assured to be written when the handle is closed. If a writer opens
|
91
|
+
a database but does not close it appropriately, the database will be broken. */
|
92
|
+
int crclose(CURIA *curia);
|
93
|
+
|
94
|
+
|
95
|
+
/* Store a record.
|
96
|
+
`curia' specifies a database handle connected as a writer.
|
97
|
+
`kbuf' specifies the pointer to the region of a key.
|
98
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
99
|
+
with `strlen(kbuf)'.
|
100
|
+
`vbuf' specifies the pointer to the region of a value.
|
101
|
+
`vsiz' specifies the size of the region of the value. If it is negative, the size is
|
102
|
+
assigned with `strlen(vbuf)'.
|
103
|
+
`dmode' specifies behavior when the key overlaps, by the following values: `CR_DOVER',
|
104
|
+
which means the specified value overwrites the existing one, `CR_DKEEP', which means the
|
105
|
+
existing value is kept, `CR_DCAT', which means the specified value is concatenated at the
|
106
|
+
end of the existing value.
|
107
|
+
If successful, the return value is true, else, it is false. */
|
108
|
+
int crput(CURIA *curia, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode);
|
109
|
+
|
110
|
+
|
111
|
+
/* Delete a record.
|
112
|
+
`curia' specifies a database handle connected as a writer.
|
113
|
+
`kbuf' specifies the pointer to the region of a key.
|
114
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
115
|
+
with `strlen(kbuf)'.
|
116
|
+
If successful, the return value is true, else, it is false. False is returned when no
|
117
|
+
record corresponds to the specified key. */
|
118
|
+
int crout(CURIA *curia, const char *kbuf, int ksiz);
|
119
|
+
|
120
|
+
|
121
|
+
/* Retrieve a record.
|
122
|
+
`curia' specifies a database handle.
|
123
|
+
`kbuf' specifies the pointer to the region of a key.
|
124
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
125
|
+
with `strlen(kbuf)'.
|
126
|
+
`start' specifies the offset address of the beginning of the region of the value to be read.
|
127
|
+
`max' specifies the max size to be read. If it is negative, the size to read is unlimited.
|
128
|
+
`sp' specifies the pointer to a variable to which the size of the region of the return value
|
129
|
+
is assigned. If it is `NULL', it is not used.
|
130
|
+
If successful, the return value is the pointer to the region of the value of the
|
131
|
+
corresponding record, else, it is `NULL'. `NULL' is returned when no record corresponds to
|
132
|
+
the specified key or the size of the value of the corresponding record is less than `start'.
|
133
|
+
Because an additional zero code is appended at the end of the region of the return value,
|
134
|
+
the return value can be treated as a character string. Because the region of the return
|
135
|
+
value is allocated with the `malloc' call, it should be released with the `free' call if it
|
136
|
+
is no longer in use. */
|
137
|
+
char *crget(CURIA *curia, const char *kbuf, int ksiz, int start, int max, int *sp);
|
138
|
+
|
139
|
+
|
140
|
+
/* Retrieve a record and write the value into a buffer.
|
141
|
+
`curia' specifies a database handle.
|
142
|
+
`kbuf' specifies the pointer to the region of a key.
|
143
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
144
|
+
with `strlen(kbuf)'.
|
145
|
+
`start' specifies the offset address of the beginning of the region of the value to be read.
|
146
|
+
`max' specifies the max size to be read. It shuld be equal to or less than the size of the
|
147
|
+
writing buffer.
|
148
|
+
`vbuf' specifies the pointer to a buffer into which the value of the corresponding record is
|
149
|
+
written.
|
150
|
+
If successful, the return value is the size of the written data, else, it is -1. -1 is
|
151
|
+
returned when no record corresponds to the specified key or the size of the value of the
|
152
|
+
corresponding record is less than `start'.
|
153
|
+
Note that no additional zero code is appended at the end of the region of the writing buffer. */
|
154
|
+
int crgetwb(CURIA *curia, const char *kbuf, int ksiz, int start, int max, char *vbuf);
|
155
|
+
|
156
|
+
|
157
|
+
/* Get the size of the value of a record.
|
158
|
+
`curia' specifies a database handle.
|
159
|
+
`kbuf' specifies the pointer to the region of a key.
|
160
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
161
|
+
with `strlen(kbuf)'.
|
162
|
+
If successful, the return value is the size of the value of the corresponding record, else,
|
163
|
+
it is -1.
|
164
|
+
Because this function does not read the entity of a record, it is faster than `crget'. */
|
165
|
+
int crvsiz(CURIA *curia, const char *kbuf, int ksiz);
|
166
|
+
|
167
|
+
|
168
|
+
/* Initialize the iterator of a database handle.
|
169
|
+
`curia' specifies a database handle.
|
170
|
+
If successful, the return value is true, else, it is false.
|
171
|
+
The iterator is used in order to access the key of every record stored in a database. */
|
172
|
+
int criterinit(CURIA *curia);
|
173
|
+
|
174
|
+
|
175
|
+
/* Get the next key of the iterator.
|
176
|
+
`curia' specifies a database handle.
|
177
|
+
`sp' specifies the pointer to a variable to which the size of the region of the return
|
178
|
+
value is assigned. If it is `NULL', it is not used.
|
179
|
+
If successful, the return value is the pointer to the region of the next key, else, it is
|
180
|
+
`NULL'. `NULL' is returned when no record is to be get out of the iterator.
|
181
|
+
Because an additional zero code is appended at the end of the region of the return value,
|
182
|
+
the return value can be treated as a character string. Because the region of the return
|
183
|
+
value is allocated with the `malloc' call, it should be released with the `free' call if it
|
184
|
+
is no longer in use. It is possible to access every record by iteration of calling this
|
185
|
+
function. However, it is not assured if updating the database is occurred while the
|
186
|
+
iteration. Besides, the order of this traversal access method is arbitrary, so it is not
|
187
|
+
assured that the order of storing matches the one of the traversal access. */
|
188
|
+
char *criternext(CURIA *curia, int *sp);
|
189
|
+
|
190
|
+
|
191
|
+
/* Set alignment of a database handle.
|
192
|
+
`curia' specifies a database handle connected as a writer.
|
193
|
+
`align' specifies the size of alignment.
|
194
|
+
If successful, the return value is true, else, it is false.
|
195
|
+
If alignment is set to a database, the efficiency of overwriting values are improved.
|
196
|
+
The size of alignment is suggested to be average size of the values of the records to be
|
197
|
+
stored. If alignment is positive, padding whose size is multiple number of the alignment
|
198
|
+
is placed. If alignment is negative, as `vsiz' is the size of a value, the size of padding
|
199
|
+
is calculated with `(vsiz / pow(2, abs(align) - 1))'. Because alignment setting is not
|
200
|
+
saved in a database, you should specify alignment every opening a database. */
|
201
|
+
int crsetalign(CURIA *curia, int align);
|
202
|
+
|
203
|
+
|
204
|
+
/* Synchronize updating contents with the files and the devices.
|
205
|
+
`curia' specifies a database handle connected as a writer.
|
206
|
+
If successful, the return value is true, else, it is false.
|
207
|
+
This function is useful when another process uses the connected database directory. */
|
208
|
+
int crsync(CURIA *curia);
|
209
|
+
|
210
|
+
|
211
|
+
/* Optimize a database.
|
212
|
+
`curia' specifies a database handle connected as a writer.
|
213
|
+
`bnum' specifies the number of the elements of each bucket array. If it is not more than 0,
|
214
|
+
the default value is specified.
|
215
|
+
If successful, the return value is true, else, it is false.
|
216
|
+
In an alternating succession of deleting and storing with overwrite or concatenate,
|
217
|
+
dispensable regions accumulate. This function is useful to do away with them. */
|
218
|
+
int croptimize(CURIA *curia, int bnum);
|
219
|
+
|
220
|
+
/* Get the name of a database.
|
221
|
+
`curia' specifies a database handle.
|
222
|
+
If successful, the return value is the pointer to the region of the name of the database,
|
223
|
+
else, it is `NULL'.
|
224
|
+
Because the region of the return value is allocated with the `malloc' call, it should be
|
225
|
+
released with the `free' call if it is no longer in use. */
|
226
|
+
char *crname(CURIA *curia);
|
227
|
+
|
228
|
+
|
229
|
+
/* Get the total size of database files.
|
230
|
+
`curia' specifies a database handle.
|
231
|
+
If successful, the return value is the total size of the database files, else, it is -1.
|
232
|
+
If the total size is more than 2GB, the return value overflows. */
|
233
|
+
int crfsiz(CURIA *curia);
|
234
|
+
|
235
|
+
|
236
|
+
/* Get the total size of database files as double-precision floating-point number.
|
237
|
+
`curia' specifies a database handle.
|
238
|
+
If successful, the return value is the total size of the database files, else, it is -1.0. */
|
239
|
+
double crfsizd(CURIA *curia);
|
240
|
+
|
241
|
+
|
242
|
+
/* Get the total number of the elements of each bucket array.
|
243
|
+
`curia' specifies a database handle.
|
244
|
+
If successful, the return value is the total number of the elements of each bucket array,
|
245
|
+
else, it is -1. */
|
246
|
+
int crbnum(CURIA *curia);
|
247
|
+
|
248
|
+
|
249
|
+
/* Get the total number of the used elements of each bucket array.
|
250
|
+
`curia' specifies a database handle.
|
251
|
+
If successful, the return value is the total number of the used elements of each bucket
|
252
|
+
array, else, it is -1.
|
253
|
+
This function is inefficient because it accesses all elements of each bucket array. */
|
254
|
+
int crbusenum(CURIA *curia);
|
255
|
+
|
256
|
+
|
257
|
+
/* Get the number of the records stored in a database.
|
258
|
+
`curia' specifies a database handle.
|
259
|
+
If successful, the return value is the number of the records stored in the database, else,
|
260
|
+
it is -1. */
|
261
|
+
int crrnum(CURIA *curia);
|
262
|
+
|
263
|
+
|
264
|
+
/* Check whether a database handle is a writer or not.
|
265
|
+
`curia' specifies a database handle.
|
266
|
+
The return value is true if the handle is a writer, false if not. */
|
267
|
+
int crwritable(CURIA *curia);
|
268
|
+
|
269
|
+
|
270
|
+
/* Check whether a database has a fatal error or not.
|
271
|
+
`curia' specifies a database handle.
|
272
|
+
The return value is true if the database has a fatal error, false if not. */
|
273
|
+
int crfatalerror(CURIA *curia);
|
274
|
+
|
275
|
+
|
276
|
+
/* Get the inode number of a database directory.
|
277
|
+
`curia' specifies a database handle.
|
278
|
+
The return value is the inode number of the database directory. */
|
279
|
+
int crinode(CURIA *curia);
|
280
|
+
|
281
|
+
|
282
|
+
/* Get the last modified time of a database.
|
283
|
+
`curia' specifies a database handle.
|
284
|
+
The return value is the last modified time of the database. */
|
285
|
+
int crmtime(CURIA *curia);
|
286
|
+
|
287
|
+
|
288
|
+
/* Remove a database directory.
|
289
|
+
`name' specifies the name of a database directory.
|
290
|
+
If successful, the return value is true, else, it is false. */
|
291
|
+
int crremove(const char *name);
|
292
|
+
|
293
|
+
|
294
|
+
/* Repair a broken database directory.
|
295
|
+
`name' specifies the name of a database directory.
|
296
|
+
If successful, the return value is true, else, it is false.
|
297
|
+
There is no guarantee that all records in a repaired database directory correspond to the
|
298
|
+
original or expected state. */
|
299
|
+
int crrepair(const char *name);
|
300
|
+
|
301
|
+
|
302
|
+
/* Dump all records as endian independent data.
|
303
|
+
`curia' specifies a database handle.
|
304
|
+
`name' specifies the name of an output directory.
|
305
|
+
If successful, the return value is true, else, it is false.
|
306
|
+
Note that large objects are ignored. */
|
307
|
+
int crexportdb(CURIA *curia, const char *name);
|
308
|
+
|
309
|
+
|
310
|
+
/* Load all records from endian independent data.
|
311
|
+
`curia' specifies a database handle connected as a writer. The database of the handle must
|
312
|
+
be empty.
|
313
|
+
`name' specifies the name of an input directory.
|
314
|
+
If successful, the return value is true, else, it is false.
|
315
|
+
Note that large objects are ignored. */
|
316
|
+
int crimportdb(CURIA *curia, const char *name);
|
317
|
+
|
318
|
+
|
319
|
+
/* Store a large object.
|
320
|
+
`curia' specifies a database handle connected as a writer.
|
321
|
+
`kbuf' specifies the pointer to the region of a key.
|
322
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
323
|
+
with `strlen(kbuf)'.
|
324
|
+
`vbuf' specifies the pointer to the region of a value.
|
325
|
+
`vsiz' specifies the size of the region of the value. If it is negative, the size is
|
326
|
+
assigned with `strlen(vbuf)'.
|
327
|
+
`dmode' specifies behavior when the key overlaps, by the following values: `CR_DOVER',
|
328
|
+
which means the specified value overwrites the existing one, `CR_DKEEP', which means the
|
329
|
+
existing value is kept, `CR_DCAT', which means the specified value is concatenated at the
|
330
|
+
end of the existing value.
|
331
|
+
If successful, the return value is true, else, it is false. */
|
332
|
+
int crputlob(CURIA *curia, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode);
|
333
|
+
|
334
|
+
|
335
|
+
/* Delete a large object.
|
336
|
+
`curia' specifies a database handle connected as a writer.
|
337
|
+
`kbuf' specifies the pointer to the region of a key.
|
338
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
339
|
+
with `strlen(kbuf)'.
|
340
|
+
If successful, the return value is true, else, it is false. false is returned when no large
|
341
|
+
object corresponds to the specified key. */
|
342
|
+
int croutlob(CURIA *curia, const char *kbuf, int ksiz);
|
343
|
+
|
344
|
+
|
345
|
+
/* Retrieve a large object.
|
346
|
+
`curia' specifies a database handle.
|
347
|
+
`kbuf' specifies the pointer to the region of a key.
|
348
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
349
|
+
with `strlen(kbuf)'.
|
350
|
+
`start' specifies the offset address of the beginning of the region of the value to be read.
|
351
|
+
`max' specifies the max size to be read. If it is negative, the size to read is unlimited.
|
352
|
+
`sp' specifies the pointer to a variable to which the size of the region of the return value
|
353
|
+
is assigned. If it is `NULL', it is not used.
|
354
|
+
If successful, the return value is the pointer to the region of the value of the
|
355
|
+
corresponding large object, else, it is `NULL'. `NULL' is returned when no large object
|
356
|
+
corresponds to the specified key or the size of the value of the corresponding large object
|
357
|
+
is less than `start'.
|
358
|
+
Because an additional zero code is appended at the end of the region of the return value,
|
359
|
+
the return value can be treated as a character string. Because the region of the return
|
360
|
+
value is allocated with the `malloc' call, it should be released with the `free' call if it
|
361
|
+
is no longer in use. */
|
362
|
+
char *crgetlob(CURIA *curia, const char *kbuf, int ksiz, int start, int max, int *sp);
|
363
|
+
|
364
|
+
|
365
|
+
/* Get the file descriptor of a large object.
|
366
|
+
`curia' specifies a database handle.
|
367
|
+
`kbuf' specifies the pointer to the region of a key.
|
368
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
369
|
+
with `strlen(kbuf)'.
|
370
|
+
If successful, the return value is the file descriptor of the corresponding large object,
|
371
|
+
else, it is -1. -1 is returned when no large object corresponds to the specified key. The
|
372
|
+
returned file descriptor is opened with the `open' call. If the database handle was opened
|
373
|
+
as a writer, the descriptor is writable (O_RDWR), else, it is not writable (O_RDONLY). The
|
374
|
+
descriptor should be closed with the `close' call if it is no longer in use. */
|
375
|
+
int crgetlobfd(CURIA *curia, const char *kbuf, int ksiz);
|
376
|
+
|
377
|
+
|
378
|
+
/* Get the size of the value of a large object.
|
379
|
+
`curia' specifies a database handle.
|
380
|
+
`kbuf' specifies the pointer to the region of a key.
|
381
|
+
`ksiz' specifies the size of the region of the key. If it is negative, the size is assigned
|
382
|
+
with `strlen(kbuf)'.
|
383
|
+
If successful, the return value is the size of the value of the corresponding large object,
|
384
|
+
else, it is -1.
|
385
|
+
Because this function does not read the entity of a large object, it is faster than
|
386
|
+
`crgetlob'. */
|
387
|
+
int crvsizlob(CURIA *curia, const char *kbuf, int ksiz);
|
388
|
+
|
389
|
+
|
390
|
+
/* Get the number of the large objects stored in a database.
|
391
|
+
`curia' specifies a database handle.
|
392
|
+
If successful, the return value is the number of the large objects stored in the database,
|
393
|
+
else, it is -1. */
|
394
|
+
int crrnumlob(CURIA *curia);
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
/*************************************************************************************************
|
399
|
+
* features for experts
|
400
|
+
*************************************************************************************************/
|
401
|
+
|
402
|
+
|
403
|
+
/* Synchronize updating contents on memory.
|
404
|
+
`curia' specifies a database handle connected as a writer.
|
405
|
+
If successful, the return value is true, else, it is false. */
|
406
|
+
int crmemsync(CURIA *curia);
|
407
|
+
|
408
|
+
|
409
|
+
/* Get flags of a database.
|
410
|
+
`curia' specifies a database handle.
|
411
|
+
The return value is the flags of a database. */
|
412
|
+
int crgetflags(CURIA *curia);
|
413
|
+
|
414
|
+
|
415
|
+
/* Set flags of a database.
|
416
|
+
`curia' specifies a database handle connected as a writer.
|
417
|
+
`flags' specifies flags to set.
|
418
|
+
If successful, the return value is true, else, it is false. */
|
419
|
+
int crsetflags(CURIA *curia, int flags);
|
420
|
+
|
421
|
+
|
422
|
+
|
423
|
+
#if defined(__cplusplus) /* export for C++ */
|
424
|
+
}
|
425
|
+
#endif
|
426
|
+
|
427
|
+
#endif /* duplication check */
|
428
|
+
|
429
|
+
|
430
|
+
/* END OF FILE */
|
@@ -0,0 +1,1910 @@
|
|
1
|
+
/*************************************************************************************************
|
2
|
+
* Implementation of Depot
|
3
|
+
* Copyright (C) 2000-2005 Mikio Hirabayashi
|
4
|
+
* This file is part of QDBM, Quick Database Manager.
|
5
|
+
* QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
|
6
|
+
* Lesser General Public License as published by the Free Software Foundation; either version
|
7
|
+
* 2.1 of the License or any later version. QDBM is distributed in the hope that it will be
|
8
|
+
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
9
|
+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
10
|
+
* details.
|
11
|
+
* You should have received a copy of the GNU Lesser General Public License along with QDBM; if
|
12
|
+
* not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
13
|
+
* 02111-1307 USA.
|
14
|
+
*************************************************************************************************/
|
15
|
+
|
16
|
+
|
17
|
+
#include "depot.h"
|
18
|
+
#include "myconf.h"
|
19
|
+
|
20
|
+
#define DP_FILEMODE 00644 /* permission of a creating file */
|
21
|
+
#define DP_MAGICNUMB "[DEPOT]\n\f" /* magic number on environments of big endian */
|
22
|
+
#define DP_MAGICNUML "[depot]\n\f" /* magic number on environments of little endian */
|
23
|
+
#define DP_HEADSIZ 48 /* size of the reagion of the header */
|
24
|
+
#define DP_FLAGSOFF 16 /* offset of the region for flags */
|
25
|
+
#define DP_FSIZOFF 24 /* offset of the region for the file size */
|
26
|
+
#define DP_BNUMOFF 32 /* offset of the region for the bucket number */
|
27
|
+
#define DP_RNUMOFF 40 /* offset of the region for the record number */
|
28
|
+
#define DP_DEFBNUM 8191 /* default bucket number */
|
29
|
+
#define DP_COALMAX 3 /* number of trials for record coalescence */
|
30
|
+
#define DP_ENTBUFSIZ 128 /* size of the entity buffer */
|
31
|
+
#define DP_STKBUFSIZ 256 /* size of the stack key buffer */
|
32
|
+
#define DP_WRTBUFSIZ 2048 /* size of the writing buffer */
|
33
|
+
#define DP_TMPFSUF MYEXTSTR "dptmp" /* suffix of a temporary file */
|
34
|
+
#define DP_OPTBLOAD 0.25 /* ratio of bucket loading at optimization */
|
35
|
+
#define DP_OPTRUNIT 256 /* number of records in a process of optimization */
|
36
|
+
#define DP_NUMBUFSIZ 32 /* size of a buffer for a number */
|
37
|
+
#define DP_IOBUFSIZ 8192 /* size of an I/O buffer */
|
38
|
+
|
39
|
+
enum { /* enumeration for a record header */
|
40
|
+
DP_RHIFLAGS, /* offset of flags */
|
41
|
+
DP_RHIHASH, /* offset of value of the second hash function */
|
42
|
+
DP_RHIKSIZ, /* offset of the size of the key */
|
43
|
+
DP_RHIVSIZ, /* offset of the size of the value */
|
44
|
+
DP_RHIPSIZ, /* offset of the size of the padding bytes */
|
45
|
+
DP_RHILEFT, /* offset of the offset of the left child */
|
46
|
+
DP_RHIRIGHT, /* offset of the offset of the right child */
|
47
|
+
DP_RHNUM /* number of elements of a header */
|
48
|
+
};
|
49
|
+
|
50
|
+
enum { /* enumeration for the flag of a record */
|
51
|
+
DP_RECFDEL = 1 << 0, /* deleted */
|
52
|
+
DP_RECFREUSE = 1 << 1 /* reusable */
|
53
|
+
};
|
54
|
+
|
55
|
+
|
56
|
+
/* private function prototypes */
|
57
|
+
static int dpbigendian(void);
|
58
|
+
static char *dpstrdup(const char *str);
|
59
|
+
static int dplock(int fd, int ex);
|
60
|
+
static int dpwrite(int fd, const void *buf, int size);
|
61
|
+
static int dpseekwrite(int fd, int off, const void *buf, int size);
|
62
|
+
static int dpseekwritenum(int fd, int off, int num);
|
63
|
+
static int dpread(int fd, void *buf, int size);
|
64
|
+
static int dpseekread(int fd, int off, void *buf, int size);
|
65
|
+
static int dpfcopy(int destfd, int destoff, int srcfd, int srcoff);
|
66
|
+
static int dpfirsthash(const char *kbuf, int ksiz);
|
67
|
+
static int dpsecondhash(const char *kbuf, int ksiz);
|
68
|
+
static int dpthirdhash(const char *kbuf, int ksiz);
|
69
|
+
static int dpgetprime(int num);
|
70
|
+
static int dppadsize(DEPOT *depot, int vsiz);
|
71
|
+
static int dprecsize(int *head);
|
72
|
+
static int dprechead(DEPOT *depot, int off, int *head, char *ebuf, int *eep);
|
73
|
+
static char *dpreckey(DEPOT *depot, int off, int *head);
|
74
|
+
static char *dprecval(DEPOT *depot, int off, int *head, int start, int max);
|
75
|
+
static int dprecvalwb(DEPOT *depot, int off, int *head, int start, int max, char *vbuf);
|
76
|
+
static int dpkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz);
|
77
|
+
static int dprecsearch(DEPOT *depot, const char *kbuf, int ksiz, int hash, int *bip, int *offp,
|
78
|
+
int *entp, int *head, char *ebuf, int *eep, int delhit);
|
79
|
+
static int dprecrewrite(DEPOT *depot, int off, int rsiz, const char *kbuf, int ksiz,
|
80
|
+
const char *vbuf, int vsiz, int hash, int left, int right);
|
81
|
+
static int dprecappend(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
|
82
|
+
int hash, int left, int right);
|
83
|
+
static int dprecover(DEPOT *depot, int off, int *head, const char *vbuf, int vsiz, int cat);
|
84
|
+
static int dprecdelete(DEPOT *depot, int off, int *head, int reusable);
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
/*************************************************************************************************
|
89
|
+
* public objects
|
90
|
+
*************************************************************************************************/
|
91
|
+
|
92
|
+
|
93
|
+
/* String containing the version information. */
|
94
|
+
const char *dpversion = _QDBM_VERSION;
|
95
|
+
|
96
|
+
|
97
|
+
/* Get a message string corresponding to an error code. */
|
98
|
+
const char *dperrmsg(int ecode){
|
99
|
+
switch(ecode){
|
100
|
+
case DP_ENOERR: return "no error";
|
101
|
+
case DP_EFATAL: return "with fatal error";
|
102
|
+
case DP_EMODE: return "invalid mode";
|
103
|
+
case DP_EBROKEN: return "broken database file";
|
104
|
+
case DP_EKEEP: return "existing record";
|
105
|
+
case DP_ENOITEM: return "no item found";
|
106
|
+
case DP_EALLOC: return "memory allocation error";
|
107
|
+
case DP_EMAP: return "memory mapping error";
|
108
|
+
case DP_EOPEN: return "open error";
|
109
|
+
case DP_ECLOSE: return "close error";
|
110
|
+
case DP_ETRUNC: return "trunc error";
|
111
|
+
case DP_ESYNC: return "sync error";
|
112
|
+
case DP_ESTAT: return "stat error";
|
113
|
+
case DP_ESEEK: return "seek error";
|
114
|
+
case DP_EREAD: return "read error";
|
115
|
+
case DP_EWRITE: return "write error";
|
116
|
+
case DP_ELOCK: return "lock error";
|
117
|
+
case DP_EUNLINK: return "unlink error";
|
118
|
+
case DP_EMKDIR: return "mkdir error";
|
119
|
+
case DP_ERMDIR: return "rmdir error";
|
120
|
+
case DP_EMISC: return "miscellaneous error";
|
121
|
+
}
|
122
|
+
return "(invalid ecode)";
|
123
|
+
}
|
124
|
+
|
125
|
+
|
126
|
+
/* Get a database handle. */
|
127
|
+
DEPOT *dpopen(const char *name, int omode, int bnum){
|
128
|
+
int mode, fd, inode, mtime, fsiz, rnum, msiz;
|
129
|
+
char hbuf[DP_HEADSIZ], *map, c;
|
130
|
+
struct stat sbuf;
|
131
|
+
DEPOT *depot;
|
132
|
+
assert(name);
|
133
|
+
mode = O_RDONLY;
|
134
|
+
if(omode & DP_OWRITER){
|
135
|
+
mode = O_RDWR;
|
136
|
+
if(omode & DP_OCREAT) mode |= O_CREAT;
|
137
|
+
}
|
138
|
+
if((fd = open(name, mode, DP_FILEMODE)) == -1){
|
139
|
+
dpecodeset(DP_EOPEN, __FILE__, __LINE__);
|
140
|
+
return NULL;
|
141
|
+
}
|
142
|
+
if(!(omode & DP_ONOLCK)){
|
143
|
+
if(!dplock(fd, omode & DP_OWRITER)){
|
144
|
+
close(fd);
|
145
|
+
return NULL;
|
146
|
+
}
|
147
|
+
}
|
148
|
+
if((omode & DP_OWRITER) && (omode & DP_OTRUNC)){
|
149
|
+
if(ftruncate(fd, 0) == -1){
|
150
|
+
close(fd);
|
151
|
+
dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
|
152
|
+
return NULL;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
|
156
|
+
close(fd);
|
157
|
+
dpecodeset(DP_ESTAT, __FILE__, __LINE__);
|
158
|
+
return NULL;
|
159
|
+
}
|
160
|
+
inode = sbuf.st_ino;
|
161
|
+
mtime = sbuf.st_mtime;
|
162
|
+
fsiz = sbuf.st_size;
|
163
|
+
if((omode & DP_OWRITER) && fsiz == 0){
|
164
|
+
memset(hbuf, 0, DP_HEADSIZ);
|
165
|
+
if(dpbigendian()){
|
166
|
+
memcpy(hbuf, DP_MAGICNUMB, strlen(DP_MAGICNUMB));
|
167
|
+
} else {
|
168
|
+
memcpy(hbuf, DP_MAGICNUML, strlen(DP_MAGICNUML));
|
169
|
+
}
|
170
|
+
bnum = bnum < 1 ? DP_DEFBNUM : bnum;
|
171
|
+
bnum = dpgetprime(bnum);
|
172
|
+
memcpy(hbuf + DP_BNUMOFF, &bnum, sizeof(int));
|
173
|
+
rnum = 0;
|
174
|
+
memcpy(hbuf + DP_RNUMOFF, &rnum, sizeof(int));
|
175
|
+
fsiz = DP_HEADSIZ + bnum * sizeof(int);
|
176
|
+
memcpy(hbuf + DP_FSIZOFF, &fsiz, sizeof(int));
|
177
|
+
if(!dpseekwrite(fd, 0, hbuf, DP_HEADSIZ)){
|
178
|
+
close(fd);
|
179
|
+
return NULL;
|
180
|
+
}
|
181
|
+
if(omode & DP_OSPARSE){
|
182
|
+
c = 0;
|
183
|
+
if(!dpseekwrite(fd, fsiz - 1, &c, 1)){
|
184
|
+
close(fd);
|
185
|
+
return NULL;
|
186
|
+
}
|
187
|
+
} else {
|
188
|
+
if(!(map = malloc(bnum * sizeof(int)))){
|
189
|
+
close(fd);
|
190
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
191
|
+
return NULL;
|
192
|
+
}
|
193
|
+
memset(map, 0, bnum * sizeof(int));
|
194
|
+
if(!dpseekwrite(fd, DP_HEADSIZ, map, bnum * sizeof(int))){
|
195
|
+
free(map);
|
196
|
+
close(fd);
|
197
|
+
return NULL;
|
198
|
+
}
|
199
|
+
free(map);
|
200
|
+
}
|
201
|
+
}
|
202
|
+
if(!dpseekread(fd, 0, hbuf, DP_HEADSIZ)){
|
203
|
+
close(fd);
|
204
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
205
|
+
return NULL;
|
206
|
+
}
|
207
|
+
if((dpbigendian() ? memcmp(hbuf, DP_MAGICNUMB, strlen(DP_MAGICNUMB)) != 0 :
|
208
|
+
memcmp(hbuf, DP_MAGICNUML, strlen(DP_MAGICNUML)) != 0) ||
|
209
|
+
memcmp(hbuf + DP_FSIZOFF, &fsiz, sizeof(int)) != 0){
|
210
|
+
close(fd);
|
211
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
212
|
+
return NULL;
|
213
|
+
}
|
214
|
+
bnum = *((int *)(hbuf + DP_BNUMOFF));
|
215
|
+
rnum = *((int *)(hbuf + DP_RNUMOFF));
|
216
|
+
if(bnum < 1 || rnum < 0 || fsiz < DP_HEADSIZ + bnum * sizeof(int)){
|
217
|
+
close(fd);
|
218
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
219
|
+
return NULL;
|
220
|
+
}
|
221
|
+
msiz = DP_HEADSIZ + bnum * sizeof(int);
|
222
|
+
map = mmap(0, msiz, PROT_READ | ((mode & DP_OWRITER) ? PROT_WRITE : 0), MAP_SHARED, fd, 0);
|
223
|
+
if(map == MAP_FAILED){
|
224
|
+
close(fd);
|
225
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
226
|
+
return NULL;
|
227
|
+
}
|
228
|
+
if(!(depot = malloc(sizeof(DEPOT))) || !(depot->name = dpstrdup(name))){
|
229
|
+
munmap(map, msiz);
|
230
|
+
free(depot);
|
231
|
+
close(fd);
|
232
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
233
|
+
return NULL;
|
234
|
+
}
|
235
|
+
depot->wmode = (mode & DP_OWRITER);
|
236
|
+
depot->inode = inode;
|
237
|
+
depot->mtime = mtime;
|
238
|
+
depot->fd = fd;
|
239
|
+
depot->fsiz = fsiz;
|
240
|
+
depot->map = map;
|
241
|
+
depot->msiz = msiz;
|
242
|
+
depot->buckets = (int *)(map + DP_HEADSIZ);
|
243
|
+
depot->bnum = bnum;
|
244
|
+
depot->rnum = rnum;
|
245
|
+
depot->fatal = FALSE;
|
246
|
+
depot->ioff = 0;
|
247
|
+
depot->mroff = -1;
|
248
|
+
depot->mrsiz = -1;
|
249
|
+
depot->align = 0;
|
250
|
+
return depot;
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
/* Close a database handle. */
|
255
|
+
int dpclose(DEPOT *depot){
|
256
|
+
int fatal, err;
|
257
|
+
assert(depot);
|
258
|
+
fatal = depot->fatal;
|
259
|
+
err = FALSE;
|
260
|
+
if(depot->wmode){
|
261
|
+
*((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
|
262
|
+
*((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
|
263
|
+
}
|
264
|
+
if(depot->map != MAP_FAILED){
|
265
|
+
if(munmap(depot->map, depot->msiz) == -1){
|
266
|
+
err = TRUE;
|
267
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
268
|
+
}
|
269
|
+
}
|
270
|
+
if(close(depot->fd) == -1){
|
271
|
+
err = TRUE;
|
272
|
+
dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
|
273
|
+
}
|
274
|
+
free(depot->name);
|
275
|
+
free(depot);
|
276
|
+
if(fatal){
|
277
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
278
|
+
return FALSE;
|
279
|
+
}
|
280
|
+
return err ? FALSE : TRUE;
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
/* Store a record. */
|
285
|
+
int dpput(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz, int dmode){
|
286
|
+
int head[DP_RHNUM], next[DP_RHNUM];
|
287
|
+
int i, hash, bi, off, entoff, ee, newoff, rsiz, nsiz, fdel, mroff, mrsiz;
|
288
|
+
char ebuf[DP_ENTBUFSIZ], *tval, *swap;
|
289
|
+
assert(depot && kbuf && vbuf);
|
290
|
+
if(depot->fatal){
|
291
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
292
|
+
return FALSE;
|
293
|
+
}
|
294
|
+
if(!depot->wmode){
|
295
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
296
|
+
return FALSE;
|
297
|
+
}
|
298
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
299
|
+
if(vsiz < 0) vsiz = strlen(vbuf);
|
300
|
+
newoff = -1;
|
301
|
+
hash = dpsecondhash(kbuf, ksiz);
|
302
|
+
switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, TRUE)){
|
303
|
+
case -1:
|
304
|
+
depot->fatal = TRUE;
|
305
|
+
return FALSE;
|
306
|
+
case 0:
|
307
|
+
fdel = head[DP_RHIFLAGS] & DP_RECFDEL;
|
308
|
+
if(dmode == DP_DKEEP && !fdel){
|
309
|
+
dpecodeset(DP_EKEEP, __FILE__, __LINE__);
|
310
|
+
return FALSE;
|
311
|
+
}
|
312
|
+
if(fdel){
|
313
|
+
head[DP_RHIPSIZ] += head[DP_RHIVSIZ];
|
314
|
+
head[DP_RHIVSIZ] = 0;
|
315
|
+
}
|
316
|
+
rsiz = dprecsize(head);
|
317
|
+
nsiz = DP_RHNUM * sizeof(int) + ksiz + vsiz;
|
318
|
+
if(dmode == DP_DCAT) nsiz += head[DP_RHIVSIZ];
|
319
|
+
if(off + rsiz >= depot->fsiz){
|
320
|
+
if(rsiz < nsiz){
|
321
|
+
head[DP_RHIPSIZ] += nsiz - rsiz;
|
322
|
+
rsiz = nsiz;
|
323
|
+
depot->fsiz = off + rsiz;
|
324
|
+
}
|
325
|
+
} else {
|
326
|
+
for(i = 0; i < DP_COALMAX && nsiz > rsiz && off + rsiz < depot->fsiz; i++){
|
327
|
+
if(off + rsiz == depot->mroff){
|
328
|
+
depot->mroff = -1;
|
329
|
+
depot->mrsiz = -1;
|
330
|
+
}
|
331
|
+
if(!dprechead(depot, off + rsiz, next, NULL, NULL)) return FALSE;
|
332
|
+
if(!(next[DP_RHIFLAGS] & DP_RECFREUSE)) break;
|
333
|
+
head[DP_RHIPSIZ] += dprecsize(next);
|
334
|
+
rsiz += dprecsize(next);
|
335
|
+
}
|
336
|
+
}
|
337
|
+
if(nsiz <= rsiz){
|
338
|
+
if(!dprecover(depot, off, head, vbuf, vsiz, dmode == DP_DCAT)){
|
339
|
+
depot->fatal = TRUE;
|
340
|
+
return FALSE;
|
341
|
+
}
|
342
|
+
} else {
|
343
|
+
tval = NULL;
|
344
|
+
if(dmode == DP_DCAT){
|
345
|
+
if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
|
346
|
+
if(!(tval = malloc(head[DP_RHIVSIZ] + vsiz + 1))){
|
347
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
348
|
+
depot->fatal = TRUE;
|
349
|
+
return FALSE;
|
350
|
+
}
|
351
|
+
memcpy(tval, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ]), head[DP_RHIVSIZ]);
|
352
|
+
} else {
|
353
|
+
if(!(tval = dprecval(depot, off, head, 0, -1))){
|
354
|
+
depot->fatal = TRUE;
|
355
|
+
return FALSE;
|
356
|
+
}
|
357
|
+
if(!(swap = realloc(tval, head[DP_RHIVSIZ] + vsiz + 1))){
|
358
|
+
free(tval);
|
359
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
360
|
+
depot->fatal = TRUE;
|
361
|
+
return FALSE;
|
362
|
+
}
|
363
|
+
tval = swap;
|
364
|
+
}
|
365
|
+
memcpy(tval + head[DP_RHIVSIZ], vbuf, vsiz);
|
366
|
+
vsiz += head[DP_RHIVSIZ];
|
367
|
+
vbuf = tval;
|
368
|
+
}
|
369
|
+
mroff = depot->mroff;
|
370
|
+
mrsiz = depot->mrsiz;
|
371
|
+
if(!dprecdelete(depot, off, head, TRUE)){
|
372
|
+
free(tval);
|
373
|
+
depot->fatal = TRUE;
|
374
|
+
return FALSE;
|
375
|
+
}
|
376
|
+
if(mroff > 0 && nsiz <= mrsiz){
|
377
|
+
if(!dprecrewrite(depot, mroff, mrsiz, kbuf, ksiz, vbuf, vsiz,
|
378
|
+
hash, head[DP_RHILEFT], head[DP_RHIRIGHT])){
|
379
|
+
free(tval);
|
380
|
+
depot->fatal = TRUE;
|
381
|
+
return FALSE;
|
382
|
+
}
|
383
|
+
newoff = mroff;
|
384
|
+
} else {
|
385
|
+
if((newoff = dprecappend(depot, kbuf, ksiz, vbuf, vsiz,
|
386
|
+
hash, head[DP_RHILEFT], head[DP_RHIRIGHT])) == -1){
|
387
|
+
free(tval);
|
388
|
+
depot->fatal = TRUE;
|
389
|
+
return FALSE;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
free(tval);
|
393
|
+
}
|
394
|
+
if(fdel) depot->rnum++;
|
395
|
+
break;
|
396
|
+
default:
|
397
|
+
if((newoff = dprecappend(depot, kbuf, ksiz, vbuf, vsiz, hash, 0, 0)) == -1){
|
398
|
+
depot->fatal = TRUE;
|
399
|
+
return FALSE;
|
400
|
+
}
|
401
|
+
depot->rnum++;
|
402
|
+
break;
|
403
|
+
}
|
404
|
+
if(newoff > 0){
|
405
|
+
if(entoff > 0){
|
406
|
+
if(!dpseekwritenum(depot->fd, entoff, newoff)){
|
407
|
+
depot->fatal = TRUE;
|
408
|
+
return FALSE;
|
409
|
+
}
|
410
|
+
} else {
|
411
|
+
depot->buckets[bi] = newoff;
|
412
|
+
}
|
413
|
+
}
|
414
|
+
return TRUE;
|
415
|
+
}
|
416
|
+
|
417
|
+
|
418
|
+
/* Delete a record. */
|
419
|
+
int dpout(DEPOT *depot, const char *kbuf, int ksiz){
|
420
|
+
int head[DP_RHNUM], hash, bi, off, entoff, ee;
|
421
|
+
char ebuf[DP_ENTBUFSIZ];
|
422
|
+
assert(depot && kbuf);
|
423
|
+
if(depot->fatal){
|
424
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
425
|
+
return FALSE;
|
426
|
+
}
|
427
|
+
if(!depot->wmode){
|
428
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
429
|
+
return FALSE;
|
430
|
+
}
|
431
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
432
|
+
hash = dpsecondhash(kbuf, ksiz);
|
433
|
+
switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
|
434
|
+
case -1:
|
435
|
+
depot->fatal = TRUE;
|
436
|
+
return FALSE;
|
437
|
+
case 0:
|
438
|
+
break;
|
439
|
+
default:
|
440
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
441
|
+
return FALSE;
|
442
|
+
}
|
443
|
+
if(!dprecdelete(depot, off, head, FALSE)){
|
444
|
+
depot->fatal = TRUE;
|
445
|
+
return FALSE;
|
446
|
+
}
|
447
|
+
depot->rnum--;
|
448
|
+
return TRUE;
|
449
|
+
}
|
450
|
+
|
451
|
+
|
452
|
+
/* Retrieve a record. */
|
453
|
+
char *dpget(DEPOT *depot, const char *kbuf, int ksiz, int start, int max, int *sp){
|
454
|
+
int head[DP_RHNUM], hash, bi, off, entoff, ee, vsiz;
|
455
|
+
char ebuf[DP_ENTBUFSIZ], *vbuf;
|
456
|
+
assert(depot && kbuf && start >= 0);
|
457
|
+
if(depot->fatal){
|
458
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
459
|
+
return NULL;
|
460
|
+
}
|
461
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
462
|
+
hash = dpsecondhash(kbuf, ksiz);
|
463
|
+
switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
|
464
|
+
case -1:
|
465
|
+
depot->fatal = TRUE;
|
466
|
+
return NULL;
|
467
|
+
case 0:
|
468
|
+
break;
|
469
|
+
default:
|
470
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
471
|
+
return NULL;
|
472
|
+
}
|
473
|
+
if(start > head[DP_RHIVSIZ]){
|
474
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
475
|
+
return NULL;
|
476
|
+
}
|
477
|
+
if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
|
478
|
+
head[DP_RHIVSIZ] -= start;
|
479
|
+
if(max < 0){
|
480
|
+
vsiz = head[DP_RHIVSIZ];
|
481
|
+
} else {
|
482
|
+
vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
|
483
|
+
}
|
484
|
+
if(!(vbuf = malloc(vsiz + 1))){
|
485
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
486
|
+
depot->fatal = TRUE;
|
487
|
+
return NULL;
|
488
|
+
}
|
489
|
+
memcpy(vbuf, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start), vsiz);
|
490
|
+
vbuf[vsiz] = '\0';
|
491
|
+
} else {
|
492
|
+
if(!(vbuf = dprecval(depot, off, head, start, max))){
|
493
|
+
depot->fatal = TRUE;
|
494
|
+
return NULL;
|
495
|
+
}
|
496
|
+
}
|
497
|
+
if(sp){
|
498
|
+
if(max < 0){
|
499
|
+
*sp = head[DP_RHIVSIZ];
|
500
|
+
} else {
|
501
|
+
*sp = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
|
502
|
+
}
|
503
|
+
}
|
504
|
+
return vbuf;
|
505
|
+
}
|
506
|
+
|
507
|
+
|
508
|
+
/* Retrieve a record and write the value into a buffer. */
|
509
|
+
int dpgetwb(DEPOT *depot, const char *kbuf, int ksiz, int start, int max, char *vbuf){
|
510
|
+
int head[DP_RHNUM], hash, bi, off, entoff, ee, vsiz;
|
511
|
+
char ebuf[DP_ENTBUFSIZ];
|
512
|
+
assert(depot && kbuf && start >= 0 && max >= 0 && vbuf);
|
513
|
+
if(depot->fatal){
|
514
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
515
|
+
return -1;
|
516
|
+
}
|
517
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
518
|
+
hash = dpsecondhash(kbuf, ksiz);
|
519
|
+
switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
|
520
|
+
case -1:
|
521
|
+
depot->fatal = TRUE;
|
522
|
+
return -1;
|
523
|
+
case 0:
|
524
|
+
break;
|
525
|
+
default:
|
526
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
527
|
+
return -1;
|
528
|
+
}
|
529
|
+
if(start > head[DP_RHIVSIZ]){
|
530
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
531
|
+
return -1;
|
532
|
+
}
|
533
|
+
if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
|
534
|
+
head[DP_RHIVSIZ] -= start;
|
535
|
+
vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
|
536
|
+
memcpy(vbuf, ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start), vsiz);
|
537
|
+
} else {
|
538
|
+
if((vsiz = dprecvalwb(depot, off, head, start, max, vbuf)) == -1){
|
539
|
+
depot->fatal = TRUE;
|
540
|
+
return -1;
|
541
|
+
}
|
542
|
+
}
|
543
|
+
return vsiz;
|
544
|
+
}
|
545
|
+
|
546
|
+
|
547
|
+
/* Get the size of the value of a record. */
|
548
|
+
int dpvsiz(DEPOT *depot, const char *kbuf, int ksiz){
|
549
|
+
int head[DP_RHNUM], hash, bi, off, entoff, ee;
|
550
|
+
char ebuf[DP_ENTBUFSIZ];
|
551
|
+
assert(depot && kbuf);
|
552
|
+
if(depot->fatal){
|
553
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
554
|
+
return -1;
|
555
|
+
}
|
556
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
557
|
+
hash = dpsecondhash(kbuf, ksiz);
|
558
|
+
switch(dprecsearch(depot, kbuf, ksiz, hash, &bi, &off, &entoff, head, ebuf, &ee, FALSE)){
|
559
|
+
case -1:
|
560
|
+
depot->fatal = TRUE;
|
561
|
+
return -1;
|
562
|
+
case 0:
|
563
|
+
break;
|
564
|
+
default:
|
565
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
566
|
+
return -1;
|
567
|
+
}
|
568
|
+
return head[DP_RHIVSIZ];
|
569
|
+
}
|
570
|
+
|
571
|
+
|
572
|
+
/* Initialize the iterator of a database handle. */
|
573
|
+
int dpiterinit(DEPOT *depot){
|
574
|
+
assert(depot);
|
575
|
+
if(depot->fatal){
|
576
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
577
|
+
return FALSE;
|
578
|
+
}
|
579
|
+
depot->ioff = 0;
|
580
|
+
return TRUE;
|
581
|
+
}
|
582
|
+
|
583
|
+
|
584
|
+
/* Get the next key of the iterator. */
|
585
|
+
char *dpiternext(DEPOT *depot, int *sp){
|
586
|
+
int off, head[DP_RHNUM], ee;
|
587
|
+
char ebuf[DP_ENTBUFSIZ], *kbuf;
|
588
|
+
assert(depot);
|
589
|
+
if(depot->fatal){
|
590
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
591
|
+
return NULL;
|
592
|
+
}
|
593
|
+
off = DP_HEADSIZ + depot->bnum * sizeof(int);
|
594
|
+
off = off > depot->ioff ? off : depot->ioff;
|
595
|
+
while(off < depot->fsiz){
|
596
|
+
if(!dprechead(depot, off, head, ebuf, &ee)){
|
597
|
+
depot->fatal = TRUE;
|
598
|
+
return NULL;
|
599
|
+
}
|
600
|
+
if(head[DP_RHIFLAGS] & DP_RECFDEL){
|
601
|
+
off += dprecsize(head);
|
602
|
+
} else {
|
603
|
+
if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
|
604
|
+
if(!(kbuf = malloc(head[DP_RHIKSIZ] + 1))){
|
605
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
606
|
+
depot->fatal = TRUE;
|
607
|
+
return NULL;
|
608
|
+
}
|
609
|
+
memcpy(kbuf, ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
|
610
|
+
kbuf[head[DP_RHIKSIZ]] = '\0';
|
611
|
+
} else {
|
612
|
+
if(!(kbuf = dpreckey(depot, off, head))){
|
613
|
+
depot->fatal = TRUE;
|
614
|
+
return NULL;
|
615
|
+
}
|
616
|
+
}
|
617
|
+
depot->ioff = off + dprecsize(head);
|
618
|
+
if(sp) *sp = head[DP_RHIKSIZ];
|
619
|
+
return kbuf;
|
620
|
+
}
|
621
|
+
}
|
622
|
+
dpecodeset(DP_ENOITEM, __FILE__, __LINE__);
|
623
|
+
return NULL;
|
624
|
+
}
|
625
|
+
|
626
|
+
|
627
|
+
/* Set alignment of a database handle. */
|
628
|
+
int dpsetalign(DEPOT *depot, int align){
|
629
|
+
assert(depot);
|
630
|
+
if(depot->fatal){
|
631
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
632
|
+
return FALSE;
|
633
|
+
}
|
634
|
+
if(!depot->wmode){
|
635
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
636
|
+
return FALSE;
|
637
|
+
}
|
638
|
+
depot->align = align;
|
639
|
+
return TRUE;
|
640
|
+
}
|
641
|
+
|
642
|
+
|
643
|
+
/* Synchronize contents of updating a database with the file and the device. */
|
644
|
+
int dpsync(DEPOT *depot){
|
645
|
+
assert(depot);
|
646
|
+
if(depot->fatal){
|
647
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
648
|
+
return FALSE;
|
649
|
+
}
|
650
|
+
if(!depot->wmode){
|
651
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
652
|
+
return FALSE;
|
653
|
+
}
|
654
|
+
*((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
|
655
|
+
*((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
|
656
|
+
if(msync(depot->map, depot->msiz, MS_SYNC) == -1){
|
657
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
658
|
+
depot->fatal = TRUE;
|
659
|
+
return FALSE;
|
660
|
+
}
|
661
|
+
if(fsync(depot->fd) == -1){
|
662
|
+
dpecodeset(DP_ESYNC, __FILE__, __LINE__);
|
663
|
+
depot->fatal = TRUE;
|
664
|
+
return FALSE;
|
665
|
+
}
|
666
|
+
return TRUE;
|
667
|
+
}
|
668
|
+
|
669
|
+
|
670
|
+
/* Optimize a database. */
|
671
|
+
int dpoptimize(DEPOT *depot, int bnum){
|
672
|
+
DEPOT *tdepot;
|
673
|
+
char *name;
|
674
|
+
int i, err, off, head[DP_RHNUM], ee, ksizs[DP_OPTRUNIT], vsizs[DP_OPTRUNIT], unum;
|
675
|
+
char ebuf[DP_ENTBUFSIZ], *kbufs[DP_OPTRUNIT], *vbufs[DP_OPTRUNIT];
|
676
|
+
assert(depot);
|
677
|
+
if(depot->fatal){
|
678
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
679
|
+
return FALSE;
|
680
|
+
}
|
681
|
+
if(!depot->wmode){
|
682
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
683
|
+
return FALSE;
|
684
|
+
}
|
685
|
+
if(!(name = malloc(strlen(depot->name) + strlen(DP_TMPFSUF) + 1))){
|
686
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
687
|
+
depot->fatal = FALSE;
|
688
|
+
return FALSE;
|
689
|
+
}
|
690
|
+
sprintf(name, "%s%s", depot->name, DP_TMPFSUF);
|
691
|
+
bnum = dpgetprime(bnum > 0 ? bnum : (int)(depot->rnum * (1.0 / DP_OPTBLOAD)) + 1);
|
692
|
+
if(!(tdepot = dpopen(name, DP_OWRITER | DP_OCREAT | DP_OTRUNC, bnum))){
|
693
|
+
free(name);
|
694
|
+
depot->fatal = TRUE;
|
695
|
+
return FALSE;
|
696
|
+
}
|
697
|
+
free(name);
|
698
|
+
if(!dpsetflags(tdepot, dpgetflags(depot))){
|
699
|
+
dpclose(tdepot);
|
700
|
+
depot->fatal = TRUE;
|
701
|
+
return FALSE;
|
702
|
+
}
|
703
|
+
tdepot->align = depot->align;
|
704
|
+
err = FALSE;
|
705
|
+
off = DP_HEADSIZ + depot->bnum * sizeof(int);
|
706
|
+
unum = 0;
|
707
|
+
while(off < depot->fsiz){
|
708
|
+
if(!dprechead(depot, off, head, ebuf, &ee)){
|
709
|
+
err = TRUE;
|
710
|
+
break;
|
711
|
+
}
|
712
|
+
if(!(head[DP_RHIFLAGS] & DP_RECFDEL)){
|
713
|
+
if(ee && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
|
714
|
+
if(!(kbufs[unum] = malloc(head[DP_RHIKSIZ] + 1))){
|
715
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
716
|
+
err = TRUE;
|
717
|
+
break;
|
718
|
+
}
|
719
|
+
memcpy(kbufs[unum], ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
|
720
|
+
if(DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] <= DP_ENTBUFSIZ){
|
721
|
+
if(!(vbufs[unum] = malloc(head[DP_RHIVSIZ] + 1))){
|
722
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
723
|
+
err = TRUE;
|
724
|
+
break;
|
725
|
+
}
|
726
|
+
memcpy(vbufs[unum], ebuf + (DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ]),
|
727
|
+
head[DP_RHIVSIZ]);
|
728
|
+
} else {
|
729
|
+
vbufs[unum] = dprecval(depot, off, head, 0, -1);
|
730
|
+
}
|
731
|
+
} else {
|
732
|
+
kbufs[unum] = dpreckey(depot, off, head);
|
733
|
+
vbufs[unum] = dprecval(depot, off, head, 0, -1);
|
734
|
+
}
|
735
|
+
ksizs[unum] = head[DP_RHIKSIZ];
|
736
|
+
vsizs[unum] = head[DP_RHIVSIZ];
|
737
|
+
unum++;
|
738
|
+
if(unum >= DP_OPTRUNIT){
|
739
|
+
for(i = 0; i < unum; i++){
|
740
|
+
if(kbufs[i] && vbufs[i]){
|
741
|
+
if(!dpput(tdepot, kbufs[i], ksizs[i], vbufs[i], vsizs[i], DP_DKEEP)) err = TRUE;
|
742
|
+
} else {
|
743
|
+
err = TRUE;
|
744
|
+
}
|
745
|
+
free(kbufs[i]);
|
746
|
+
free(vbufs[i]);
|
747
|
+
if(err) break;
|
748
|
+
}
|
749
|
+
unum = 0;
|
750
|
+
}
|
751
|
+
}
|
752
|
+
off += dprecsize(head);
|
753
|
+
if(err) break;
|
754
|
+
}
|
755
|
+
for(i = 0; i < unum; i++){
|
756
|
+
if(kbufs[i] && vbufs[i]){
|
757
|
+
if(!dpput(tdepot, kbufs[i], ksizs[i], vbufs[i], vsizs[i], DP_DKEEP)) err = TRUE;
|
758
|
+
} else {
|
759
|
+
err = TRUE;
|
760
|
+
}
|
761
|
+
free(kbufs[i]);
|
762
|
+
free(vbufs[i]);
|
763
|
+
if(err) break;
|
764
|
+
}
|
765
|
+
if(!dpsync(tdepot)) err = TRUE;
|
766
|
+
if(err){
|
767
|
+
unlink(tdepot->name);
|
768
|
+
dpclose(tdepot);
|
769
|
+
depot->fatal = TRUE;
|
770
|
+
return FALSE;
|
771
|
+
}
|
772
|
+
if(munmap(depot->map, depot->msiz) == -1){
|
773
|
+
dpclose(tdepot);
|
774
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
775
|
+
depot->fatal = TRUE;
|
776
|
+
return FALSE;
|
777
|
+
}
|
778
|
+
depot->map = MAP_FAILED;
|
779
|
+
if(ftruncate(depot->fd, 0) == -1){
|
780
|
+
dpclose(tdepot);
|
781
|
+
unlink(tdepot->name);
|
782
|
+
dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
|
783
|
+
depot->fatal = TRUE;
|
784
|
+
return FALSE;
|
785
|
+
}
|
786
|
+
if(dpfcopy(depot->fd, 0, tdepot->fd, 0) == -1){
|
787
|
+
dpclose(tdepot);
|
788
|
+
unlink(tdepot->name);
|
789
|
+
depot->fatal = TRUE;
|
790
|
+
return FALSE;
|
791
|
+
}
|
792
|
+
depot->fsiz = tdepot->fsiz;
|
793
|
+
depot->bnum = tdepot->bnum;
|
794
|
+
depot->ioff = 0;
|
795
|
+
depot->mroff = -1;
|
796
|
+
depot->mrsiz = -1;
|
797
|
+
depot->msiz = tdepot->msiz;
|
798
|
+
depot->map = mmap(0, depot->msiz, PROT_READ | PROT_WRITE, MAP_SHARED, depot->fd, 0);
|
799
|
+
if(depot->map == MAP_FAILED){
|
800
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
801
|
+
depot->fatal = TRUE;
|
802
|
+
return FALSE;
|
803
|
+
}
|
804
|
+
depot->buckets = (int *)(depot->map + DP_HEADSIZ);
|
805
|
+
if(!(name = dpname(tdepot))){
|
806
|
+
dpclose(tdepot);
|
807
|
+
unlink(tdepot->name);
|
808
|
+
depot->fatal = TRUE;
|
809
|
+
return FALSE;
|
810
|
+
}
|
811
|
+
if(!dpclose(tdepot)){
|
812
|
+
free(name);
|
813
|
+
unlink(tdepot->name);
|
814
|
+
depot->fatal = TRUE;
|
815
|
+
return FALSE;
|
816
|
+
}
|
817
|
+
if(unlink(name) == -1){
|
818
|
+
free(name);
|
819
|
+
dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
|
820
|
+
depot->fatal = TRUE;
|
821
|
+
return FALSE;
|
822
|
+
}
|
823
|
+
free(name);
|
824
|
+
return TRUE;
|
825
|
+
}
|
826
|
+
|
827
|
+
|
828
|
+
/* Get the name of a database. */
|
829
|
+
char *dpname(DEPOT *depot){
|
830
|
+
char *name;
|
831
|
+
assert(depot);
|
832
|
+
if(depot->fatal){
|
833
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
834
|
+
return NULL;
|
835
|
+
}
|
836
|
+
if(!(name = dpstrdup(depot->name))){
|
837
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
838
|
+
depot->fatal = TRUE;
|
839
|
+
return NULL;
|
840
|
+
}
|
841
|
+
return name;
|
842
|
+
}
|
843
|
+
|
844
|
+
|
845
|
+
/* Get the size of a database file. */
|
846
|
+
int dpfsiz(DEPOT *depot){
|
847
|
+
assert(depot);
|
848
|
+
if(depot->fatal){
|
849
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
850
|
+
return -1;
|
851
|
+
}
|
852
|
+
return depot->fsiz;
|
853
|
+
}
|
854
|
+
|
855
|
+
|
856
|
+
/* Get the number of the elements of the bucket array. */
|
857
|
+
int dpbnum(DEPOT *depot){
|
858
|
+
assert(depot);
|
859
|
+
if(depot->fatal){
|
860
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
861
|
+
return -1;
|
862
|
+
}
|
863
|
+
return depot->bnum;
|
864
|
+
}
|
865
|
+
|
866
|
+
|
867
|
+
/* Get the number of the used elements of the bucket array. */
|
868
|
+
int dpbusenum(DEPOT *depot){
|
869
|
+
int i, hits;
|
870
|
+
assert(depot);
|
871
|
+
if(depot->fatal){
|
872
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
873
|
+
return -1;
|
874
|
+
}
|
875
|
+
hits = 0;
|
876
|
+
for(i = 0; i < depot->bnum; i++){
|
877
|
+
if(depot->buckets[i]) hits++;
|
878
|
+
}
|
879
|
+
return hits;
|
880
|
+
}
|
881
|
+
|
882
|
+
|
883
|
+
/* Get the number of the records stored in a database. */
|
884
|
+
int dprnum(DEPOT *depot){
|
885
|
+
assert(depot);
|
886
|
+
if(depot->fatal){
|
887
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
888
|
+
return -1;
|
889
|
+
}
|
890
|
+
return depot->rnum;
|
891
|
+
}
|
892
|
+
|
893
|
+
|
894
|
+
/* Check whether a database handle is a writer or not. */
|
895
|
+
int dpwritable(DEPOT *depot){
|
896
|
+
assert(depot);
|
897
|
+
return depot->wmode;
|
898
|
+
}
|
899
|
+
|
900
|
+
|
901
|
+
/* Check whether a database has a fatal error or not. */
|
902
|
+
int dpfatalerror(DEPOT *depot){
|
903
|
+
assert(depot);
|
904
|
+
return depot->fatal;
|
905
|
+
}
|
906
|
+
|
907
|
+
|
908
|
+
/* Get the inode number of a database file. */
|
909
|
+
int dpinode(DEPOT *depot){
|
910
|
+
assert(depot);
|
911
|
+
return depot->inode;
|
912
|
+
}
|
913
|
+
|
914
|
+
|
915
|
+
/* Get the last modified time of a database. */
|
916
|
+
int dpmtime(DEPOT *depot){
|
917
|
+
assert(depot);
|
918
|
+
return depot->mtime;
|
919
|
+
}
|
920
|
+
|
921
|
+
|
922
|
+
/* Get the file descriptor of a database file. */
|
923
|
+
int dpfdesc(DEPOT *depot){
|
924
|
+
assert(depot);
|
925
|
+
return depot->fd;
|
926
|
+
}
|
927
|
+
|
928
|
+
|
929
|
+
/* Remove a database file. */
|
930
|
+
int dpremove(const char *name){
|
931
|
+
struct stat sbuf;
|
932
|
+
DEPOT *depot;
|
933
|
+
assert(name);
|
934
|
+
if(stat(name, &sbuf) == -1){
|
935
|
+
dpecodeset(DP_ESTAT, __FILE__, __LINE__);
|
936
|
+
return FALSE;
|
937
|
+
}
|
938
|
+
if((depot = dpopen(name, DP_OWRITER | DP_OTRUNC, -1)) != NULL) dpclose(depot);
|
939
|
+
if(unlink(name) == -1){
|
940
|
+
dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
|
941
|
+
return FALSE;
|
942
|
+
}
|
943
|
+
return TRUE;
|
944
|
+
}
|
945
|
+
|
946
|
+
|
947
|
+
/* Repair a broken database file. */
|
948
|
+
int dprepair(const char *name){
|
949
|
+
DEPOT *tdepot;
|
950
|
+
char dbhead[DP_HEADSIZ], *tname, *kbuf, *vbuf;
|
951
|
+
int fd, fsiz, flags, bnum, tbnum, err, head[DP_RHNUM], off, rsiz, ksiz, vsiz;
|
952
|
+
struct stat sbuf;
|
953
|
+
assert(name);
|
954
|
+
if(stat(name, &sbuf) == -1){
|
955
|
+
dpecodeset(DP_ESTAT, __FILE__, __LINE__);
|
956
|
+
return FALSE;
|
957
|
+
}
|
958
|
+
fsiz = sbuf.st_size;
|
959
|
+
if((fd = open(name, O_RDWR, DP_FILEMODE)) == -1){
|
960
|
+
dpecodeset(DP_EOPEN, __FILE__, __LINE__);
|
961
|
+
return FALSE;
|
962
|
+
}
|
963
|
+
if(!dpseekread(fd, 0, dbhead, DP_HEADSIZ)){
|
964
|
+
close(fd);
|
965
|
+
return FALSE;
|
966
|
+
}
|
967
|
+
flags = *(int *)(dbhead + DP_FLAGSOFF);
|
968
|
+
bnum = *(int *)(dbhead + DP_BNUMOFF);
|
969
|
+
tbnum = *(int *)(dbhead + DP_RNUMOFF) * 2;
|
970
|
+
if(tbnum < DP_DEFBNUM) tbnum = DP_DEFBNUM;
|
971
|
+
if(!(tname = malloc(strlen(name) + strlen(DP_TMPFSUF) + 1))){
|
972
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
973
|
+
return FALSE;
|
974
|
+
}
|
975
|
+
sprintf(tname, "%s%s", name, DP_TMPFSUF);
|
976
|
+
if(!(tdepot = dpopen(tname, DP_OWRITER | DP_OCREAT | DP_OTRUNC, tbnum))){
|
977
|
+
free(tname);
|
978
|
+
close(fd);
|
979
|
+
return FALSE;
|
980
|
+
}
|
981
|
+
err = FALSE;
|
982
|
+
off = DP_HEADSIZ + bnum * sizeof(int);
|
983
|
+
while(off < fsiz){
|
984
|
+
if(!dpseekread(fd, off, head, DP_RHNUM * sizeof(int))) break;
|
985
|
+
if(head[DP_RHIFLAGS] & DP_RECFDEL){
|
986
|
+
if((rsiz = dprecsize(head)) < 0) break;
|
987
|
+
off += rsiz;
|
988
|
+
continue;
|
989
|
+
}
|
990
|
+
ksiz = head[DP_RHIKSIZ];
|
991
|
+
vsiz = head[DP_RHIVSIZ];
|
992
|
+
if(ksiz >= 0 && vsiz >= 0){
|
993
|
+
kbuf = malloc(ksiz + 1);
|
994
|
+
vbuf = malloc(vsiz + 1);
|
995
|
+
if(kbuf && vbuf){
|
996
|
+
if(dpseekread(fd, off + DP_RHNUM * sizeof(int), kbuf, ksiz) &&
|
997
|
+
dpseekread(fd, off + DP_RHNUM * sizeof(int) + ksiz, vbuf, vsiz)){
|
998
|
+
if(!dpput(tdepot, kbuf, ksiz, vbuf, vsiz, DP_DKEEP)) err = TRUE;
|
999
|
+
} else {
|
1000
|
+
err = TRUE;
|
1001
|
+
}
|
1002
|
+
} else {
|
1003
|
+
if(!err) dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1004
|
+
err = TRUE;
|
1005
|
+
}
|
1006
|
+
free(vbuf);
|
1007
|
+
free(kbuf);
|
1008
|
+
} else {
|
1009
|
+
if(!err) dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
1010
|
+
err = TRUE;
|
1011
|
+
}
|
1012
|
+
if((rsiz = dprecsize(head)) < 0) break;
|
1013
|
+
off += rsiz;
|
1014
|
+
}
|
1015
|
+
if(!dpsetflags(tdepot, flags)) err = TRUE;
|
1016
|
+
if(!dpsync(tdepot)) err = TRUE;
|
1017
|
+
if(ftruncate(fd, 0) == -1){
|
1018
|
+
if(!err) dpecodeset(DP_ETRUNC, __FILE__, __LINE__);
|
1019
|
+
err = TRUE;
|
1020
|
+
}
|
1021
|
+
if(dpfcopy(fd, 0, tdepot->fd, 0) == -1) err = TRUE;
|
1022
|
+
if(!dpclose(tdepot)) err = TRUE;
|
1023
|
+
if(close(fd) == -1){
|
1024
|
+
if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
|
1025
|
+
err = TRUE;
|
1026
|
+
}
|
1027
|
+
if(unlink(tname) == -1){
|
1028
|
+
if(!err) dpecodeset(DP_EUNLINK, __FILE__, __LINE__);
|
1029
|
+
err = TRUE;
|
1030
|
+
}
|
1031
|
+
free(tname);
|
1032
|
+
return err ? FALSE : TRUE;
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
|
1036
|
+
/* Dump all records as endian independent data. */
|
1037
|
+
int dpexportdb(DEPOT *depot, const char *name){
|
1038
|
+
char *kbuf, *vbuf, *pbuf;
|
1039
|
+
int fd, err, ksiz, vsiz, psiz;
|
1040
|
+
assert(depot && name);
|
1041
|
+
if(!(dpiterinit(depot))) return FALSE;
|
1042
|
+
if((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, DP_FILEMODE)) == -1){
|
1043
|
+
dpecodeset(DP_EOPEN, __FILE__, __LINE__);
|
1044
|
+
return FALSE;
|
1045
|
+
}
|
1046
|
+
err = FALSE;
|
1047
|
+
while(!err && (kbuf = dpiternext(depot, &ksiz)) != NULL){
|
1048
|
+
if((vbuf = dpget(depot, kbuf, ksiz, 0, -1, &vsiz)) != NULL){
|
1049
|
+
if((pbuf = malloc(ksiz + vsiz + DP_NUMBUFSIZ * 2)) != NULL){
|
1050
|
+
psiz = 0;
|
1051
|
+
psiz += sprintf(pbuf + psiz, "%X\n%X\n", ksiz, vsiz);
|
1052
|
+
memcpy(pbuf + psiz, kbuf, ksiz);
|
1053
|
+
psiz += ksiz;
|
1054
|
+
pbuf[psiz++] = '\n';
|
1055
|
+
memcpy(pbuf + psiz, vbuf, vsiz);
|
1056
|
+
psiz += vsiz;
|
1057
|
+
pbuf[psiz++] = '\n';
|
1058
|
+
if(!dpwrite(fd, pbuf, psiz)){
|
1059
|
+
dpecodeset(DP_EWRITE, __FILE__, __LINE__);
|
1060
|
+
err = TRUE;
|
1061
|
+
}
|
1062
|
+
free(pbuf);
|
1063
|
+
} else {
|
1064
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1065
|
+
err = TRUE;
|
1066
|
+
}
|
1067
|
+
free(vbuf);
|
1068
|
+
} else {
|
1069
|
+
err = TRUE;
|
1070
|
+
}
|
1071
|
+
free(kbuf);
|
1072
|
+
}
|
1073
|
+
if(close(fd) == -1){
|
1074
|
+
if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
|
1075
|
+
return FALSE;
|
1076
|
+
}
|
1077
|
+
return !err && !dpfatalerror(depot);
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
|
1081
|
+
/* Load all records from endian independent data. */
|
1082
|
+
int dpimportdb(DEPOT *depot, const char *name){
|
1083
|
+
char mbuf[DP_IOBUFSIZ], *rbuf;
|
1084
|
+
int i, j, fd, err, fsiz, off, msiz, ksiz, vsiz, hlen;
|
1085
|
+
struct stat sbuf;
|
1086
|
+
assert(depot && name);
|
1087
|
+
if(!depot->wmode){
|
1088
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
1089
|
+
return FALSE;
|
1090
|
+
}
|
1091
|
+
if(dprnum(depot) > 0){
|
1092
|
+
dpecodeset(DP_EMISC, __FILE__, __LINE__);
|
1093
|
+
return FALSE;
|
1094
|
+
}
|
1095
|
+
if((fd = open(name, O_RDONLY, DP_FILEMODE)) == -1){
|
1096
|
+
dpecodeset(DP_EOPEN, __FILE__, __LINE__);
|
1097
|
+
return FALSE;
|
1098
|
+
}
|
1099
|
+
if(fstat(fd, &sbuf) == -1 || !S_ISREG(sbuf.st_mode)){
|
1100
|
+
dpecodeset(DP_ESTAT, __FILE__, __LINE__);
|
1101
|
+
close(fd);
|
1102
|
+
return FALSE;
|
1103
|
+
}
|
1104
|
+
err = FALSE;
|
1105
|
+
fsiz = sbuf.st_size;
|
1106
|
+
off = 0;
|
1107
|
+
while(!err && off < fsiz){
|
1108
|
+
msiz = fsiz - off;
|
1109
|
+
if(msiz > DP_IOBUFSIZ) msiz = DP_IOBUFSIZ;
|
1110
|
+
if(!dpseekread(fd, off, mbuf, msiz)){
|
1111
|
+
err = TRUE;
|
1112
|
+
break;
|
1113
|
+
}
|
1114
|
+
hlen = 0;
|
1115
|
+
ksiz = -1;
|
1116
|
+
vsiz = -1;
|
1117
|
+
for(i = 0; i < msiz; i++){
|
1118
|
+
if(mbuf[i] == '\n'){
|
1119
|
+
mbuf[i] = '\0';
|
1120
|
+
ksiz = strtol(mbuf, NULL, 16);
|
1121
|
+
for(j = i + 1; j < msiz; j++){
|
1122
|
+
if(mbuf[j] == '\n'){
|
1123
|
+
mbuf[j] = '\0';
|
1124
|
+
vsiz = strtol(mbuf + i + 1, NULL, 16);
|
1125
|
+
hlen = j + 1;
|
1126
|
+
break;
|
1127
|
+
}
|
1128
|
+
}
|
1129
|
+
break;
|
1130
|
+
}
|
1131
|
+
}
|
1132
|
+
if(ksiz < 0 || vsiz < 0 || hlen < 4){
|
1133
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
1134
|
+
err = TRUE;
|
1135
|
+
break;
|
1136
|
+
}
|
1137
|
+
if(hlen + ksiz + vsiz + 2 < DP_IOBUFSIZ){
|
1138
|
+
if(!dpput(depot, mbuf + hlen, ksiz, mbuf + hlen + ksiz + 1, vsiz, DP_DKEEP)) err = TRUE;
|
1139
|
+
} else {
|
1140
|
+
if((rbuf = malloc(ksiz + vsiz + 2)) != NULL){
|
1141
|
+
if(dpseekread(fd, off + hlen, rbuf, ksiz + vsiz + 2)){
|
1142
|
+
if(!dpput(depot, rbuf, ksiz, rbuf + ksiz + 1, vsiz, DP_DKEEP)) err = TRUE;
|
1143
|
+
} else {
|
1144
|
+
err = TRUE;
|
1145
|
+
}
|
1146
|
+
free(rbuf);
|
1147
|
+
} else {
|
1148
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1149
|
+
err = TRUE;
|
1150
|
+
}
|
1151
|
+
}
|
1152
|
+
off += hlen + ksiz + vsiz + 2;
|
1153
|
+
}
|
1154
|
+
if(close(fd) == -1){
|
1155
|
+
if(!err) dpecodeset(DP_ECLOSE, __FILE__, __LINE__);
|
1156
|
+
return FALSE;
|
1157
|
+
}
|
1158
|
+
return !err && !dpfatalerror(depot);
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
|
1162
|
+
/* Hash function used inside Depot. */
|
1163
|
+
int dpinnerhash(const char *kbuf, int ksiz){
|
1164
|
+
assert(kbuf);
|
1165
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
1166
|
+
return dpfirsthash(kbuf, ksiz);
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
|
1170
|
+
/* Hash function which is independent from the hash functions used inside Depot. */
|
1171
|
+
int dpouterhash(const char *kbuf, int ksiz){
|
1172
|
+
assert(kbuf);
|
1173
|
+
if(ksiz < 0) ksiz = strlen(kbuf);
|
1174
|
+
return dpthirdhash(kbuf, ksiz);
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
|
1178
|
+
/* Get a natural prime number not less than a number. */
|
1179
|
+
int dpprimenum(int num){
|
1180
|
+
assert(num > 0);
|
1181
|
+
return dpgetprime(num);
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
|
1185
|
+
|
1186
|
+
/*************************************************************************************************
|
1187
|
+
* features for experts
|
1188
|
+
*************************************************************************************************/
|
1189
|
+
|
1190
|
+
|
1191
|
+
/* Name of the operating system. */
|
1192
|
+
char *dpsysname = _QDBM_SYSNAME;
|
1193
|
+
|
1194
|
+
|
1195
|
+
/* File descriptor for debugging output. */
|
1196
|
+
int dpdbgfd = -1;
|
1197
|
+
|
1198
|
+
|
1199
|
+
/* Set the last happened error code. */
|
1200
|
+
void dpecodeset(int ecode, const char *file, int line){
|
1201
|
+
char iobuf[DP_IOBUFSIZ];
|
1202
|
+
assert(ecode >= DP_ENOERR && file && line >= 0);
|
1203
|
+
dpecode = ecode;
|
1204
|
+
if(dpdbgfd >= 0){
|
1205
|
+
fflush(stdout);
|
1206
|
+
fflush(stderr);
|
1207
|
+
sprintf(iobuf, "* dpecodeset: %s:%d: [%d] %s\n", file, line, ecode, dperrmsg(ecode));
|
1208
|
+
dpwrite(dpdbgfd, iobuf, strlen(iobuf));
|
1209
|
+
}
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
|
1213
|
+
/* Get the pointer of the variable of the last happened error code. */
|
1214
|
+
int *dpecodeptr(void){
|
1215
|
+
static int defdpecode = DP_ENOERR;
|
1216
|
+
void *ptr;
|
1217
|
+
if(_qdbm_ptsafe){
|
1218
|
+
if(!(ptr = _qdbm_settsd(&defdpecode, sizeof(int), &defdpecode))){
|
1219
|
+
defdpecode = DP_EMISC;
|
1220
|
+
return &defdpecode;
|
1221
|
+
}
|
1222
|
+
return (int *)ptr;
|
1223
|
+
}
|
1224
|
+
return &defdpecode;
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
|
1228
|
+
/* Synchronize updating contents on memory. */
|
1229
|
+
int dpmemsync(DEPOT *depot){
|
1230
|
+
assert(depot);
|
1231
|
+
if(depot->fatal){
|
1232
|
+
dpecodeset(DP_EFATAL, __FILE__, __LINE__);
|
1233
|
+
return FALSE;
|
1234
|
+
}
|
1235
|
+
if(!depot->wmode){
|
1236
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
1237
|
+
return FALSE;
|
1238
|
+
}
|
1239
|
+
*((int *)(depot->map + DP_FSIZOFF)) = depot->fsiz;
|
1240
|
+
*((int *)(depot->map + DP_RNUMOFF)) = depot->rnum;
|
1241
|
+
if(msync(depot->map, depot->msiz, MS_SYNC) == -1){
|
1242
|
+
dpecodeset(DP_EMAP, __FILE__, __LINE__);
|
1243
|
+
depot->fatal = TRUE;
|
1244
|
+
return FALSE;
|
1245
|
+
}
|
1246
|
+
return TRUE;
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
|
1250
|
+
/* Get flags of a database. */
|
1251
|
+
int dpgetflags(DEPOT *depot){
|
1252
|
+
assert(depot);
|
1253
|
+
return *(depot->map + DP_FLAGSOFF);
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
|
1257
|
+
/* Set flags of a database. */
|
1258
|
+
int dpsetflags(DEPOT *depot, int flags){
|
1259
|
+
assert(depot);
|
1260
|
+
if(!depot->wmode){
|
1261
|
+
dpecodeset(DP_EMODE, __FILE__, __LINE__);
|
1262
|
+
return FALSE;
|
1263
|
+
}
|
1264
|
+
*(depot->map + DP_FLAGSOFF) = flags;
|
1265
|
+
return TRUE;
|
1266
|
+
}
|
1267
|
+
|
1268
|
+
|
1269
|
+
|
1270
|
+
/*************************************************************************************************
|
1271
|
+
* private objects
|
1272
|
+
*************************************************************************************************/
|
1273
|
+
|
1274
|
+
|
1275
|
+
/* Check whether the byte order of the platform is big endian or not.
|
1276
|
+
The return value is true if bigendian, else, it is false. */
|
1277
|
+
static int dpbigendian(void){
|
1278
|
+
char buf[sizeof(int)];
|
1279
|
+
*(int *)buf = 1;
|
1280
|
+
return !buf[0];
|
1281
|
+
}
|
1282
|
+
|
1283
|
+
|
1284
|
+
/* Get a copied string.
|
1285
|
+
`str' specifies an original string.
|
1286
|
+
The return value is a copied string whose region is allocated by `malloc'. */
|
1287
|
+
static char *dpstrdup(const char *str){
|
1288
|
+
int len;
|
1289
|
+
char *buf;
|
1290
|
+
assert(str);
|
1291
|
+
len = strlen(str);
|
1292
|
+
if(!(buf = malloc(len + 1))) return NULL;
|
1293
|
+
memcpy(buf, str, len + 1);
|
1294
|
+
return buf;
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
|
1298
|
+
/* Lock a file descriptor.
|
1299
|
+
`fd' specifies a file descriptor.
|
1300
|
+
`ex' specifies whether an exclusive lock or a shared lock is performed.
|
1301
|
+
The return value is true if successful, else, it is false. */
|
1302
|
+
static int dplock(int fd, int ex){
|
1303
|
+
struct flock lock;
|
1304
|
+
assert(fd >= 0);
|
1305
|
+
memset(&lock, 0, sizeof(struct flock));
|
1306
|
+
lock.l_type = ex ? F_WRLCK : F_RDLCK;
|
1307
|
+
lock.l_whence = SEEK_SET;
|
1308
|
+
lock.l_start = 0;
|
1309
|
+
lock.l_len = 0;
|
1310
|
+
lock.l_pid = 0;
|
1311
|
+
while(fcntl(fd, F_SETLKW, &lock) == -1){
|
1312
|
+
if(errno != EINTR){
|
1313
|
+
dpecodeset(DP_ELOCK, __FILE__, __LINE__);
|
1314
|
+
return FALSE;
|
1315
|
+
}
|
1316
|
+
}
|
1317
|
+
return TRUE;
|
1318
|
+
}
|
1319
|
+
|
1320
|
+
|
1321
|
+
/* Write into a file.
|
1322
|
+
`fd' specifies a file descriptor.
|
1323
|
+
`buf' specifies a buffer to write.
|
1324
|
+
`size' specifies the size of the buffer.
|
1325
|
+
The return value is the size of the written buffer, or, -1 on failure. */
|
1326
|
+
static int dpwrite(int fd, const void *buf, int size){
|
1327
|
+
const char *lbuf;
|
1328
|
+
int rv, wb;
|
1329
|
+
assert(fd >= 0 && buf && size >= 0);
|
1330
|
+
lbuf = buf;
|
1331
|
+
rv = 0;
|
1332
|
+
do {
|
1333
|
+
wb = write(fd, lbuf, size);
|
1334
|
+
switch(wb){
|
1335
|
+
case -1: if(errno != EINTR) return -1;
|
1336
|
+
case 0: break;
|
1337
|
+
default:
|
1338
|
+
lbuf += wb;
|
1339
|
+
size -= wb;
|
1340
|
+
rv += wb;
|
1341
|
+
break;
|
1342
|
+
}
|
1343
|
+
} while(size > 0);
|
1344
|
+
return rv;
|
1345
|
+
}
|
1346
|
+
|
1347
|
+
|
1348
|
+
/* Write into a file at an offset.
|
1349
|
+
`fd' specifies a file descriptor.
|
1350
|
+
`off' specifies an offset of the file.
|
1351
|
+
`buf' specifies a buffer to write.
|
1352
|
+
`size' specifies the size of the buffer.
|
1353
|
+
The return value is true if successful, else, it is false. */
|
1354
|
+
static int dpseekwrite(int fd, int off, const void *buf, int size){
|
1355
|
+
assert(fd >= 0 && buf && size >= 0);
|
1356
|
+
if(size < 1) return TRUE;
|
1357
|
+
if(off < 0){
|
1358
|
+
if(lseek(fd, 0, SEEK_END) == -1){
|
1359
|
+
dpecodeset(DP_ESEEK, __FILE__, __LINE__);
|
1360
|
+
return FALSE;
|
1361
|
+
}
|
1362
|
+
} else {
|
1363
|
+
if(lseek(fd, off, SEEK_SET) != off){
|
1364
|
+
dpecodeset(DP_ESEEK, __FILE__, __LINE__);
|
1365
|
+
return FALSE;
|
1366
|
+
}
|
1367
|
+
}
|
1368
|
+
if(dpwrite(fd, buf, size) != size){
|
1369
|
+
dpecodeset(DP_EWRITE, __FILE__, __LINE__);
|
1370
|
+
return FALSE;
|
1371
|
+
}
|
1372
|
+
return TRUE;
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
|
1376
|
+
/* Write an integer into a file at an offset.
|
1377
|
+
`fd' specifies a file descriptor.
|
1378
|
+
`off' specifies an offset of the file.
|
1379
|
+
`num' specifies an integer.
|
1380
|
+
The return value is true if successful, else, it is false. */
|
1381
|
+
static int dpseekwritenum(int fd, int off, int num){
|
1382
|
+
assert(fd >= 0);
|
1383
|
+
return dpseekwrite(fd, off, &num, sizeof(int));
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
|
1387
|
+
/* Read from a file and store the data into a buffer.
|
1388
|
+
`fd' specifies a file descriptor.
|
1389
|
+
`buffer' specifies a buffer to store into.
|
1390
|
+
`size' specifies the size to read with.
|
1391
|
+
The return value is the size read with, or, -1 on failure. */
|
1392
|
+
static int dpread(int fd, void *buf, int size){
|
1393
|
+
char *lbuf;
|
1394
|
+
int i, bs;
|
1395
|
+
assert(fd >= 0 && buf && size >= 0);
|
1396
|
+
lbuf = buf;
|
1397
|
+
for(i = 0; i < size && (bs = read(fd, lbuf + i, size - i)) != 0; i += bs){
|
1398
|
+
if(bs == -1 && errno != EINTR) return -1;
|
1399
|
+
}
|
1400
|
+
return i;
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
|
1404
|
+
/* Read from a file at an offset and store the data into a buffer.
|
1405
|
+
`fd' specifies a file descriptor.
|
1406
|
+
`off' specifies an offset of the file.
|
1407
|
+
`buffer' specifies a buffer to store into.
|
1408
|
+
`size' specifies the size to read with.
|
1409
|
+
The return value is true if successful, else, it is false. */
|
1410
|
+
static int dpseekread(int fd, int off, void *buf, int size){
|
1411
|
+
char *lbuf;
|
1412
|
+
assert(fd >= 0 && off >= 0 && buf && size >= 0);
|
1413
|
+
lbuf = (char *)buf;
|
1414
|
+
if(lseek(fd, off, SEEK_SET) != off){
|
1415
|
+
dpecodeset(DP_ESEEK, __FILE__, __LINE__);
|
1416
|
+
return FALSE;
|
1417
|
+
}
|
1418
|
+
if(dpread(fd, lbuf, size) != size){
|
1419
|
+
dpecodeset(DP_EREAD, __FILE__, __LINE__);
|
1420
|
+
return FALSE;
|
1421
|
+
}
|
1422
|
+
return TRUE;
|
1423
|
+
}
|
1424
|
+
|
1425
|
+
|
1426
|
+
/* Copy data between files.
|
1427
|
+
`destfd' specifies a file descriptor of a destination file.
|
1428
|
+
`destoff' specifies an offset of the destination file.
|
1429
|
+
`srcfd' specifies a file descriptor of a source file.
|
1430
|
+
`srcoff' specifies an offset of the source file.
|
1431
|
+
The return value is the size copied with, or, -1 on failure. */
|
1432
|
+
static int dpfcopy(int destfd, int destoff, int srcfd, int srcoff){
|
1433
|
+
char iobuf[DP_IOBUFSIZ];
|
1434
|
+
int sum, iosiz;
|
1435
|
+
if(lseek(srcfd, srcoff, SEEK_SET) == -1 || lseek(destfd, destoff, SEEK_SET) == -1){
|
1436
|
+
dpecodeset(DP_ESEEK, __FILE__, __LINE__);
|
1437
|
+
return -1;
|
1438
|
+
}
|
1439
|
+
sum = 0;
|
1440
|
+
while((iosiz = dpread(srcfd, iobuf, DP_IOBUFSIZ)) > 0){
|
1441
|
+
if(dpwrite(destfd, iobuf, iosiz) == -1){
|
1442
|
+
dpecodeset(DP_EWRITE, __FILE__, __LINE__);
|
1443
|
+
return -1;
|
1444
|
+
}
|
1445
|
+
sum += iosiz;
|
1446
|
+
}
|
1447
|
+
if(iosiz < 0){
|
1448
|
+
dpecodeset(DP_EREAD, __FILE__, __LINE__);
|
1449
|
+
return -1;
|
1450
|
+
}
|
1451
|
+
return sum;
|
1452
|
+
}
|
1453
|
+
|
1454
|
+
|
1455
|
+
/* Get the first hash value.
|
1456
|
+
`kbuf' specifies the pointer to the region of a key.
|
1457
|
+
`ksiz' specifies the size of the key.
|
1458
|
+
The return value is 31 bit hash value of the key. */
|
1459
|
+
static int dpfirsthash(const char *kbuf, int ksiz){
|
1460
|
+
unsigned int sum;
|
1461
|
+
int i;
|
1462
|
+
assert(kbuf && ksiz >= 0);
|
1463
|
+
if(ksiz == sizeof(int)){
|
1464
|
+
memcpy(&sum, kbuf, sizeof(int));
|
1465
|
+
} else {
|
1466
|
+
sum = 751;
|
1467
|
+
}
|
1468
|
+
for(i = 0; i < ksiz; i++){
|
1469
|
+
sum = sum * 31 + ((const unsigned char *)kbuf)[i];
|
1470
|
+
}
|
1471
|
+
return (sum * 87767623) & 0x7FFFFFFF;
|
1472
|
+
}
|
1473
|
+
|
1474
|
+
|
1475
|
+
/* Get the second hash value.
|
1476
|
+
`kbuf' specifies the pointer to the region of a key.
|
1477
|
+
`ksiz' specifies the size of the key.
|
1478
|
+
The return value is 31 bit hash value of the key. */
|
1479
|
+
static int dpsecondhash(const char *kbuf, int ksiz){
|
1480
|
+
unsigned int sum;
|
1481
|
+
int i;
|
1482
|
+
assert(kbuf && ksiz >= 0);
|
1483
|
+
sum = 19780211;
|
1484
|
+
for(i = ksiz - 1; i >= 0; i--){
|
1485
|
+
sum = sum * 37 + ((const unsigned char *)kbuf)[i];
|
1486
|
+
}
|
1487
|
+
return (sum * 43321879) & 0x7FFFFFFF;
|
1488
|
+
}
|
1489
|
+
|
1490
|
+
|
1491
|
+
/* Get the third hash value.
|
1492
|
+
`kbuf' specifies the pointer to the region of a key.
|
1493
|
+
`ksiz' specifies the size of the key.
|
1494
|
+
The return value is 31 bit hash value of the key. */
|
1495
|
+
static int dpthirdhash(const char *kbuf, int ksiz){
|
1496
|
+
unsigned int sum;
|
1497
|
+
int i;
|
1498
|
+
assert(kbuf && ksiz >= 0);
|
1499
|
+
sum = 774831917;
|
1500
|
+
for(i = ksiz - 1; i >= 0; i--){
|
1501
|
+
sum = sum * 29 + ((const unsigned char *)kbuf)[i];
|
1502
|
+
}
|
1503
|
+
return (sum * 5157883) & 0x7FFFFFFF;
|
1504
|
+
}
|
1505
|
+
|
1506
|
+
|
1507
|
+
/* Get a natural prime number not less than a number.
|
1508
|
+
`num' specified a natural number.
|
1509
|
+
The return value is a prime number not less than the specified number. */
|
1510
|
+
static int dpgetprime(int num){
|
1511
|
+
int primes[] = {
|
1512
|
+
1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 43, 47, 53, 59, 61, 71, 79, 83,
|
1513
|
+
89, 103, 109, 113, 127, 139, 157, 173, 191, 199, 223, 239, 251, 283, 317, 349,
|
1514
|
+
383, 409, 443, 479, 509, 571, 631, 701, 761, 829, 887, 953, 1021, 1151, 1279,
|
1515
|
+
1399, 1531, 1663, 1789, 1913, 2039, 2297, 2557, 2803, 3067, 3323, 3583, 3833,
|
1516
|
+
4093, 4603, 5119, 5623, 6143, 6653, 7159, 7673, 8191, 9209, 10223, 11261,
|
1517
|
+
12281, 13309, 14327, 15359, 16381, 18427, 20479, 22511, 24571, 26597, 28669,
|
1518
|
+
30713, 32749, 36857, 40949, 45053, 49139, 53239, 57331, 61417, 65521, 73727,
|
1519
|
+
81919, 90107, 98299, 106487, 114679, 122869, 131071, 147451, 163819, 180221,
|
1520
|
+
196597, 212987, 229373, 245759, 262139, 294911, 327673, 360439, 393209, 425977,
|
1521
|
+
458747, 491503, 524287, 589811, 655357, 720887, 786431, 851957, 917503, 982981,
|
1522
|
+
1048573, 1179641, 1310719, 1441771, 1572853, 1703903, 1835003, 1966079,
|
1523
|
+
2097143, 2359267, 2621431, 2883577, 3145721, 3407857, 3670013, 3932153,
|
1524
|
+
4194301, 4718579, 5242877, 5767129, 6291449, 6815741, 7340009, 7864301,
|
1525
|
+
8388593, 9437179, 10485751, 11534329, 12582893, 13631477, 14680063, 15728611,
|
1526
|
+
16777213, 18874367, 20971507, 23068667, 25165813, 27262931, 29360087, 31457269,
|
1527
|
+
33554393, 37748717, 41943023, 46137319, 50331599, 54525917, 58720253, 62914549,
|
1528
|
+
67108859, 75497467, 83886053, 92274671, 100663291, 109051903, 117440509,
|
1529
|
+
125829103, 134217689, 150994939, 167772107, 184549373, 201326557, 218103799,
|
1530
|
+
234881011, 251658227, 268435399, 301989881, 335544301, 369098707, 402653171,
|
1531
|
+
436207613, 469762043, 503316469, 536870909, 603979769, 671088637, 738197503,
|
1532
|
+
805306357, 872415211, 939524087, 1006632947, 1073741789, 1207959503,
|
1533
|
+
1342177237, 1476394991, 1610612711, 1744830457, 1879048183, 2013265907, -1
|
1534
|
+
};
|
1535
|
+
int i;
|
1536
|
+
assert(num > 0);
|
1537
|
+
for(i = 0; primes[i] > 0; i++){
|
1538
|
+
if(num <= primes[i]) return primes[i];
|
1539
|
+
}
|
1540
|
+
return primes[i-1];
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
|
1544
|
+
/* Get the padding size of a record.
|
1545
|
+
`vsiz' specifies the size of the value of a record.
|
1546
|
+
The return value is the padding size of a record. */
|
1547
|
+
static int dppadsize(DEPOT *depot, int vsiz){
|
1548
|
+
int mod, pad;
|
1549
|
+
assert(depot && vsiz >= 0);
|
1550
|
+
if(depot->align > 0){
|
1551
|
+
mod = vsiz % depot->align;
|
1552
|
+
return mod == 0 ? 0 : depot->align - mod;
|
1553
|
+
} else if(depot->align < 0){
|
1554
|
+
pad = (int)(vsiz * (2.0 / (1 << -(depot->align))));
|
1555
|
+
return pad >= DP_RHNUM * sizeof(int) ? pad : DP_RHNUM * sizeof(int);
|
1556
|
+
}
|
1557
|
+
return 0;
|
1558
|
+
}
|
1559
|
+
|
1560
|
+
|
1561
|
+
/* Get the size of a record in a database file.
|
1562
|
+
`head' specifies the header of a record.
|
1563
|
+
The return value is the size of a record in a database file. */
|
1564
|
+
static int dprecsize(int *head){
|
1565
|
+
assert(head);
|
1566
|
+
return DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] + head[DP_RHIPSIZ];
|
1567
|
+
}
|
1568
|
+
|
1569
|
+
|
1570
|
+
/* Read the header of a record.
|
1571
|
+
`depot' specifies a database handle.
|
1572
|
+
`off' specifies an offset of the database file.
|
1573
|
+
`head' specifies a buffer for the header.
|
1574
|
+
`ebuf' specifies the pointer to the entity buffer.
|
1575
|
+
`eep' specifies the pointer to a variable to which whether ebuf was used is assigned.
|
1576
|
+
The return value is true if successful, else, it is false. */
|
1577
|
+
static int dprechead(DEPOT *depot, int off, int *head, char *ebuf, int *eep){
|
1578
|
+
assert(depot && off >= 0 && head);
|
1579
|
+
if(off > depot->fsiz){
|
1580
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
1581
|
+
return FALSE;
|
1582
|
+
}
|
1583
|
+
if(ebuf){
|
1584
|
+
*eep = FALSE;
|
1585
|
+
if(off < depot->fsiz - DP_ENTBUFSIZ){
|
1586
|
+
*eep = TRUE;
|
1587
|
+
if(!dpseekread(depot->fd, off, ebuf, DP_ENTBUFSIZ)) return FALSE;
|
1588
|
+
memcpy(head, ebuf, DP_RHNUM * sizeof(int));
|
1589
|
+
if(head[DP_RHIKSIZ] < 0 || head[DP_RHIVSIZ] < 0 || DP_RHIPSIZ < 0 ||
|
1590
|
+
head[DP_RHILEFT] < 0 || head[DP_RHIRIGHT] < 0){
|
1591
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
1592
|
+
return FALSE;
|
1593
|
+
}
|
1594
|
+
return TRUE;
|
1595
|
+
}
|
1596
|
+
}
|
1597
|
+
if(!dpseekread(depot->fd, off, head, DP_RHNUM * sizeof(int))) return FALSE;
|
1598
|
+
if(head[DP_RHIKSIZ] < 0 || head[DP_RHIVSIZ] < 0 || DP_RHIPSIZ < 0 ||
|
1599
|
+
head[DP_RHILEFT] < 0 || head[DP_RHIRIGHT] < 0){
|
1600
|
+
dpecodeset(DP_EBROKEN, __FILE__, __LINE__);
|
1601
|
+
return FALSE;
|
1602
|
+
}
|
1603
|
+
return TRUE;
|
1604
|
+
}
|
1605
|
+
|
1606
|
+
|
1607
|
+
/* Read the entitiy of the key of a record.
|
1608
|
+
`depot' specifies a database handle.
|
1609
|
+
`off' specifies an offset of the database file.
|
1610
|
+
`head' specifies the header of a record.
|
1611
|
+
The return value is a key data whose region is allocated by `malloc', or NULL on failure. */
|
1612
|
+
static char *dpreckey(DEPOT *depot, int off, int *head){
|
1613
|
+
char *kbuf;
|
1614
|
+
int ksiz;
|
1615
|
+
assert(depot && off >= 0);
|
1616
|
+
ksiz = head[DP_RHIKSIZ];
|
1617
|
+
if(!(kbuf = malloc(ksiz + 1))){
|
1618
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1619
|
+
return NULL;
|
1620
|
+
}
|
1621
|
+
if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int), kbuf, ksiz)){
|
1622
|
+
free(kbuf);
|
1623
|
+
return NULL;
|
1624
|
+
}
|
1625
|
+
kbuf[ksiz] = '\0';
|
1626
|
+
return kbuf;
|
1627
|
+
}
|
1628
|
+
|
1629
|
+
|
1630
|
+
/* Read the entitiy of the value of a record.
|
1631
|
+
`depot' specifies a database handle.
|
1632
|
+
`off' specifies an offset of the database file.
|
1633
|
+
`head' specifies the header of a record.
|
1634
|
+
`start' specifies the offset address of the beginning of the region of the value to be read.
|
1635
|
+
`max' specifies the max size to be read. If it is negative, the size to read is unlimited.
|
1636
|
+
The return value is a value data whose region is allocated by `malloc', or NULL on failure. */
|
1637
|
+
static char *dprecval(DEPOT *depot, int off, int *head, int start, int max){
|
1638
|
+
char *vbuf;
|
1639
|
+
int vsiz;
|
1640
|
+
assert(depot && off >= 0 && start >= 0);
|
1641
|
+
head[DP_RHIVSIZ] -= start;
|
1642
|
+
if(max < 0){
|
1643
|
+
vsiz = head[DP_RHIVSIZ];
|
1644
|
+
} else {
|
1645
|
+
vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
|
1646
|
+
}
|
1647
|
+
if(!(vbuf = malloc(vsiz + 1))){
|
1648
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1649
|
+
return NULL;
|
1650
|
+
}
|
1651
|
+
if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start, vbuf, vsiz)){
|
1652
|
+
free(vbuf);
|
1653
|
+
return NULL;
|
1654
|
+
}
|
1655
|
+
vbuf[vsiz] = '\0';
|
1656
|
+
return vbuf;
|
1657
|
+
}
|
1658
|
+
|
1659
|
+
|
1660
|
+
/* Read the entitiy of the value of a record and write it into a given buffer.
|
1661
|
+
`depot' specifies a database handle.
|
1662
|
+
`off' specifies an offset of the database file.
|
1663
|
+
`head' specifies the header of a record.
|
1664
|
+
`start' specifies the offset address of the beginning of the region of the value to be read.
|
1665
|
+
`max' specifies the max size to be read. It shuld be less than the size of the writing buffer.
|
1666
|
+
If successful, the return value is the size of the written data, else, it is -1. */
|
1667
|
+
static int dprecvalwb(DEPOT *depot, int off, int *head, int start, int max, char *vbuf){
|
1668
|
+
int vsiz;
|
1669
|
+
assert(depot && off >= 0 && start >= 0 && max >= 0 && vbuf);
|
1670
|
+
head[DP_RHIVSIZ] -= start;
|
1671
|
+
vsiz = max < head[DP_RHIVSIZ] ? max : head[DP_RHIVSIZ];
|
1672
|
+
if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + start, vbuf, vsiz))
|
1673
|
+
return -1;
|
1674
|
+
return vsiz;
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
|
1678
|
+
/* Compare two keys.
|
1679
|
+
`abuf' specifies the pointer to the region of the former.
|
1680
|
+
`asiz' specifies the size of the region.
|
1681
|
+
`bbuf' specifies the pointer to the region of the latter.
|
1682
|
+
`bsiz' specifies the size of the region.
|
1683
|
+
The return value is 0 if two equals, positive if the formar is big, else, negative. */
|
1684
|
+
static int dpkeycmp(const char *abuf, int asiz, const char *bbuf, int bsiz){
|
1685
|
+
assert(abuf && asiz >= 0 && bbuf && bsiz >= 0);
|
1686
|
+
if(asiz > bsiz) return 1;
|
1687
|
+
if(asiz < bsiz) return -1;
|
1688
|
+
return memcmp(abuf, bbuf, asiz);
|
1689
|
+
}
|
1690
|
+
|
1691
|
+
|
1692
|
+
/* Search for a record.
|
1693
|
+
`depot' specifies a database handle.
|
1694
|
+
`kbuf' specifies the pointer to the region of a key.
|
1695
|
+
`ksiz' specifies the size of the region.
|
1696
|
+
`hash' specifies the second hash value of the key.
|
1697
|
+
`bip' specifies the pointer to the region to assign the index of the corresponding record.
|
1698
|
+
`offp' specifies the pointer to the region to assign the last visited node in the hash chain,
|
1699
|
+
or, -1 if the hash chain is empty.
|
1700
|
+
`entp' specifies the offset of the last used joint, or, -1 if the hash chain is empty.
|
1701
|
+
`head' specifies the pointer to the region to store the header of the last visited record in.
|
1702
|
+
`ebuf' specifies the pointer to the entity buffer.
|
1703
|
+
`eep' specifies the pointer to a variable to which whether ebuf was used is assigned.
|
1704
|
+
`delhit' specifies whether a deleted record corresponds or not.
|
1705
|
+
The return value is 0 if successful, 1 if there is no corresponding record, -1 on error. */
|
1706
|
+
static int dprecsearch(DEPOT *depot, const char *kbuf, int ksiz, int hash, int *bip, int *offp,
|
1707
|
+
int *entp, int *head, char *ebuf, int *eep, int delhit){
|
1708
|
+
int off, entoff, thash, kcmp;
|
1709
|
+
char stkey[DP_STKBUFSIZ], *tkey;
|
1710
|
+
assert(depot && kbuf && ksiz >= 0 && hash >= 0 && bip && offp && entp && head && ebuf && eep);
|
1711
|
+
*bip = dpfirsthash(kbuf, ksiz) % depot->bnum;
|
1712
|
+
off = depot->buckets[*bip];
|
1713
|
+
*offp = -1;
|
1714
|
+
*entp = -1;
|
1715
|
+
entoff = -1;
|
1716
|
+
*eep = FALSE;
|
1717
|
+
while(off != 0){
|
1718
|
+
if(!dprechead(depot, off, head, ebuf, eep)) return -1;
|
1719
|
+
thash = head[DP_RHIHASH];
|
1720
|
+
if(hash > thash){
|
1721
|
+
entoff = off + DP_RHILEFT * sizeof(int);
|
1722
|
+
off = head[DP_RHILEFT];
|
1723
|
+
} else if(hash < thash){
|
1724
|
+
entoff = off + DP_RHIRIGHT * sizeof(int);
|
1725
|
+
off = head[DP_RHIRIGHT];
|
1726
|
+
} else {
|
1727
|
+
if(*eep && DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] <= DP_ENTBUFSIZ){
|
1728
|
+
kcmp = dpkeycmp(kbuf, ksiz, ebuf + (DP_RHNUM * sizeof(int)), head[DP_RHIKSIZ]);
|
1729
|
+
} else if(head[DP_RHIKSIZ] > DP_STKBUFSIZ){
|
1730
|
+
if(!(tkey = dpreckey(depot, off, head))) return -1;
|
1731
|
+
kcmp = dpkeycmp(kbuf, ksiz, tkey, head[DP_RHIKSIZ]);
|
1732
|
+
free(tkey);
|
1733
|
+
} else {
|
1734
|
+
if(!dpseekread(depot->fd, off + DP_RHNUM * sizeof(int), stkey, head[DP_RHIKSIZ]))
|
1735
|
+
return -1;
|
1736
|
+
kcmp = dpkeycmp(kbuf, ksiz, stkey, head[DP_RHIKSIZ]);
|
1737
|
+
}
|
1738
|
+
if(kcmp > 0){
|
1739
|
+
entoff = off + DP_RHILEFT * sizeof(int);
|
1740
|
+
off = head[DP_RHILEFT];
|
1741
|
+
} else if(kcmp < 0){
|
1742
|
+
entoff = off + DP_RHIRIGHT * sizeof(int);
|
1743
|
+
off = head[DP_RHIRIGHT];
|
1744
|
+
} else {
|
1745
|
+
if(!delhit && (head[DP_RHIFLAGS] & DP_RECFDEL)){
|
1746
|
+
entoff = off + DP_RHILEFT * sizeof(int);
|
1747
|
+
off = head[DP_RHILEFT];
|
1748
|
+
} else {
|
1749
|
+
*offp = off;
|
1750
|
+
*entp = entoff;
|
1751
|
+
return 0;
|
1752
|
+
}
|
1753
|
+
}
|
1754
|
+
}
|
1755
|
+
}
|
1756
|
+
*offp = off;
|
1757
|
+
*entp = entoff;
|
1758
|
+
return 1;
|
1759
|
+
}
|
1760
|
+
|
1761
|
+
|
1762
|
+
/* Overwrite a record.
|
1763
|
+
`depot' specifies a database handle.
|
1764
|
+
`off' specifies the offset of the database file.
|
1765
|
+
`rsiz' specifies the size of the existing record.
|
1766
|
+
`kbuf' specifies the pointer to the region of a key.
|
1767
|
+
`ksiz' specifies the size of the region.
|
1768
|
+
`vbuf' specifies the pointer to the region of a value.
|
1769
|
+
`vsiz' specifies the size of the region.
|
1770
|
+
`hash' specifies the second hash value of the key.
|
1771
|
+
`left' specifies the offset of the left child.
|
1772
|
+
`right' specifies the offset of the right child.
|
1773
|
+
The return value is true if successful, or, false on failure. */
|
1774
|
+
static int dprecrewrite(DEPOT *depot, int off, int rsiz, const char *kbuf, int ksiz,
|
1775
|
+
const char *vbuf, int vsiz, int hash, int left, int right){
|
1776
|
+
char ebuf[DP_WRTBUFSIZ];
|
1777
|
+
int head[DP_RHNUM], asiz, psiz, hoff, koff, voff, c;
|
1778
|
+
assert(depot && off >= 1 && rsiz > 0 && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
|
1779
|
+
psiz = rsiz - sizeof(head) - ksiz - vsiz;
|
1780
|
+
head[DP_RHIFLAGS] = 0;
|
1781
|
+
head[DP_RHIHASH] = hash;
|
1782
|
+
head[DP_RHIKSIZ] = ksiz;
|
1783
|
+
head[DP_RHIVSIZ] = vsiz;
|
1784
|
+
head[DP_RHIPSIZ] = psiz;
|
1785
|
+
head[DP_RHILEFT] = left;
|
1786
|
+
head[DP_RHIRIGHT] = right;
|
1787
|
+
asiz = sizeof(head) + ksiz + vsiz + psiz;
|
1788
|
+
if(asiz <= DP_WRTBUFSIZ){
|
1789
|
+
memcpy(ebuf, head, sizeof(head));
|
1790
|
+
memcpy(ebuf + sizeof(head), kbuf, ksiz);
|
1791
|
+
memcpy(ebuf + sizeof(head) + ksiz, vbuf, vsiz);
|
1792
|
+
memset(ebuf + sizeof(head) + ksiz + vsiz, 0, psiz);
|
1793
|
+
if(!dpseekwrite(depot->fd, off, ebuf, asiz)) return FALSE;
|
1794
|
+
} else {
|
1795
|
+
hoff = off;
|
1796
|
+
koff = hoff + sizeof(head);
|
1797
|
+
voff = koff + ksiz;
|
1798
|
+
c = 0;
|
1799
|
+
if(!dpseekwrite(depot->fd, hoff, head, sizeof(head)) ||
|
1800
|
+
!dpseekwrite(depot->fd, koff, kbuf, ksiz) ||
|
1801
|
+
!dpseekwrite(depot->fd, voff, vbuf, vsiz) ||
|
1802
|
+
(psiz > 0 && !dpseekwrite(depot->fd, voff + vsiz + psiz - 1, &c, 1))) return FALSE;
|
1803
|
+
}
|
1804
|
+
return TRUE;
|
1805
|
+
}
|
1806
|
+
|
1807
|
+
|
1808
|
+
/* Write a record at the end of a database file.
|
1809
|
+
`depot' specifies a database handle.
|
1810
|
+
`kbuf' specifies the pointer to the region of a key.
|
1811
|
+
`ksiz' specifies the size of the region.
|
1812
|
+
`vbuf' specifies the pointer to the region of a value.
|
1813
|
+
`vsiz' specifies the size of the region.
|
1814
|
+
`hash' specifies the second hash value of the key.
|
1815
|
+
`left' specifies the offset of the left child.
|
1816
|
+
`right' specifies the offset of the right child.
|
1817
|
+
The return value is the offset of the record, or, -1 on failure. */
|
1818
|
+
static int dprecappend(DEPOT *depot, const char *kbuf, int ksiz, const char *vbuf, int vsiz,
|
1819
|
+
int hash, int left, int right){
|
1820
|
+
char ebuf[DP_WRTBUFSIZ], *hbuf;
|
1821
|
+
int head[DP_RHNUM], asiz, psiz, off;
|
1822
|
+
assert(depot && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
|
1823
|
+
psiz = dppadsize(depot, vsiz);
|
1824
|
+
head[DP_RHIFLAGS] = 0;
|
1825
|
+
head[DP_RHIHASH] = hash;
|
1826
|
+
head[DP_RHIKSIZ] = ksiz;
|
1827
|
+
head[DP_RHIVSIZ] = vsiz;
|
1828
|
+
head[DP_RHIPSIZ] = psiz;
|
1829
|
+
head[DP_RHILEFT] = left;
|
1830
|
+
head[DP_RHIRIGHT] = right;
|
1831
|
+
asiz = sizeof(head) + ksiz + vsiz + psiz;
|
1832
|
+
off = depot->fsiz;
|
1833
|
+
if(asiz <= DP_WRTBUFSIZ){
|
1834
|
+
memcpy(ebuf, head, sizeof(head));
|
1835
|
+
memcpy(ebuf + sizeof(head), kbuf, ksiz);
|
1836
|
+
memcpy(ebuf + sizeof(head) + ksiz, vbuf, vsiz);
|
1837
|
+
memset(ebuf + sizeof(head) + ksiz + vsiz, 0, psiz);
|
1838
|
+
if(!dpseekwrite(depot->fd, off, ebuf, asiz)) return -1;
|
1839
|
+
} else {
|
1840
|
+
if(!(hbuf = malloc(asiz))){
|
1841
|
+
dpecodeset(DP_EALLOC, __FILE__, __LINE__);
|
1842
|
+
return -1;
|
1843
|
+
}
|
1844
|
+
memcpy(hbuf, head, sizeof(head));
|
1845
|
+
memcpy(hbuf + sizeof(head), kbuf, ksiz);
|
1846
|
+
memcpy(hbuf + sizeof(head) + ksiz, vbuf, vsiz);
|
1847
|
+
memset(hbuf + sizeof(head) + ksiz + vsiz, 0, psiz);
|
1848
|
+
if(!dpseekwrite(depot->fd, off, hbuf, asiz)){
|
1849
|
+
free(hbuf);
|
1850
|
+
return -1;
|
1851
|
+
}
|
1852
|
+
free(hbuf);
|
1853
|
+
}
|
1854
|
+
depot->fsiz += asiz;
|
1855
|
+
return off;
|
1856
|
+
}
|
1857
|
+
|
1858
|
+
|
1859
|
+
/* Overwrite the value of a record.
|
1860
|
+
`depot' specifies a database handle.
|
1861
|
+
`off' specifies the offset of the database file.
|
1862
|
+
`head' specifies the header of the record.
|
1863
|
+
`vbuf' specifies the pointer to the region of a value.
|
1864
|
+
`vsiz' specifies the size of the region.
|
1865
|
+
`cat' specifies whether it is concatenate mode or not.
|
1866
|
+
The return value is true if successful, or, false on failure. */
|
1867
|
+
static int dprecover(DEPOT *depot, int off, int *head, const char *vbuf, int vsiz, int cat){
|
1868
|
+
int hsiz, hoff, voff;
|
1869
|
+
assert(depot && off >= 0 && head && vbuf && vsiz >= 0);
|
1870
|
+
if(depot->mroff == off) depot->mroff = -1;
|
1871
|
+
if(cat){
|
1872
|
+
head[DP_RHIFLAGS] = 0;
|
1873
|
+
head[DP_RHIPSIZ] -= vsiz;
|
1874
|
+
head[DP_RHIVSIZ] += vsiz;
|
1875
|
+
hsiz = DP_RHNUM * sizeof(int);
|
1876
|
+
hoff = off;
|
1877
|
+
voff = hoff + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ] + head[DP_RHIVSIZ] - vsiz;
|
1878
|
+
} else {
|
1879
|
+
head[DP_RHIFLAGS] = 0;
|
1880
|
+
head[DP_RHIPSIZ] += head[DP_RHIVSIZ] - vsiz;
|
1881
|
+
head[DP_RHIVSIZ] = vsiz;
|
1882
|
+
hsiz = DP_RHNUM * sizeof(int);
|
1883
|
+
hoff = off;
|
1884
|
+
voff = hoff + DP_RHNUM * sizeof(int) + head[DP_RHIKSIZ];
|
1885
|
+
}
|
1886
|
+
if(!dpseekwrite(depot->fd, hoff, head, hsiz) ||
|
1887
|
+
!dpseekwrite(depot->fd, voff, vbuf, vsiz)) return FALSE;
|
1888
|
+
return TRUE;
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
|
1892
|
+
/* Delete a record.
|
1893
|
+
`depot' specifies a database handle.
|
1894
|
+
`off' specifies the offset of the database file.
|
1895
|
+
`head' specifies the header of the record.
|
1896
|
+
`reusable' specifies whether the region is reusable or not.
|
1897
|
+
The return value is true if successful, or, false on failure. */
|
1898
|
+
static int dprecdelete(DEPOT *depot, int off, int *head, int reusable){
|
1899
|
+
assert(depot && off >= 0 && head);
|
1900
|
+
if(reusable){
|
1901
|
+
depot->mroff = off;
|
1902
|
+
depot->mrsiz = dprecsize(head);
|
1903
|
+
}
|
1904
|
+
return dpseekwritenum(depot->fd, off + DP_RHIFLAGS * sizeof(int),
|
1905
|
+
DP_RECFDEL | (reusable ? DP_RECFREUSE : 0));
|
1906
|
+
}
|
1907
|
+
|
1908
|
+
|
1909
|
+
|
1910
|
+
/* END OF FILE */
|