changelog shortlog graph tags branches changeset file revisions annotate raw help

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

revision 18: 61482ce290f9
child 45: ad67a57b0134
     1.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2+++ b/lisp/lib/rdb/pkg.lisp	Mon Oct 23 23:33:06 2023 -0400
     1.3@@ -0,0 +1,205 @@
     1.4+;;; rdb.lisp --- High-level RocksDB API
     1.5+
     1.6+;; a thin ORM for working with RocksDB storage. 
     1.7+
     1.8+;; Low-level bindings are in rocksdb.lisp.
     1.9+
    1.10+;; Commentary:
    1.11+
    1.12+;; Code:
    1.13+(uiop:define-package :rdb/pkg
    1.14+  (:nicknames :rdb)
    1.15+  (:use :cl :std/alien :std/fu :rocksdb)
    1.16+  (:import-from :sb-ext :string-to-octets :octets-to-string)
    1.17+  (:reexport :rocksdb)
    1.18+  (:export 
    1.19+   ;; opts
    1.20+   :make-rdb-opts
    1.21+   :rdb-opts
    1.22+   :default-rdb-opts
    1.23+   ;; db
    1.24+   :open-db
    1.25+   :with-open-db 
    1.26+   ;; iter
    1.27+   :create-iter :with-iter
    1.28+   :iter-key :iter-key-str
    1.29+   :iter-val :iter-val-str
    1.30+   ;; err
    1.31+   :unable-to-open-db 
    1.32+   :unable-to-put-key-value-to-db 
    1.33+   :unable-to-get-value-to-db))
    1.34+
    1.35+(in-package :rdb/pkg)
    1.36+
    1.37+(defstruct rdb-opts
    1.38+  (create-if-missing nil :type boolean)
    1.39+  (total-threads 1 :type integer) ;; numcpus is default
    1.40+  (max-open-files 10000 :type integer)
    1.41+  (use-fsync nil :type boolean)
    1.42+  (disable-auto-compations nil :type boolean))
    1.43+
    1.44+;; unsafe
    1.45+(defun bind-rocksdb-opts% (opts)
    1.46+  (let ((o (rocksdb-options-create)))
    1.47+    (with-slots (create-if-missing total-threads) opts
    1.48+      (rocksdb-options-set-create-if-missing o create-if-missing)
    1.49+      (rocksdb-options-increase-parallelism o total-threads))
    1.50+    o))
    1.51+
    1.52+(defun default-rdb-opts () 
    1.53+  (make-rdb-opts
    1.54+   :create-if-missing t 
    1.55+   :total-threads 4))
    1.56+
    1.57+(defun default-rocksdb-options% ()
    1.58+  (bind-rocksdb-opts% (default-rdb-opts)))
    1.59+
    1.60+(defmacro with-open-db ((db-var db-path &optional opt) &body body)
    1.61+  `(let ((,db-var (open-db ,db-path ,opt)))
    1.62+     (unwind-protect (progn ,@body)
    1.63+       (rocksdb-close ,db-var))))
    1.64+
    1.65+(defmacro with-iter ((iter-var db &optional opt) &body body)
    1.66+  `(let ((,iter-var (create-iter ,db ,opt)))
    1.67+     (unwind-protect (progn ,@body)
    1.68+       (rocksdb-iter-destroy ,iter-var))))
    1.69+
    1.70+;;; Conditions
    1.71+(define-condition unable-to-open-db (error)
    1.72+  ((db-path :initarg :db-path
    1.73+            :reader db-path)
    1.74+   (error-message :initarg :error-message
    1.75+                  :reader error-message)))
    1.76+
    1.77+(defmethod print-object ((obj unable-to-open-db) stream)
    1.78+  (print-unreadable-object (obj stream :type t :identity t)
    1.79+    (format stream "error-message=~A" (error-message obj))))
    1.80+
    1.81+(define-condition unable-to-put-key-value-to-db (error)
    1.82+  ((db :initarg :db
    1.83+       :reader db)
    1.84+   (key :initarg :key
    1.85+        :reader key)
    1.86+   (val :initarg :val
    1.87+        :reader val)
    1.88+   (error-message :initarg :error-message
    1.89+                  :reader error-message)))
    1.90+
    1.91+(define-condition unable-to-get-value-to-db (error)
    1.92+  ((db :initarg :db
    1.93+       :reader db)
    1.94+   (key :initarg :key
    1.95+        :reader key)
    1.96+   (error-message :initarg :error-message
    1.97+                  :reader error-message)))
    1.98+
    1.99+;;; API
   1.100+(defun open-db (db-path &optional opts)
   1.101+  (let ((opts (if opts (bind-rocksdb-opts% opts) (default-rocksdb-options%))))
   1.102+    (with-alien ((e rocksdb-errptr))
   1.103+      (let* ((db-path (if (pathnamep db-path)
   1.104+                          (namestring db-path)
   1.105+                          db-path))
   1.106+             (db (rocksdb-open opts db-path e)))
   1.107+	(if (null-alien e)
   1.108+            db
   1.109+            (error 'unable-to-open-db
   1.110+                   :db-path db-path
   1.111+                   :error-message e))))))
   1.112+
   1.113+(defun put-kv (db key val &optional opts)
   1.114+  (let ((opts (or opts (rocksdb-writeoptions-create)))
   1.115+	(klen (length key))
   1.116+	(vlen (length val)))
   1.117+    (with-alien ((errptr rocksdb-errptr nil)
   1.118+		 (k (* char) (make-alien char klen))
   1.119+		 (v (* char) (make-alien char vlen)))
   1.120+      (loop for x across key
   1.121+	    for i from 0 below klen
   1.122+	    do (setf (deref k i) x))
   1.123+      (loop for y across val
   1.124+	    for i from 0 below vlen
   1.125+	    do (setf (deref v i) y))
   1.126+      (rocksdb-put db
   1.127+		   opts
   1.128+		   k
   1.129+		   klen
   1.130+		   v
   1.131+		   vlen
   1.132+		   errptr)
   1.133+      (unless (null-alien errptr)
   1.134+        (error 'unable-to-put-key-value-to-db
   1.135+                :db db
   1.136+                :key key
   1.137+                :val val
   1.138+                :error-message (alien-sap errptr))))))
   1.139+
   1.140+(defun put-kv-str (db key val &optional opt)
   1.141+  (let ((key-octets (string-to-octets key))
   1.142+        (val-octets (string-to-octets val)))
   1.143+    (put-kv db key-octets val-octets opt)))
   1.144+
   1.145+(defun get-kv (db key &optional opt)
   1.146+  (let ((opt (or opt (rocksdb-readoptions-create)))
   1.147+	(key (string-to-octets key))
   1.148+	(klen (length key)))
   1.149+    (with-alien ((vlen (* size-t))
   1.150+		 (errptr rocksdb-errptr nil)
   1.151+		 (k (* char) (make-alien char klen)))
   1.152+      (loop for x across key
   1.153+	    for i from 0 below klen
   1.154+	    do (setf (deref k i) x))
   1.155+
   1.156+      (let* ((val (rocksdb-get db
   1.157+			      opt
   1.158+			      k
   1.159+			      klen
   1.160+			      vlen
   1.161+			      errptr))
   1.162+	     (vlen (deref vlen)))
   1.163+	(unless (null-alien errptr)
   1.164+          (error 'unable-to-get-value-to-db
   1.165+		 :db db
   1.166+		 :key key
   1.167+		 :error-message (alien-sap errptr)))
   1.168+	;; helps if we know the vlen beforehand, would need a custom
   1.169+	;; C-side function probably.
   1.170+	(let ((v (make-array vlen :element-type 'unsigned-byte)))
   1.171+	  (loop for i from 0 below vlen
   1.172+		with x = (deref val i) 
   1.173+		do (setf (aref v i) x))
   1.174+	  (map 'vector #'code-char v))))))
   1.175+
   1.176+ (defun get-kv-str (db key &optional opt)
   1.177+   (let ((k (string-to-octets key)))
   1.178+     (let ((v (get-kv db k opt)))
   1.179+       (when v (print v)))))
   1.180+
   1.181+(defun create-iter (db &optional opt)
   1.182+  (unless opt
   1.183+    (setq opt (rocksdb-readoptions-create)))
   1.184+  (rocksdb-create-iterator db opt))
   1.185+
   1.186+(defun iter-key (iter)
   1.187+  (with-alien ((klen-ptr (* unsigned-int)))
   1.188+    (let* ((key-ptr (rocksdb-iter-key iter klen-ptr))
   1.189+           (klen (deref klen-ptr))
   1.190+           (k (make-array klen :element-type '(unsigned-byte 8))))
   1.191+      (loop for i from 0 below klen with x = (deref key-ptr i) do (setf (aref k i) x))
   1.192+      k)))
   1.193+
   1.194+(defun iter-key-str (iter)
   1.195+  (when-let ((k (iter-key iter)))
   1.196+    (octets-to-string k)))
   1.197+
   1.198+ (defun iter-val (iter)
   1.199+   (with-alien ((vlen-ptr (* unsigned-int)))
   1.200+     (let* ((val-ptr (rocksdb-iter-value iter vlen-ptr))
   1.201+            (vlen (deref vlen-ptr))
   1.202+            (v (make-array vlen :element-type '(unsigned-byte 8))))
   1.203+       (loop for i from 0 below vlen with x = (deref val-ptr i) do (setf (aref v i) x))
   1.204+       v)))
   1.205+
   1.206+ (defun iter-val-str (iter)
   1.207+   (when-let ((v (iter-val iter)))
   1.208+     (octets-to-string v)))