changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/lib/rdb/pkg.lisp

changeset 45: ad67a57b0134
parent: 61482ce290f9
child: 01f7dc4d7a8e
author: ellis <ellis@rwest.io>
date: Tue, 21 Nov 2023 17:14:06 -0500
permissions: -rw-r--r--
description: rocksdb bindings and emacs config
1 ;;; rdb.lisp --- High-level RocksDB API
2 
3 ;; a thin ORM for working with RocksDB storage.
4 
5 ;; Low-level bindings are in rocksdb.lisp.
6 
7 ;; Commentary:
8 
9 ;; Code:
10 (uiop:define-package :rdb/pkg
11  (:nicknames :rdb)
12  (:use :cl :std/alien :std/fu :rocksdb)
13  (:import-from :sb-ext :string-to-octets :octets-to-string)
14  (:reexport :rocksdb)
15  (:export
16  ;; opts
17  :make-rdb-opts
18  :rdb-opts
19  :default-rdb-opts
20  ;; db
21  :open-db
22  :with-open-db
23  ;; iter
24  :create-iter :with-iter
25  :iter-key :iter-key-str
26  :iter-val :iter-val-str
27  ;; err
28  :unable-to-open-db
29  :unable-to-put-key-value-to-db
30  :unable-to-get-value-to-db))
31 
32 (in-package :rdb/pkg)
33 
34 (defstruct rdb-opts
35  (create-if-missing nil :type boolean)
36  (total-threads 1 :type integer) ;; numcpus is default
37  (max-open-files 10000 :type integer)
38  (use-fsync nil :type boolean)
39  (disable-auto-compactions nil :type boolean))
40 
41 ;; unsafe
42 (defun bind-rocksdb-opts% (opts)
43  (let ((o (rocksdb-options-create)))
44  (with-slots (create-if-missing total-threads) opts
45  (rocksdb-options-set-create-if-missing o create-if-missing)
46  (rocksdb-options-increase-parallelism o total-threads))
47  o))
48 
49 (defun default-rdb-opts ()
50  (make-rdb-opts
51  :create-if-missing t
52  :total-threads 4))
53 
54 (defun default-rocksdb-options% ()
55  (bind-rocksdb-opts% (default-rdb-opts)))
56 
57 (defmacro with-open-db ((db-var db-path &optional opt) &body body)
58  `(let ((,db-var (open-db ,db-path ,opt)))
59  (unwind-protect (progn ,@body)
60  (rocksdb-close ,db-var))))
61 
62 (defmacro with-iter ((iter-var db &optional opt) &body body)
63  `(let ((,iter-var (create-iter ,db ,opt)))
64  (unwind-protect (progn ,@body)
65  (rocksdb-iter-destroy ,iter-var))))
66 
67 ;;; Conditions
68 (define-condition unable-to-open-db (error)
69  ((db-path :initarg :db-path
70  :reader db-path)
71  (error-message :initarg :error-message
72  :reader error-message)))
73 
74 (defmethod print-object ((obj unable-to-open-db) stream)
75  (print-unreadable-object (obj stream :type t :identity t)
76  (format stream "error-message=~A" (error-message obj))))
77 
78 (define-condition unable-to-put-key-value-to-db (error)
79  ((db :initarg :db
80  :reader db)
81  (key :initarg :key
82  :reader key)
83  (val :initarg :val
84  :reader val)
85  (error-message :initarg :error-message
86  :reader error-message)))
87 
88 (define-condition unable-to-get-value-to-db (error)
89  ((db :initarg :db
90  :reader db)
91  (key :initarg :key
92  :reader key)
93  (error-message :initarg :error-message
94  :reader error-message)))
95 
96 ;;; API
97 (defun open-db (db-path &optional opts)
98  (let ((opts (if opts (bind-rocksdb-opts% opts) (default-rocksdb-options%))))
99  (with-alien ((e rocksdb-errptr))
100  (let* ((db-path (if (pathnamep db-path)
101  (namestring db-path)
102  db-path))
103  (db (rocksdb-open opts db-path e)))
104  (if (null-alien e)
105  db
106  (error 'unable-to-open-db
107  :db-path db-path
108  :error-message e))))))
109 
110 (defun put-kv (db key val &optional opts)
111  (let ((opts (or opts (rocksdb-writeoptions-create)))
112  (klen (length key))
113  (vlen (length val)))
114  (with-alien ((errptr rocksdb-errptr nil)
115  (k (* char) (make-alien char klen))
116  (v (* char) (make-alien char vlen)))
117  (loop for x across key
118  for i from 0 below klen
119  do (setf (deref k i) x))
120  (loop for y across val
121  for i from 0 below vlen
122  do (setf (deref v i) y))
123  (rocksdb-put db
124  opts
125  k
126  klen
127  v
128  vlen
129  errptr)
130  (unless (null-alien errptr)
131  (error 'unable-to-put-key-value-to-db
132  :db db
133  :key key
134  :val val
135  :error-message (alien-sap errptr))))))
136 
137 (defun put-kv-str (db key val &optional opt)
138  (let ((key-octets (string-to-octets key))
139  (val-octets (string-to-octets val)))
140  (put-kv db key-octets val-octets opt)))
141 
142 (defun get-kv (db key &optional opt)
143  (let ((opt (or opt (rocksdb-readoptions-create)))
144  (key (string-to-octets key))
145  (klen (length key)))
146  (with-alien ((vlen (* size-t))
147  (errptr rocksdb-errptr nil)
148  (k (* char) (make-alien char klen)))
149  (loop for x across key
150  for i from 0 below klen
151  do (setf (deref k i) x))
152 
153  (let* ((val (rocksdb-get db
154  opt
155  k
156  klen
157  vlen
158  errptr))
159  (vlen (deref vlen)))
160  (unless (null-alien errptr)
161  (error 'unable-to-get-value-to-db
162  :db db
163  :key key
164  :error-message (alien-sap errptr)))
165  ;; helps if we know the vlen beforehand, would need a custom
166  ;; C-side function probably.
167  (let ((v (make-array vlen :element-type 'unsigned-byte)))
168  (loop for i from 0 below vlen
169  with x = (deref val i)
170  do (setf (aref v i) x))
171  (map 'vector #'code-char v))))))
172 
173  (defun get-kv-str (db key &optional opt)
174  (let ((k (string-to-octets key)))
175  (let ((v (get-kv db k opt)))
176  (when v (print v)))))
177 
178 (defun create-iter (db &optional opt)
179  (unless opt
180  (setq opt (rocksdb-readoptions-create)))
181  (rocksdb-create-iterator db opt))
182 
183 (defun iter-key (iter)
184  (with-alien ((klen-ptr (* unsigned-int)))
185  (let* ((key-ptr (rocksdb-iter-key iter klen-ptr))
186  (klen (deref klen-ptr))
187  (k (make-array klen :element-type '(unsigned-byte 8))))
188  (loop for i from 0 below klen with x = (deref key-ptr i) do (setf (aref k i) x))
189  k)))
190 
191 (defun iter-key-str (iter)
192  (when-let ((k (iter-key iter)))
193  (octets-to-string k)))
194 
195  (defun iter-val (iter)
196  (with-alien ((vlen-ptr (* unsigned-int)))
197  (let* ((val-ptr (rocksdb-iter-value iter vlen-ptr))
198  (vlen (deref vlen-ptr))
199  (v (make-array vlen :element-type '(unsigned-byte 8))))
200  (loop for i from 0 below vlen with x = (deref val-ptr i) do (setf (aref v i) x))
201  v)))
202 
203  (defun iter-val-str (iter)
204  (when-let ((v (iter-val iter)))
205  (octets-to-string v)))