source: gsdl/trunk/common-src/src/lib/gdbmclass.cpp@ 16895

Last change on this file since 16895 was 16895, checked in by davidb, 16 years ago

Runtime code can now support GDBM database being provided as a gzipped txt file, which is platform independant. If the required .ldb (or .bdb) isn't there than the runtime system executes txt2db to generate it. The rest of the code then works as before

File size: 7.4 KB
Line 
1/**********************************************************************
2 *
3 * gdbmclass.cpp --
4 * Copyright (C) 1999-2008 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "gdbmclass.h"
27#include "gsdltools.h"
28#include "gsdlunicode.h"
29#include "fileutil.h"
30
31
32
33
34gdbmclass::~gdbmclass()
35{
36 closedatabase();
37}
38
39
40// returns true if opened
41bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys,
42#ifdef __WIN32__
43 bool need_filelock
44#else
45 bool
46#endif
47 )
48{
49
50 text_t data_location;
51 int block_size = 512;
52
53 if (gdbmfile != NULL) {
54 if (openfile == filename) return true;
55 else closedatabase ();
56 }
57
58 openfile = filename;
59
60 // Map the DB mode values into GDBM mode values
61 int gdbm_mode = GDBM_READER;
62 if (mode == DB_WRITER)
63 {
64 gdbm_mode = GDBM_WRITER;
65 }
66 else if (mode == DB_WRITER_CREATE)
67 {
68 gdbm_mode = GDBM_WRCREAT;
69 }
70
71 if (gdbm_mode == GDBM_READER) {
72 // Looking to read in the database
73 // => check to see if .ldb/.bdb file already there
74 // if not (first time) then generate using txt2db
75 if (!file_exists(filename)) {
76
77 // need to generate architecture native GDBM file using txt2db
78
79 // replace sought after gdbm filename ext with ".txt.gz"
80
81 text_t::const_iterator begin = filename.begin();
82 text_t::const_iterator end= filename.end();
83 text_t::const_iterator here = end;
84
85 bool found_ext = false;
86
87 while (here != begin) {
88 if (*here == '.') {
89 found_ext = true;
90 break;
91 }
92 here--;
93 }
94
95 text_t filename_root;
96
97 if (found_ext) {
98 filename_root = substr(begin,here);
99 }
100 else {
101 filename_root = filename;
102 }
103
104 text_t txtgz_filename = filename_root + ".txt.gz";
105
106 text_t cmd = "gzip --decompress --to-stdout \"" + txtgz_filename + "\"";
107 cmd += " | txt2db \"" + filename + "\"";
108
109 int rv = gsdl_system(cmd, true, cerr);
110 if (rv != 0) {
111 cerr << "Tried to run command \""<<cmd<<"\", but it failed\n";
112 }
113 }
114 }
115
116 char *namebuffer = filename.getcstr();
117 do {
118#ifdef __WIN32__
119 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL, (need_filelock) ? 1 : 0);
120#else
121 gdbmfile = gdbm_open (namebuffer, block_size, gdbm_mode, 00664, NULL);
122#endif
123 --num_retrys;
124 } while (num_retrys>0 && gdbmfile==NULL &&
125 (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
126 delete []namebuffer;
127
128 if (gdbmfile == NULL && logout != NULL) {
129 outconvertclass text_t2ascii;
130 (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
131 }
132
133 return (gdbmfile != NULL);
134}
135
136
137void gdbmclass::closedatabase ()
138{
139 if (gdbmfile == NULL) return;
140
141 gdbm_close (gdbmfile);
142 gdbmfile = NULL;
143 openfile.clear();
144}
145
146
147void gdbmclass::deletekey (const text_t &key)
148{
149 if (gdbmfile == NULL) return;
150
151 // get a utf-8 encoded c string of the unicode key
152 datum key_data;
153 key_data.dptr = (to_utf8(key)).getcstr();
154 if (key_data.dptr == NULL) return;
155 key_data.dsize = strlen (key_data.dptr);
156
157 // delete the key
158 gdbm_delete (gdbmfile, key_data);
159
160 // free up the key memory
161 delete []key_data.dptr;
162}
163
164
165// returns file extension string
166text_t gdbmclass::getfileextension ()
167{
168 if (littleEndian()) return ".ldb";
169 return ".bdb";
170}
171
172
173// returns true on success
174bool gdbmclass::getkeydata (const text_t& key, text_t &data)
175{
176 datum key_data;
177 datum return_data;
178
179 if (gdbmfile == NULL) return false;
180
181 // get a utf-8 encoded c string of the unicode key
182 key_data.dptr = (to_utf8(key)).getcstr();
183 if (key_data.dptr == NULL) {
184 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
185 return false;
186 }
187 key_data.dsize = strlen (key_data.dptr);
188
189 // fetch the result
190 return_data = gdbm_fetch (gdbmfile, key_data);
191 delete []key_data.dptr;
192
193 if (return_data.dptr == NULL) return false;
194
195 data.setcarr (return_data.dptr, return_data.dsize);
196 free (return_data.dptr);
197 data = to_uni(data); // convert to unicode
198
199 return true;
200}
201
202
203// returns array of keys
204text_tarray gdbmclass::getkeys ()
205{
206 text_tarray keys;
207
208 text_t key = getfirstkey();
209 while (!key.empty())
210 {
211 keys.push_back(key);
212 key = getnextkey(key);
213 }
214
215 return keys;
216}
217
218
219// returns true on success
220bool gdbmclass::setkeydata (const text_t &key, const text_t &data)
221{
222 if (gdbmfile == NULL) return false;
223
224 // store the value
225 datum key_data;
226 datum data_data;
227
228 // get a utf-8 encoded c string of the unicode key
229 key_data.dptr = (to_utf8(key)).getcstr();
230 if (key_data.dptr == NULL) {
231 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
232 return false;
233 }
234 key_data.dsize = strlen (key_data.dptr);
235
236 data_data.dptr = (to_utf8(data)).getcstr();
237 if (data_data.dptr == NULL) {
238 if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
239 delete []key_data.dptr;
240 return false;
241 }
242 data_data.dsize = strlen (data_data.dptr);
243
244 int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
245 delete []key_data.dptr;
246 delete []data_data.dptr;
247
248 return (ret == 0);
249}
250
251
252// ----------------------------------------------------------------------------------------
253// GDBM-ONLY FUNCTIONS
254// ----------------------------------------------------------------------------------------
255
256// getfirstkey and getnextkey are used for traversing the database
257// no insertions or deletions should be carried out while traversing
258// the database. when there are no keys left to visit in the database
259// an empty string is returned.
260text_t gdbmclass::getfirstkey ()
261{
262 if (gdbmfile == NULL) return g_EmptyText;
263
264 // get the first key
265 datum firstkey_data = gdbm_firstkey (gdbmfile);
266 if (firstkey_data.dptr == NULL) return g_EmptyText;
267
268 // convert it to text_t
269 text_t firstkey;
270 firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
271 free (firstkey_data.dptr);
272 return to_uni(firstkey); // convert to unicode
273}
274
275
276text_t gdbmclass::getnextkey (const text_t &key)
277{
278 if (gdbmfile == NULL || key.empty()) return g_EmptyText;
279
280 // get a utf-8 encoded c string of the unicode key
281 datum key_data;
282 key_data.dptr = (to_utf8(key)).getcstr();
283 if (key_data.dptr == NULL) return g_EmptyText;
284 key_data.dsize = strlen (key_data.dptr);
285
286 // get the next key
287 datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
288 if (nextkey_data.dptr == NULL) {
289 delete []key_data.dptr;
290 return g_EmptyText;
291 }
292
293 // convert it to text_t
294 text_t nextkey;
295 nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
296 free (nextkey_data.dptr);
297 delete []key_data.dptr;
298 return to_uni(nextkey); // convert to unicode
299}
Note: See TracBrowser for help on using the repository browser.