Arc Forumnew | comments | leaders | submitlogin
Super simple persistent hash tables
5 points by drcode 5924 days ago | 1 comment
Just wrote some functions for creating some persistent hash tables. Note that pg makes references to this idea in arc.arc comments, so this is just a stopgap to tie you over.

Note that this would could be more elegant with ac.scm changes, which I assume would be part of pg's implementation.

This code also includes functions for serializing arbitrary arc structures that may contain tables (no sharing detection though, if you care) These seem a lot simpler and flexible than the table serializing functions in arc.arc- Not sure why you wouldn't make something like this the default read/write behavior for tables and make serializing easier...

To create a "permanent" hash table:

  arc> (= foo (perm 'test))
  #hash((%dir . "perm/test/"))
Notice that the table is given a directory name as a special key, indicating where it should be serialized.

  arc> (permset foo 'bar 5)  
  5
  arc> foo
  #hash((bar . 5) (%dir . "perm/test/"))
You set keys with 'permset. At the time a key is written, a file with that key name is created in the directory, holding the data for that key. This code could be hidden more elegantly behind the standard form accessors, with ac.scm changes.

  arc> (permset foo 'baz (list 5 (obj x 1 y 4)))
  (5 #hash((y . 4) (x . 1)))
Here you see a table living deeply in a table value. Nonetheless, it will serialize properly, by design.

   arc> (quit)
...now we reenter arc...

  arc> (= foo (perm 'test))
  #hash((baz . (5 #hash((y . 4) (x . 1)))) (bar . 5) (%dir . "perm/test/"))
As you can see, when we create the table again, it's prepopulated with values.

  arc> foo!baz          
  (5 #hash((y . 4) (x . 1)))
The nested hash table serialized OK, too.

  arc> (permdel foo 'baz)
  nil
...this will delete the key, as well as the associated file from the directory.

That's all there is to this system. Here's the code:

  (def detable (obj)
    (case type.obj
      table (detable:cons '%table tablist.obj)
      cons (cons (detable car.obj) (detable cdr.obj))
      obj))

  (def retable (obj)
    (if acons.obj
        (if (is car.obj '%table)
            (listtab:retable:cdr obj)
            (cons (retable car.obj) (retable cdr.obj)))
        obj))

  (def perm (nam)
    (w/table tb
             (let ^ (string "perm/" nam "/")
                  ensure-dir.^   
                  (= (tb '%dir) ^)
                  (each key (map read dir.^)
                            (= (tb key) (retable:readfile1:string ^ key))))))

  (def permset (x key val)
    (writefile1 detable.val (string (x '%dir) key))
    (= (x key) val))

  (def permdel (x key)
    (rmfile:string x!%dir key)
    (wipe (x key)))


3 points by almkglor 5923 days ago | link

Existing frameworks for building this:

http://arclanguage.com/item?id=3762

http://arclanguage.com/item?id=3698

you can also always just overload sref:

  (redef sref (ob v . rest)
    (if (is-perm-table ob) ; need to implement this function
        (if v
            (permset ob (car rest) v)
            (permdel ob (car rest)))
        (apply old ob v rest)))
For example, you might want to use (annotate 'perm-table ...), or better yet just use the settable-fn framework which provides you with 'keys, 'sref, etc. "for free"

-----