1 /*
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifdef _WIN32 /* needed for htonl, Ugh! */
30 #include <winsock2.h>
31 #else
32 #include <netinet/in.h>
33 #endif
34
35 #include "jni.h"
36 #include "jlong.h"
37 #include "jni_util.h"
38 #include "org_openjdk_jigsaw_PersistentTreeMap.h"
39 #include "PersistentTreeMap.h"
40
41 static jboolean
42 error(JNIEnv *env, int rv)
43 {
44 if (rv != 0) {
45 char *m = libdb_db_strerror(rv);
46 JNU_ThrowIOException(env, m);
47 return JNI_TRUE;
48 }
49 return JNI_FALSE;
50 }
51
52 static const char *
53 getutf(JNIEnv *env, jstring s)
54 {
55 // TODO: replace with GetStringUTFRegion and use on stack buffer
56 // to avoid malloc from GetStringUTFChars???
57 const char *u = (*env)->GetStringUTFChars(env, s, NULL);
58 if (u == NULL) {
59 JNU_ThrowOutOfMemoryError(env, "org.openjdk.jigsaw.PersistentTreeMap.getutf");
60 return NULL;
61 }
62 return u;
63 }
64
65 static void freeutf(JNIEnv *env, jstring s, const char *su)
66 {
67 (*env)->ReleaseStringUTFChars(env, s, su);
68 }
69
70 JNIEXPORT void JNICALL
71 Java_org_openjdk_jigsaw_PersistentTreeMap_initialize(JNIEnv *env, jclass cl)
72 {
73 if (libdb_db_create == NULL)
74 loadLibrary(env);
75 }
76
77 JNIEXPORT jlong JNICALL
78 Java_org_openjdk_jigsaw_PersistentTreeMap_create0(JNIEnv *env, jclass cl,
79 jstring path)
80 {
81 DB *dbp;
82 int rv;
83 const char *pathb = getutf(env, path);
84 if (pathb == NULL)
85 return 0;
86
87 rv = libdb_db_create(&dbp, NULL, 0);
88 if (error(env, rv)) {
89 freeutf(env, path, pathb);
90 return 0;
91 }
92
93 rv = dbp->open(dbp, NULL, pathb, NULL, DB_BTREE,
94 DB_CREATE | DB_TRUNCATE | DB_THREAD, 0);
95
96 freeutf(env, path, pathb);
97 if (error(env, rv)) {
98 dbp->close(dbp, 0);
99 return 0;
100 }
101 return ptr_to_jlong(dbp);
102 }
103
104 JNIEXPORT jlong JNICALL
105 Java_org_openjdk_jigsaw_PersistentTreeMap_open0(JNIEnv *env, jclass cl,
106 jstring path)
107 {
108 DB *dbp;
109 int rv;
110 const char *pathb = getutf(env, path);
111 if (pathb == NULL)
112 return 0;
113
114 rv = libdb_db_create(&dbp, NULL, 0);
115 if (error(env, rv)) {
116 freeutf(env, path, pathb);
117 return 0;
118 }
119
120 rv = dbp->open(dbp, NULL, pathb, NULL, DB_BTREE, DB_RDONLY | DB_THREAD, 0);
121 freeutf(env, path, pathb);
122 if (error(env, rv)) {
123 dbp->close(dbp, 0);
124 return 0;
125 }
126 return ptr_to_jlong(dbp);
127 }
128
129 JNIEXPORT void JNICALL
130 Java_org_openjdk_jigsaw_PersistentTreeMap_put0(JNIEnv *env, jobject ob,
131 jlong dbl, jstring key,
132 jstring val)
133 {
134 DB *dbp = jlong_to_ptr(dbl);
135 DBT dbkey, dbdata;
136 int rv;
137 const char *v;
138 const char *k = getutf(env, key);
139 if (k == NULL)
140 return;
141 v = getutf(env, val);
142 if (v == NULL) {
143 freeutf(env, key, k);
144 return;
145 }
146
147 memset(&dbkey, 0, sizeof(DBT));
148 memset(&dbdata, 0, sizeof(DBT));
149 dbkey.data = (void*)k;
150 dbkey.size = dbkey.ulen = strlen(k);
151 dbdata.data = (void*)v;
152 dbdata.size = dbdata.ulen = strlen(v);
153
154 rv = dbp->put(dbp, NULL, &dbkey, &dbdata, 0);
155
156 freeutf(env, key, k);
157 freeutf(env, val, v);
158 (void)error(env, rv);
159 }
160
161 JNIEXPORT jstring JNICALL
162 Java_org_openjdk_jigsaw_PersistentTreeMap_get0(JNIEnv *env, jobject ob,
163 jlong dbl, jstring key)
164 {
165 DB *dbp = jlong_to_ptr(dbl);
166 DBT dbkey, dbdata;
167 int rv;
168 char valbuf[1024]; // TODO: 1k limit on data value, increase/malloc?
169 const char *k = getutf(env, key);
170 if (k == NULL)
171 return NULL;
172
173 memset(&dbkey, 0, sizeof(DBT));
174 memset(&dbdata, 0, sizeof(DBT));
175 dbkey.data = (void*)k;
176 dbkey.size = dbkey.ulen = strlen(k);
177 dbdata.data = valbuf;
178 dbdata.ulen = 1023; // leave space for null terminator
179 dbdata.flags = DB_DBT_USERMEM;
180
181 rv = dbp->get(dbp, NULL, &dbkey, &dbdata, 0);
182 freeutf(env, key, k);
183 if (rv == DB_NOTFOUND || error(env, rv) || dbdata.data == NULL)
184 return NULL;
185
186 // TODO: check for DB_BUFFER_SMALL (possibly in error) and handle
187 valbuf[dbdata.size] = 0; // null terminate
188
189 return (*env)->NewStringUTF(env, valbuf);
190 }
191
192 JNIEXPORT void JNICALL
193 Java_org_openjdk_jigsaw_PersistentTreeMap_put1(JNIEnv *env, jobject ob,
194 jlong dbl, jstring key,
195 jint val)
196 {
197 DB *dbp = jlong_to_ptr(dbl);
198 DBT dbkey, dbdata;
199 int rv;
200 int aval = htonl(val);
201 const char *k = getutf(env, key);
202 if (k == NULL)
203 return;
204
205 memset(&dbkey, 0, sizeof(DBT));
206 memset(&dbdata, 0, sizeof(DBT));
207 dbkey.data = (void*)k;
208 dbkey.size = dbkey.ulen = strlen(k);
209 dbdata.data = &aval;
210 dbdata.size = dbdata.ulen = sizeof(aval);
211
212 rv = dbp->put(dbp, NULL, &dbkey, &dbdata, 0);
213 freeutf(env, key, k);
214 (void)error(env, rv);
215 }
216
217 JNIEXPORT jint JNICALL
218 Java_org_openjdk_jigsaw_PersistentTreeMap_get1(JNIEnv *env, jobject ob,
219 jlong dbl, jstring key)
220 {
221 DB *dbp = jlong_to_ptr(dbl);
222 DBT dbkey, dbdata;
223 int rv;
224 jint ival;
225 const char *k = getutf(env, key);
226 if (k == NULL)
227 return -1;
228
229 memset(&dbkey, 0, sizeof(DBT));
230 memset(&dbdata, 0, sizeof(DBT));
231 dbkey.data = (void*)k;
232 dbkey.size = dbkey.ulen = strlen(k);
233 dbdata.data = &ival;
234 dbdata.ulen = sizeof(ival);
235 dbdata.flags = DB_DBT_USERMEM;
236
237 rv = dbp->get(dbp, NULL, &dbkey, &dbdata, 0);
238 freeutf(env, key, k);
239 if (rv == DB_NOTFOUND || error(env, rv) || dbdata.data == NULL)
240 return -1;
241
242 return ntohl(ival);
243 }
244
245 JNIEXPORT void JNICALL
246 Java_org_openjdk_jigsaw_PersistentTreeMap_put2(JNIEnv *env, jobject ob,
247 jlong dbl, jstring key,
248 jstring sval, jint ival)
249 {
250 DB *dbp = jlong_to_ptr(dbl);
251 DBT dbkey, dbdata;
252 int rv, slen, sulen, blen;
253 char *valbuf;
254 int aval = htonl(ival);
255 const char *k = getutf(env, key);
256 if (k == NULL)
257 return;
258
259 slen = (*env)->GetStringLength(env, sval);
260 sulen = (*env)->GetStringUTFLength(env, sval); //TODO; error checking jni fails?
261 blen = sulen + sizeof(aval);
262 valbuf = (char*)malloc(blen + 1); //TODO: on stack buffer if small enough?
263 memcpy(valbuf, &aval, sizeof(aval));
264 (*env)->GetStringUTFRegion(env, sval, 0, slen, valbuf + sizeof(aval));
265
266 memset(&dbkey, 0, sizeof(DBT));
267 memset(&dbdata, 0, sizeof(DBT));
268 dbkey.data = (void*)k;
269 dbkey.size = dbkey.ulen = strlen(k);
270 dbdata.data = (void*)valbuf;
271 dbdata.size = dbdata.ulen = blen;
272 dbdata.flags = DB_DBT_USERMEM;
273
274 rv = dbp->put(dbp, NULL, &dbkey, &dbdata, 0);
275 freeutf(env, key, k);
276 free(valbuf);
277 (void)error(env, rv);
278 }
279
280 JNIEXPORT jboolean JNICALL
281 Java_org_openjdk_jigsaw_PersistentTreeMap_get2(JNIEnv *env, jobject ob,
282 jlong dbl, jstring key,
283 jobjectArray svala,
284 jintArray ivala)
285 {
286 DB *dbp = jlong_to_ptr(dbl);
287 DBT dbkey, dbdata;
288 int rv;
289 char valbuf[1024];
290 jint ival;
291 jstring sval;
292 const char *k = getutf(env, key);
293 if (k == NULL)
294 return JNI_FALSE;
295
296 memset(&dbkey, 0, sizeof(DBT));
297 memset(&dbdata, 0, sizeof(DBT));
298 dbkey.data = (void*)k;
299 dbkey.size = dbkey.ulen = strlen(k);
300 dbdata.data = valbuf;
301 dbdata.ulen = 1023; // leave space for null terminator
302 dbdata.flags = DB_DBT_USERMEM;
303
304 rv = dbp->get(dbp, NULL, &dbkey, &dbdata, 0);
305 freeutf(env, key, k);
306 if (rv == DB_NOTFOUND || error(env, rv) ||
307 dbdata.data == NULL || dbdata.size < sizeof(jint))
308 return JNI_FALSE;
309
310 // TODO: check for DB_BUFFER_SMALL (possibly in error) and handle
311 valbuf[dbdata.size] = 0; // null terminate
312
313 ival = ntohl(*((jint *)valbuf));
314 sval = (*env)->NewStringUTF(env, valbuf + sizeof(ival));
315 (*env)->SetObjectArrayElement(env, svala, 0, sval);
316 (*env)->SetIntArrayRegion(env, ivala, 0, 1, &ival);
317 return JNI_TRUE;
318 }
319
320 JNIEXPORT void JNICALL
321 Java_org_openjdk_jigsaw_PersistentTreeMap_close0(JNIEnv *env, jobject ob,
322 jlong dbl)
323 {
324 DB *dbp = jlong_to_ptr(dbl);
325 (void)error(env, dbp->close(dbp, 0));
326 }