Code review.

draft
kimory 2022-10-18 22:31:47 +02:00
parent b3a50358ab
commit 32155d7690
1 changed files with 55 additions and 49 deletions

View File

@ -36,14 +36,14 @@
; db/new ensures directory '<path>/data/' exist,
; then loads values from existing files, if any, and puts them into db-data.
(defun db/new (path)
(let ((data (make-hash-table))
(let ((data (make-hash-table))
(data-dir-path (concatenate 'string path "/data/"))
(current-index 0))
(ensure-directories-exist data-dir-path)
(loop for filename in (osicat:list-directory data-dir-path)
do (let ((id (filename->integer filename))
do (let ((id (filename->integer filename))
(value (util:read-object-from-file filename)))
(if (> id current-index)
(setf current-index id))
@ -54,7 +54,6 @@
:data data
:current-index current-index)))
; Example: ./storage/cars 18 -> ./storage/cars/data/000000000000018
; USAGE: when dealing with hash keys from the in-memory db.
; The hash key is the number used to build the filename.
@ -62,35 +61,36 @@
(concatenate 'string dbpath "/data/" (number->filename number)))
; Example: returns "./storage/cars/indexes/by_name/".
(defun db/index/get-directory-path (dbpath object-attribute)
(let ((name (typecase object-attribute
(string object-attribute)
(symbol (symbol-name object-attribute))
(t (format nil "~A" object-attribute)))))
(concatenate 'string dbpath "/indexes/by_" name "/")))
(defun db/index/get-directory-path (dbpath index-name)
(concatenate 'string dbpath "/indexes/by_" index-name "/"))
; Example: returns "./storage/cars/partitions/by_color/Red/".
(defun db/partition/get-directory-path (dbpath name object-attribute)
(let ((value (typecase object-attribute
(string object-attribute)
(symbol (symbol-name object-attribute))
(t (format nil "~A" object-attribute)))))
(t (format nil "~A" object-attribute)))))
(concatenate 'string dbpath "/partitions/by_" name "/" value "/")))
; Example: dbpath "name" #'vehicle-name object -> "./storage/cars/indexes/by_name/Corvet".
; Example: "./storage/cars/" "name" #'vehicle-name object -> "./storage/cars/indexes/by_name/Corvet".
(defun db/index/get-symlink-path (dbpath index-name fsymbol object)
(concatenate 'string
(db/index/get-directory-path dbpath index-name)
(funcall fsymbol object)))
(let* ((value (funcall fsymbol object))
(symlink-basename (typecase value
(string value)
(symbol (symbol-name value))
(t (format nil "~A" value)))))
(concatenate 'string
(db/index/get-directory-path dbpath index-name)
symlink-basename)))
; Example: dbpath "name" #'vehicle-name object "0000000015"
; Example: "./storage/cars/" "name" #'vehicle-name object "0000000015"
; -> (osicat:make-link "./storage/cars/indexes/by_name/Corvet"
; :target "../../data/0000000015"
; :hard nil)
(defun db/index/new (dbpath index-name fsymbol object file-name)
(let ((symlink-path (db/index/get-symlink-path dbpath index-name fsymbol object)))
; Works even when the database directory is moved.
; works even when the database directory is moved
(osicat:make-link symlink-path
:target (concatenate 'string "../../data/" file-name)
:hard nil)))
@ -98,17 +98,16 @@
(defun db/index/del (dbpath index-name fsymbol object)
(delete-file (db/index/get-symlink-path dbpath index-name fsymbol object)))
; Example: dbpath "color" #'vehicle-color object
; Example: "./storage/cars/" "color" #'vehicle-color object "0000000015".
; -> "./storage/cars/partitions/by_color/Red/0000000015".
(defun db/partition/get-symlink-path (dbpath partition-name fsymbol object file-name)
(concatenate 'string
(db/partition/get-directory-path dbpath partition-name
; example: "Red"
(funcall fsymbol object))
; example: "./storage/cars/partitions/by_color/Red/"
(db/partition/get-directory-path dbpath partition-name (funcall fsymbol object))
; example: "0000000015"
file-name))
; Example: dbpath "color" #'vehicle-color object "0000000015"
; Example: "./storage/cars/" "color" #'vehicle-color object "0000000015"
; -> (osicat:make-link "./storage/cars/partitions/by_color/Red/0000000015"
; :target "../../../data/0000000015"
; :hard nil)
@ -118,7 +117,7 @@
(ensure-directories-exist symlink-path)
; Works even when the database directory is moved.
; works even when the database directory is moved
(osicat:make-link symlink-path
:target (concatenate 'string "../../../data/" file-name)
:hard nil)))
@ -126,21 +125,20 @@
(defun db/partition/del (dbpath partition-name fsymbol object file-basename)
(delete-file (db/partition/get-symlink-path dbpath partition-name fsymbol object file-basename)))
; Example: db-path/indexes/by_name/
(defun db/new-index (database attribute-name fsymbol)
(defun db/new-index (database index-name fsymbol)
(let ((dbpath (db-path database)))
; create a directory for the indexes
(ensure-directories-exist
(concatenate 'string dbpath "/indexes/by_" attribute-name "/"))
(concatenate 'string dbpath "/indexes/by_" index-name "/"))
; add this new index to the list
(setf (gethash attribute-name (db-indexes database)) fsymbol)
(setf (gethash index-name (db-indexes database)) fsymbol)
; generate index for all DB elements
(maphash #'(lambda (number object)
(handler-case (db/index/new dbpath attribute-name fsymbol object (number->filename number))
(handler-case (db/index/new dbpath index-name fsymbol object (number->filename number))
(OSICAT-POSIX:EEXIST ()
(format t "db/new-index: symlink already exists, ignoring.~&"))))
(format t "dodb:db/new-index: symlink already exists, ignoring.~&"))))
(db-data database))))
(defun db/partition/update (dbpath partition-name fsymbol object file-name old-object)
@ -151,30 +149,29 @@
; delete old partition
(db/partition/del dbpath partition-name fsymbol old-object file-name)
; create new partition
(db/partition/new dbpath partition-name fsymbol object file-name)))))
(db/partition/new dbpath partition-name fsymbol object file-name)))))
; Example: db-path/partitions/by_color/
(defun db/new-partition (database attribute-name fsymbol)
(let (dbpath (db-path database))
(defun db/new-partition (database partition-name fsymbol)
(let ((dbpath (db-path database)))
; create a directory for the partitions
(ensure-directories-exist
(concatenate 'string dbpath "/partitions/by_" attribute-name "/"))
(concatenate 'string dbpath "/partitions/by_" partition-name "/"))
; add this new partition to the list
(setf (gethash attribute-name (db-partitions database)) fsymbol)
(setf (gethash partition-name (db-partitions database)) fsymbol)
; generate partition for all DB elements
(maphash #'(lambda (number object)
(handler-case (db/partition/new dbpath attribute-name fsymbol object (number->filename number))
(handler-case (db/partition/new dbpath partition-name fsymbol object (number->filename number))
(OSICAT-POSIX:EEXIST ()
(format t "db/new-partition: symlink already exists, ignoring.~&"))))
(format t "dodb:db/new-partition: symlink already exists, ignoring.~&"))))
(db-data database))))
; Example: database -> "000000000000018".
(defun db/add/new-data-basename (database)
(number->filename (db-current-index database)))
; Example: {db-path}/data/000000000000018.
; Example: "./storage/cars/data/000000000000018".
(defun get-filepath (dbpath file-name)
(concatenate 'string dbpath "/data/" file-name))
@ -227,25 +224,34 @@
(remhash object-index (db-data database))))
; Search for the data from the FS.
(defun db/get-by-index (database index-name value)
(filename->integer
(osicat:read-link
(concatenate 'string
(db/index/get-directory-path (db-path database) index-name) "/" value))))
(defun db/get-by-index (database index-name attribute-value)
(let ((value (typecase attribute-value
(string attribute-value)
(symbol (symbol-name attribute-value))
(t (format nil "~A" attribute-value)))))
(filename->integer
(osicat:read-link
(concatenate 'string
(db/index/get-directory-path (db-path database) index-name) "/" value)))))
; Search for the data from the FS.
(defun db/get-by-partition (database name value)
(loop for filename in (osicat:list-directory (db/partition/get-directory-path database name value))
collect (filename->integer filename)))
(defun db/get-by-partition (database name attribute-value)
(let ((value (typecase attribute-value
(string attribute-value)
(symbol (symbol-name attribute-value))
(t (format nil "~A" attribute-value))))
(dbpath (db-path database)))
(loop for filename in (osicat:list-directory (db/partition/get-directory-path dbpath name value))
collect (filename->integer filename))))
(defun db/index/update (dbpath index-name fsymbol object file-name old-object)
(let* ((new-value (funcall fsymbol object))
(old-value (funcall fsymbol old-object))
(symlink-path (db/index/get-symlink-path dbpath index-name fsymbol object)))
(let ((new-value (funcall fsymbol object))
(old-value (funcall fsymbol old-object))
(symlink-path (db/index/get-symlink-path dbpath index-name fsymbol object)))
(if (not (equal new-value old-value))
; display a message in case the new index is already used by another object
(if (probe-file symlink-path)
(format t "db/index/update: the value ~a is already used by another object.~&" new-value)
(format t "dodb:db/index/update: the value ~a is already used by another object.~&" new-value)
(progn
; delete old index
(db/index/del dbpath index-name fsymbol old-object)