瀏覽代碼

btree +dbopen

David Marec 8 月之前
父節點
當前提交
24f5f3b18e
共有 9 個文件被更改,包括 511 次插入1 次删除
  1. 38 0
      btree/Makefile
  2. 71 0
      btree/README.md
  3. 22 0
      btree/bcompare.c
  4. 7 0
      btree/bcompare.h
  5. 186 0
      btree/bprompt.c
  6. 95 0
      btree/btest.c
  7. 12 0
      btree/gram.l
  8. 79 0
      btree/parse.y
  9. 1 1
      kqueue/kq_timer.c

+ 38 - 0
btree/Makefile

@@ -0,0 +1,38 @@
+CFLAGS+=-O3 -Wall -fPIE -fno-strict-aliasing
+CFLAGS+=-Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough
+CFLAGS+=-Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
+CFLAGS+=-fstack-clash-protection -fstack-protector-strong
+CFLAGS+=-fstrict-flex-arrays=3
+
+LDFLAGS=-lutil
+LDFLAGS+=-Wl,-O3,--sort-common,--as-needed,-z,relro,-z,now,--strip-all -pie
+LDFLAGS+=-Wl,-z,nodlopen -Wl,-z,noexecstack,--no-copy-dt-needed-entries
+
+BTREE=btest
+BTREE_OBJS=btest.o bcompare.o
+
+BPROMPT=bprompt
+BPROMPT_OBJS=bprompt.o bcompare.o
+BPROMPT_LEX=lex.yy.c
+BPROMPT_YACC=y.tab.c
+.PHONY: clean 
+
+.MAIN: clean $(BPROMPT) $(BTREE)
+
+$(BTREE): $(BTREE_OBJS)
+	$(CC) -o ${.TARGET} ${.ALLSRC} $(LDFLAGS)
+
+$(BPROMPT_LEX): gram.l
+	lex ${.ALLSRC}
+
+$(BPROMPT_YACC): parse.y 
+	yacc -d ${.ALLSRC}
+
+$(BPROMPT): $(BPROMPT_OBJS) $(BPROMPT_LEX) $(BPROMPT_YACC)
+	$(CC) -o ${.TARGET} ${.ALLSRC} -O3 -fPIE $(LDFLAGS)
+
+.o:
+	$(CC) -o ${.TARGET} $(CFLAGS) -c ${.IMPSRC}
+
+clean:
+	rm -f *.o $(BTREE) ${BPROMPT} $(BPROMPT_YACC) $(BPROMPT_LEX)

+ 71 - 0
btree/README.md

@@ -0,0 +1,71 @@
+# DB BTree and yacc/flex example
+
+Example d'utilisation de `dbopen(3)` en mode `btree`.
+Syntaxe _yacc/lex_ pour l'exemple.
+
+
+* bprompt: ajouter, efface ou affiche des entrées:
+  * insert <key> "<test>"
+  * delete <key>
+  * get <key>
+  * quit
+* btest: remplit arbitrairement la table avec `coucou %%`.
+
+Passez l'option `-d` pour choisir le fichier de base de donnée.
+
+# bcompare
+```sh
+get 0
+-> "zero".
+
+get 42
+-> "guide du routard".
+
+get 43
+bprompt: record 43 was not found.
+
+insert 43 "quarante trois"
+Record inserted with key 43.
+
+insert 10 "dix"
+Record inserted with key 10.
+
+get 10
+-> "dix".
+
+get 43
+-> "test".
+
+delete 10
+Record 10 deleted.
+
+get 10
+bprompt: record 10 was not found.
+```
+
+# btest
+
+```sh
+./obj/btest -d /tmp/coucou
+Data stored into /tmp/coucou.
+llanura david ~/cc/freebsd/btree % ./obj/bprompt -d /tmp/coucou
+get 0
+-> coucou 0.
+
+get 99
+-> coucou 99.
+
+get 98
+-> coucou 98.
+
+get 10
+-> coucou 10.
+
+get 11
+-> coucou 11.
+
+get 42
+-> coucou 42.
+```
+
+

+ 22 - 0
btree/bcompare.c

@@ -0,0 +1,22 @@
+#include <db.h>
+/*
+ * btree compare algorithm
+ *
+ * @a: entry
+ * @b: entry
+ *
+ * return -1,0,<+diff> if a is lower, equal or greater than b
+ */
+__attribute__((pure)) int compare(const DBT * restrict a, const DBT * restrict b)
+{ 
+	size_t *v1 = a->data;
+	size_t *v2 = b->data;
+
+	if (*v1 > *v2)
+		return -1;
+
+	if (*v1 == *v2)
+		return 0;
+
+	return 1;
+}

+ 7 - 0
btree/bcompare.h

