Keystore
1 Overview
2 Structure
keystore
keystore?
3 Opening & Closing
ks-open
ks-close
4 Basic Operations
ks-set!
ks-get
ks-exists?
ks-key-count
ks-drop!
5 Enumeration
ks-keys
ks-key-values
6 Glob Queries
ks-keys-glob
ks-key-values-glob
7 Raw Access
ks-keys-raw
ks-key-values-raw
8 Transactions
ks-transaction
ks-commit
ks-begin-transaction
ks-end-transaction
ks-abort-transaction
9 Locking
ks-with-lock
10 Examples
10.1 Basic Usage
10.2 Enumeration Example
10.3 Glob Query Example
10.4 Locking Example
9.3

Keystore🔗ℹ

 (require keystore) package: keystore

A small persistent key-value store backed by SQLite. Keys and values may be arbitrary Racket values and are stored using transparent serialization.

1 Overview🔗ℹ

The keystore provides persistent storage with automatic serialization and deserialization. Keys are additionally stored in a stringified lowercase form, which allows glob-style queries.

2 Structure🔗ℹ

struct

(struct keystore (file path dbh lock-sem in-lock entered))

  file : any/c
  path : path?
  dbh : any/c
  lock-sem : semaphore?
  in-lock : (or/c thread? #f)
  entered : exact-nonnegative-integer?
Represents an open keystore. The file field contains the original argument, path is the resolved database path, and dbh is the SQLite connection. The remaining fields implement the reentrant lock used by ks-with-lock: lock-sem serializes access, in-lock records the thread that holds the lock, and entered records that thread’s nesting depth. The in-lock and entered fields are mutable internal state.

The keystore? predicate is altered to also check if the database connection is (still) valid.

procedure

(keystore? ks)  boolean?

  ks : any/c
Returns #t, if ks is a valid keystore. Returns #f, otherwise.

Note. When a previously opened keystore (which is valid), is closed with ks-close, keystore? will return #f, because the keystore is not valid anymore.

3 Opening & Closing🔗ℹ

procedure

(ks-open file)  keystore?

  file : (or/c path? string? symbol?)
Opens or creates a keystore. When file is a symbol, a cache location is used; otherwise it is interpreted as a filesystem path. The database schema is created automatically if it does not yet exist.

procedure

(ks-close ks)  boolean?

  ks : keystore?
Closes the keystore. The keystore handle is invalidated after closing the underlying storage (database).

4 Basic Operations🔗ℹ

procedure

(ks-set! ks key value)  boolean?

  ks : keystore?
  key : any/c
  value : any/c
Stores value under key, replacing any existing value. The function always returns #t.

procedure

(ks-get ks key default ...)  any/c

  ks : keystore?
  key : any/c
  default : any/c
Retrieves the value associated with key. If the key is not present, the provided default value is returned when given; otherwise the symbol 'ks-nil is returned.

procedure

(ks-exists? ks key)  boolean?

  ks : keystore?
  key : any/c
Returns #t if the key exists, and #f otherwise.

procedure

(ks-key-count ks)  number?

  ks : keystore?
Returns the number of keys in the keystore.

procedure

(ks-drop! ks key)  boolean?

  ks : keystore?
  key : any/c
Removes the key from the store. The function always returns #t.

5 Enumeration🔗ℹ

procedure

(ks-keys ks)  (listof any/c)

  ks : keystore?
Returns all keys in the store.

procedure

(ks-key-values ks)  (listof (cons/c any/c any/c))

  ks : keystore?
Returns all key-value pairs as cons cells.

6 Glob Queries🔗ℹ

Glob queries operate on a lowercase string representation of keys.

procedure

(ks-keys-glob ks pattern)  (listof any/c)

  ks : keystore?
  pattern : string?
Returns all keys whose string form matches pattern.

procedure

(ks-key-values-glob ks pattern)  (listof (cons/c any/c any/c))

  ks : keystore?
  pattern : string?
Returns key-value pairs whose keys match pattern.

7 Raw Access🔗ℹ

procedure

(ks-keys-raw ks)  list?

  ks : keystore?
Returns raw key rows in the form:

(list key-string str-key)

procedure

(ks-key-values-raw ks)  list?

  ks : keystore?
Returns raw key-value rows in the form:

(list key-string str-key value-string)

8 Transactions🔗ℹ

syntax

(ks-transaction [ks keystore?] b1 ...)

Puts b1 ... in a "BEGIN/COMMIT" transaction. It uses with-handlers exn?, so if you raise an exception, it will do a "BEGIN/ROLLBACK" abd re-raise the exception.

procedure

(ks-commit ks)  boolean?

  ks : keystore?
Commits (part of a transaction) using COMMIT/BEGIN. Fits in a ks-transaction form.

procedure

(ks-begin-transaction ks)  boolean?

  ks : keystore?
Begins a transaction with "BEGIN".

procedure

(ks-end-transaction ks)  boolean?

  ks : keystore?
Commits a transaction with "COMMIT".

procedure

(ks-abort-transaction ks)  boolean?

  ks : keystore?
Aborts a transaction with "ROLLBACK".

9 Locking🔗ℹ

procedure

(ks-with-lock ks proc)  any/c

  ks : keystore?
  proc : (-> any/c)
Calls proc while holding the lock belonging to ks and returns the value produced by proc. Other threads using ks-with-lock with the same keystore handle wait until the lock is released.

The lock is reentrant: proc may call ks-with-lock again on the same handle and thread. The lock is released when control leaves proc, including when an exception is raised.

The lock coordinates only code that uses the same keystore handle and explicitly calls ks-with-lock. Individual keystore operations do not acquire it automatically.

10 Examples🔗ℹ

10.1 Basic Usage🔗ℹ

(define ks (ks-open 'demo))
 
(ks-set! ks 'a 42)
(ks-set! ks "b" '(1 2 3))
 
(ks-get ks 'a)
(ks-get ks 'missing)
(ks-get ks 'missing 0)

10.2 Enumeration Example🔗ℹ

(ks-keys ks)
 
 
(ks-key-values ks)

10.3 Glob Query Example🔗ℹ

(ks-keys-glob ks "*b*")

10.4 Locking Example🔗ℹ

(ks-with-lock
 ks
 (λ ()
   (ks-set! ks 'counter
            (add1 (ks-get ks 'counter 0)))))