Saturday, December 30, 2006

Serialization To Disk

For fun, I wrote a TinyURL clone in Factor. You can try it out at I needed a way to save the data to a file, so I used libs/serialize to serialize the hashtable containing the links. There was yet another bug involving vector literals -- the serialization code would reuse a vector, so the first time you serialized the output is correct, but the next time it would produce garbage.
  scratchpad SYMBOL: aa H{ { 1 2 } } aa set
scratchpad aa get .
H{ { 1 2 } }
scratchpad aa get [ [ serialize ] with-serialized ] string-out .
scratchpad aa get [ [ serialize ] with-serialized ] string-out .
The fix was to change a V{ } to a V{ } clone.

Serialization to Disk Code

: save-fstore ( variable path -- )
[ [ get serialize ] with-serialized ] with-stream ;

: load-fstore ( variable path -- )
dup exists? [
[ [ deserialize ] with-serialized ] with-stream
] [
drop >r H{ } clone r>
] if set-global ;

: fstore-set ( variable fstore -- )
get >r [ get ] keep r> set-hash ;

: fstore-get ( default variable fstore -- )
get dupd hash* [ swap set-global drop ] [ drop set-global ] if ;

save-fstore and load-fstore save/load a hashtable to disk. The hashtable keys are variable names and the values are the variable values. fstore-set puts your variable in the hashtable, so you should call this directly before saving to disk. fstore-get loads the data from your store. If there is no fstore or if the key does not exist, it uses your default value.

The loading code is pretty simple:
: fstore-name "wee-url.fstore" ;
SYMBOL: wee-shortcuts
SYMBOL: wee-fstore
wee-fstore fstore-name load-fstore
H{ } clone wee-shortcuts wee-fstore fstore-get
The variable wee-shortcuts stores the encoded URLs, while wee-fstore is the hashtable that the above code reads/writes to disk.

Finally, to write the store:
: save-shortcuts ( -- )
wee-shortcuts wee-fstore fstore-set
wee-fstore fstore-name save-fstore ;

Notice that we add wee-shortcuts to the hashtable before saving to disk.

I'm going to rewrite the wee-url code to use Furnace instead of callback-responder. Once I get it looking nice, I'll show you how it works.