@@ -0,0 +1,7 @@
+#ifndef BCOMPARE_H
+#define BCOMPARE_H
+
+extern int compare(const DBT * restrict a, const DBT * restrict b) __attribute__((pure));
+
+#endif
+

+ 186 - 0
btree/bprompt.c

@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <db.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <err.h>
+#include <string.h>
+#include <sys/types.h>
+#include <malloc_np.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include "bcompare.h"
+
+/* yacc */
+int yyparse(void);
+extern int yyin;
+int btreeparse(const char *line);
+int do_quit = 0;
+/* MALLOC_CONF=stats_print:true,junk:true */
+static DB * btreedb;
+#define KEYDATA_MAX 64
+
+
+static struct option longopts[] = {
+	{ "db",   required_argument,      NULL, 'd' },
+	{ NULL,	0, NULL, 0 }
+};
+
+__attribute__((noreturn)) static int usage(void)
+{
+	fputs("bprompt [--db filename]\n", stderr);
+	exit (EXIT_SUCCESS);
+}
+
+/*
+ * insert key/val pair in database
+ *
+ * @key: key id
+ * @data: cargo
+ * 
+ * return 0 on success, -1 otherwise
+ */
+int dbinsert(size_t key, char *data)
+{
+	DBT k =  {};
+	DBT d = {};
+	int rc = 0;
+	size_t l =strnlen(data, KEYDATA_MAX);
+
+	k.data = &key;
+	k.size = sizeof key;
+	d.size = l + 1;
+	d.data = malloc(KEYDATA_MAX);
+
+	*((char *) mempcpy (d.data, data, l)) = '\0';
+
+	rc = btreedb->put(btreedb, &k, &d, R_NOOVERWRITE);
+	if (rc == -1) {
+		warn("Failed to insert record %zu:", key);
+		goto dbinsert_out;
+	}
+
+	if (rc) {
+		warnx("This record can't be ovewritten.");
+		rc = -1;
+		goto dbinsert_out;
+	}
+
+	printf("Record inserted with key %zu.\n", key);
+
+dbinsert_out:
+	free(d.data);
+	return rc;
+}
+
+/*
+ * delete key/val pair from database
+ *
+ * @key: key id
+ * 
+ * return 0 on success, -1 otherwise
+ */
+int dbdelete(size_t key)
+{
+	DBT k =  {};
+	k.data = &key;
+	k.size = sizeof key;
+	int rc;
+
+	rc = btreedb->del(btreedb, &k, 0);
+
+	if (rc == -1) {
+		warn("Failed to delete record %zu:", key);
+		return -1;
+	}
+	if (rc) {
+		warnx("record key %zu was not found.", key);
+		return -1;
+	}
+
+	printf("Record %zu deleted.\n", key);
+	return 0;
+}
+
+/*
+ * display key/val pair from database
+ *
+ * @key: key id
+ * 
+ * return 0 on success, -1 otherwise
+ */
+int dbget(size_t key)
+{
+	DBT k =  {};
+	DBT d =  {};
+	k.data = &key;
+	k.size = sizeof key;
+	int rc;
+
+	rc = btreedb->get(btreedb, &k, &d, 0);
+
+	if (rc == -1) {
+		warn("Failed to grab record %zu.", key);
+		return -1;
+	}
+
+	if (rc) {
+		warnx("record %zu was not found.", key);
+		return -1;
+	}
+
+	printf("-> %s.\n", (char *)d.data);
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	char *dbname = NULL;
+	char buf[PATH_MAX];
+	/* btree */
+	BTREEINFO type = {};
+
+	/* opt */
+	int ch;
+	while ((ch = getopt_long(argc, argv, "d:", longopts, NULL)) != -1) {
+		switch (ch) {
+			case 'd':
+				dbname = optarg;
+				break;
+			case 0:
+				/* long option */
+				break;
+			default:
+				usage();
+		}
+	}
+
+	if (optind != argc)
+		usage();
+
+	if (dbname == NULL) {
+		const char *t = getenv("TMPDIR");
+		if (t == NULL)
+			t = "/tmp";
+		(void)snprintf(buf, sizeof(buf), "%s/david", t);
+		dbname = buf;
+	}
+
+	type.compare = compare;
+	btreedb= dbopen(dbname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, DB_BTREE, &type);
+
+	if (!btreedb)
+		err(EXIT_FAILURE, "Database unreachable:");
+
+	while (!do_quit) {
+		yyparse();
+	}
+
+	btreedb->close(btreedb);
+
+	printf("Data stored into %s.\n", dbname);
+}
+

+ 95 - 0
btree/btest.c

