1/*	$NetBSD: mtest.c,v 1.3 2021/08/14 16:14:57 christos Exp $	*/
2
3/* mtest.c - memory-mapped database tester/toy */
4/*
5 * Copyright 2011-2021 Howard Chu, Symas Corp.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16#include <stdio.h>
17#include <stdlib.h>
18#include <time.h>
19#include "lmdb.h"
20
21#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
22#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
23#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
24	"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
25
26int main(int argc,char * argv[])
27{
28	int i = 0, j = 0, rc;
29	MDB_env *env;
30	MDB_dbi dbi;
31	MDB_val key, data;
32	MDB_txn *txn;
33	MDB_stat mst;
34	MDB_cursor *cursor, *cur2;
35	MDB_cursor_op op;
36	int count;
37	int *values;
38	char sval[32] = "";
39
40	srand(time(NULL));
41
42	    count = (rand()%384) + 64;
43	    values = (int *)malloc(count*sizeof(int));
44
45	    for(i = 0;i<count;i++) {
46			values[i] = rand()%1024;
47	    }
48
49		E(mdb_env_create(&env));
50		E(mdb_env_set_maxreaders(env, 1));
51		E(mdb_env_set_mapsize(env, 10485760));
52		E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
53
54		E(mdb_txn_begin(env, NULL, 0, &txn));
55		E(mdb_dbi_open(txn, NULL, 0, &dbi));
56
57		key.mv_size = sizeof(int);
58		key.mv_data = sval;
59
60		printf("Adding %d values\n", count);
61	    for (i=0;i<count;i++) {
62			sprintf(sval, "%03x %d foo bar", values[i], values[i]);
63			/* Set <data> in each iteration, since MDB_NOOVERWRITE may modify it */
64			data.mv_size = sizeof(sval);
65			data.mv_data = sval;
66			if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
67				j++;
68				data.mv_size = sizeof(sval);
69				data.mv_data = sval;
70			}
71	    }
72		if (j) printf("%d duplicates skipped\n", j);
73		E(mdb_txn_commit(txn));
74		E(mdb_env_stat(env, &mst));
75
76		E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
77		E(mdb_cursor_open(txn, dbi, &cursor));
78		while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
79			printf("key: %p %.*s, data: %p %.*s\n",
80				key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
81				data.mv_data, (int) data.mv_size, (char *) data.mv_data);
82		}
83		CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
84		mdb_cursor_close(cursor);
85		mdb_txn_abort(txn);
86
87		j=0;
88		key.mv_data = sval;
89	    for (i= count - 1; i > -1; i-= (rand()%5)) {
90			j++;
91			txn=NULL;
92			E(mdb_txn_begin(env, NULL, 0, &txn));
93			sprintf(sval, "%03x ", values[i]);
94			if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
95				j--;
96				mdb_txn_abort(txn);
97			} else {
98				E(mdb_txn_commit(txn));
99			}
100	    }
101	    free(values);
102		printf("Deleted %d values\n", j);
103
104		E(mdb_env_stat(env, &mst));
105		E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));
106		E(mdb_cursor_open(txn, dbi, &cursor));
107		printf("Cursor next\n");
108		while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
109			printf("key: %.*s, data: %.*s\n",
110				(int) key.mv_size,  (char *) key.mv_data,
111				(int) data.mv_size, (char *) data.mv_data);
112		}
113		CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
114		printf("Cursor last\n");
115		E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
116		printf("key: %.*s, data: %.*s\n",
117			(int) key.mv_size,  (char *) key.mv_data,
118			(int) data.mv_size, (char *) data.mv_data);
119		printf("Cursor prev\n");
120		while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
121			printf("key: %.*s, data: %.*s\n",
122				(int) key.mv_size,  (char *) key.mv_data,
123				(int) data.mv_size, (char *) data.mv_data);
124		}
125		CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
126		printf("Cursor last/prev\n");
127		E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
128			printf("key: %.*s, data: %.*s\n",
129				(int) key.mv_size,  (char *) key.mv_data,
130				(int) data.mv_size, (char *) data.mv_data);
131		E(mdb_cursor_get(cursor, &key, &data, MDB_PREV));
132			printf("key: %.*s, data: %.*s\n",
133				(int) key.mv_size,  (char *) key.mv_data,
134				(int) data.mv_size, (char *) data.mv_data);
135
136		mdb_cursor_close(cursor);
137		mdb_txn_abort(txn);
138
139		printf("Deleting with cursor\n");
140		E(mdb_txn_begin(env, NULL, 0, &txn));
141		E(mdb_cursor_open(txn, dbi, &cur2));
142		for (i=0; i<50; i++) {
143			if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT)))
144				break;
145			printf("key: %p %.*s, data: %p %.*s\n",
146				key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
147				data.mv_data, (int) data.mv_size, (char *) data.mv_data);
148			E(mdb_del(txn, dbi, &key, NULL));
149		}
150
151		printf("Restarting cursor in txn\n");
152		for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
153			if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op)))
154				break;
155			printf("key: %p %.*s, data: %p %.*s\n",
156				key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
157				data.mv_data, (int) data.mv_size, (char *) data.mv_data);
158		}
159		mdb_cursor_close(cur2);
160		E(mdb_txn_commit(txn));
161
162		printf("Restarting cursor outside txn\n");
163		E(mdb_txn_begin(env, NULL, 0, &txn));
164		E(mdb_cursor_open(txn, dbi, &cursor));
165		for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
166			if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op)))
167				break;
168			printf("key: %p %.*s, data: %p %.*s\n",
169				key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
170				data.mv_data, (int) data.mv_size, (char *) data.mv_data);
171		}
172		mdb_cursor_close(cursor);
173		mdb_txn_abort(txn);
174
175		mdb_dbi_close(env, dbi);
176		mdb_env_close(env);
177
178	return 0;
179}
180