136 lines · 4.9 KB · Text
RawDownload
= Dbm: Dbf, init: data base with hashed indexing     include "dbm.m";     dbm := load Dbm Dbm->PATH;    Datum, Dbf: import dbm;     Datum:  type array of byte;     Dbf: adt {        create: fn(file: string, perm: int): ref Dbf;        open:   fn(file: string, flags: int): ref Dbf;            fetch:  fn(db: self ref Dbf, key: Datum): Datum;        delete: fn(db: self ref Dbf, key: Datum): int;        store:  fn(db: self ref Dbf, key: Datum, data: Datum,                      replace: int): int;            firstkey: fn(db: self ref Dbf): Datum;        nextkey:  fn(db: self ref Dbf, key: Datum): Datum;            flush:    fn(db: self ref Dbf);        isrdonly: fn(db: self ref Dbf): int;    };        init:   fn(); Dbm  maintains  key/content  pairs in a data base.  The func‐tions will handle very large (a billion blocks) databases andwill access a keyed item in one or two filesystem accesses. Keys  and  contents  are  both represented by arrays of bytes(with the synonym Datum), allowing arbitrary binary values. The data base is stored in two files.  One file is  a  direc‐tory  containing a bit map and has as its suffix.  The secondfile contains all data and has as its suffix.  An applicationcan  access several databases at once, but must avoid concur‐rent operations on any one database (eg, by using  a  monitorprocess to control access). Init must be called before any other operation of the module. A  database  is  created  by Dbf.create, which accepts a filepermission parameter perm, as described for Sys->create  (seesys-open(2)); it creates the two files file.dir and file.pag.If successful, it returns  a  Dbf  reference  describing  thedatabase,  which  is  open for reading and writing.  (It willtruncate an existing database.)  It returns nil if it  cannotcreate  the  database  for  some  reason,  and sets the errorstring. Dbf.open accepts  a  mode  parameter  as  described  in  sys-open(2),  and  opens  the  existing  database in file.dir andfile.pag.  If successful, it returns a Dbf reference describ‐ing  the database, which is open either for reading and writ‐ing (ie, Sys->ORDWR), or only  for  reading  (Sys->OREAD)  asdetermined by mode.  It returns nil if the database cannot beopened successfully, and sets the error string. The remaining operations apply to an existing  Dbf  referencedb: db.fetch(key)       Return the data stored under a key; nil is returned if       the key is not in the database. db.store(key, data, replace)       Store data under the given key.  If  replace  is  non-       zero,  store will simply replace the existing value by       the new one if the key is already in the database;  if       replace  is  zero  store will return 0 if the new item       was inserted, but 1 if the key already appears in  the       database, and the new value will not be stored. db.delete(key)       Key and its associated value is removed from the data‐       base. db.firstkey()       Return the first key in the database;  return  nil  if       the database is empty. db.nextkey(key)       Return  the  key  following  the  given key, or nil if       there is none. db.flush()       Discard any data cached from the file.  The  cache  is       write-through,  so  it  is  not necessary to flush the       file before the application exits. db.isrdonly()       Return true if db was  opened  only  for  reading  and       writes are not allowed. == exampleA  linear pass through all keys in a database may be made, inan (apparently) random order,  by  use  of  Dbf.firstkey  andDbf.nextkey.  This code will traverse the data base:        for(key := db.firstkey(); key != nil; key = db.nextkey(key)){            d := db.fetch(key);       } The  order  of keys presented by Dbf.firstkey and Dbf.nextkeydepends on a hashing function, not on anything interesting. == source/appl/lib/dbm.b == diagnosticsAll functions that return an int indicate errors  with  nega‐tive values.  A zero return indicates success.  Routines thatreturn pointers, including values of Datum, return nil valueson  error.   Dbf.create and Dbf.open return nil on failure toaccess the database, setting  the  error  string  to  a  moredetailed diagnostic. == bugsOn  some systems (notably Plan 9 but also some Unix systems),the .pag file might contain holes where  no  data  block  hasever  been  written  so  that its apparent size is about fourtimes its actual content.  These files cannot  be  copied  bynormal means (cp, cat) without filling in the holes. Except  for  firstkey  and  nextkey, Datum values returned bythese functions point to storage that is  changed  by  subse‐quent calls. The  sum  of  the sizes of a key/content pair must not exceedthe internal block size (currently 512 bytes).  Moreover  allkey/content  pairs  that  hash  together must fit on a singleblock.  Dbf.store will return an error in the  event  that  ablock fills with inseparable data.