@@ -0,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <db.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <err.h>
+#include <string.h>
+#include <sys/types.h>
+#include <malloc_np.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include "bcompare.h"
+
+/* MALLOC_CONF=stats_print:true,junk:true */
+static DB * btreedb;
+#define KEYDATA_MAX 64
+
+
+static struct option longopts[] = {
+	{ "db",   required_argument,      NULL, 'd' },
+	{ "size",   required_argument,      NULL, 's' },
+	{ NULL,	0, NULL, 0 }
+};
+
+__attribute__((noreturn)) static int usage(void)
+{
+	fputs("btest [--db filename]\n", stderr);
+	exit (EXIT_SUCCESS);
+}
+
+
+int main(int argc, char *argv[])
+{
+	char *dbname = NULL;
+	size_t loops = 100;
+	char buf[PATH_MAX];
+	BTREEINFO type = {};
+	DBT key =  {};
+	key.data = malloc(sizeof (size_t));
+	DBT data = {};
+	data.data = malloc(KEYDATA_MAX);
+	size_t j;
+	key.data = &j;
+	key.size = sizeof j;
+
+
+	int ch;
+	while ((ch = getopt_long(argc, argv, "s:d:", longopts, NULL)) != -1) {
+		switch (ch) {
+			case 's':
+				loops = strtoul(optarg, NULL, 10);
+				break;
+			case 'd':
+				dbname = optarg;
+				break;
+			case 0:
+				/* long option */
+				break;
+			default:
+				usage();
+		}
+	}
+
+	if (optind != argc)
+		usage();
+
+	if (dbname == NULL) {
+		const char *t = getenv("TMPDIR");
+		if (t == NULL)
+			t = "/tmp";
+		(void)snprintf(buf, sizeof(buf), "%s/david", t);
+		dbname = buf;
+	}
+
+	type.compare = compare;
+	btreedb= dbopen(dbname, O_CREAT | O_RDWR | O_SYNC , S_IRUSR | S_IWUSR, DB_BTREE, &type);
+
+	if (!btreedb)
+		err(EXIT_FAILURE, "Database unreachable:");
+
+
+	for (j = 0; j < loops; ++j) {
+		data.size = (size_t)snprintf(data.data, KEYDATA_MAX,  "coucou %zu", j);
+		if (btreedb->put(btreedb, &key, &data, R_NOOVERWRITE)) {
+			warnx("Failed to insert data: %zu", j);
+		}
+	}
+
+	free(data.data);
+	btreedb->close(btreedb);
+
+	printf("Data stored into %s.\n", dbname);
+}
+

+ 12 - 0
btree/gram.l

@@ -0,0 +1,12 @@
+%{
+#include "y.tab.h"
+%}
+%%
+[0-9]+	{ yylval.number=strtoul(yytext, NULL, 10); return KEY;}
+(\"(\\.|[^"])*\") { yylval.string=strdup(yytext); return STRING;}
+insert	{ return INSERT;}
+delete	{ return DELETE;}
+get		{ return GET;}
+quit	{ return QUIT;}
+. { ; }
+

+ 79 - 0
btree/parse.y

@@ -0,0 +1,79 @@
+/* parser */
+%{
+#include <stdio.h>
+extern int yylineno;
+extern int do_quit;
+static void yyerror(const char *);
+
+static void yyerror(const char *errmsg)
+{
+    fprintf(stderr, "ruleset line %d: %s.", yylineno - 1, errmsg);
+}
+
+int yywrap(void)
+{
+    return (1);
+}
+
+int dbinsert(size_t key, char *data);
+int dbdelete(size_t key);
+int dbget(size_t key);
+
+%}
+
+%union 
+{
+        size_t number;
+        char *string;
+}
+
+%token <number> KEY
+%token <string> STRING
+
+%token QUOTE INSERT DELETE GET QUIT
+
+%%
+
+
+
+ruleset:	/*empty*/
+	|	ruleset	command
+	;
+
+command:	
+	insert
+	|
+	delete
+	|
+	get
+	|
+	quit
+	;
+
+insert:
+	INSERT	KEY STRING
+	{
+		dbinsert($2, $3);
+	}
+	;
+	
+delete:
+	DELETE	KEY
+	{
+		dbdelete($2);
+	}
+	;
+get:
+	GET	KEY
+	{
+		dbget($2);
+	}
+	;
+quit:
+	QUIT
+	{
+		do_quit = 1;
+		YYACCEPT;
+	}
+	;
+%%

+ 1 - 1
kqueue/kq_timer.c

@@ -31,7 +31,7 @@ void file_close(FILE **fd) {
 }
 #define _smartfile __attribute((cleanup(file_close)))
 
-[[noreturn]] static int usage(void)
+__attribute__((noreturn))static int usage(void)
 {
 	fputs("kq_timer [--verbose] [--period ms]\n", stderr);
 	exit (EXIT_SUCCESS);