Patch title: Release 94 bulk changes
Abstract:
File: /pliant/storage/index/index.pli
Key:
    Removed line
    Added line
   
module "/pliant/language/unsafe.pli"
module "/pliant/language/stream.pli"
module "/pliant/util/pml/io.pli"

constant in_memory true


type StorageIndex
  if in_memory
    field (Index Str Str) index
  else
    field (Index Str Intn) chunk
    field (Index Str Str) inserted
    field (Dictionary Str Void) deleted
    field Stream stream
    field Str current
  field Str basename
  field Sem sem
  field Stream log


method si bind basename -> status
  arg_rw StorageIndex si ; arg Str basename ; arg ExtendedStatus status
  si basename := basename
  if in_memory
    (var Stream s) open basename+".sie" in+safe
    while not s:atend
      if (s iraw (var Str key) (var Str value))
        var Pointer:Str p :> si:index first key
        if exists:p
          p := value
        else
          si:index insert key value
      eif (s iraw (var Str key) (var Void drop))
        var Pointer:Str p :> si:index first key
        if exists:p
          si:index remove p
      else
        return (failure "Storage extra keys file is corrupted at offset "+(s safe_query "seek"))
    s close
  else
    (var Stream s) open basename+".sic" in+safe # chunks
    while not s:atend
      if (s iraw (var Str key) (var Intn offset))
        si:chunk insert key offset
      else
        return (failure "Storage chunks list file is corrupted at offset "+(s safe_query "seek"))
    (var Stream s) open basename+".sie" in+safe # extra
    while not s:atend
      if (s iraw (var Str key) (var Str value))
        si:inserted insert key value
      eif (s iraw (var Str key) (var Void drop))
        si:deleted insert key void
      else
        return (failure "Storage extra keys file is corrupted at offset "+(s safe_query "seek"))
    s close
    si:stream open basename+".sis" in+safe # sorted


method si first -> key
  arg_rw StorageIndex si ; arg Str key
  if in_memory
    si:sem rd_request
    var Pointer:Str p :> si:index first
    if exists:p
      key := si:index key p
    else
      key := ""
    si:sem rd_release
  else
    void
 
method si next key1 -> key2
  arg_rw StorageIndex si ; arg Str key1 key2
  if in_memory
    si:sem rd_request
    var Pointer:Str p :> si:index first key1
    if exists:p
      p :> si:index next p
      if exists:p
        key2 := si:index key p
      else
        key2 := ""
    else
      key2 := ""
    si:sem rd_release
  else
    void


method si insert key value
  arg_rw StorageIndex si ; arg Str key value
  if in_memory
    si:sem request
    if not si:log:is_open
      si:log open si:basename+".sie" append+safe
    si:log oraw key value
    si:log flush anytime
    var Pointer:Str p :> si:index first key
    if exists:p
      p := value
    else
      si:index insert key value
    si:sem release
  else
    si:sem request
    if not si:log:is_open
      si:log open si:basename+".sie" append+safe
    si:log oraw key value
    si:log flush anytime
    if exists:(si:deleted first key)
      si:deleted remove (si:deleted first key)
    si:inserted insert key value
    si:sem release
  
  
method si remove key
  arg_rw StorageIndex si ; arg Str key
  if in_memory
    si:sem request
    if not si:log:is_open
      si:log open si:basename+".sie" append+safe
    si:log oraw key void
    si:log flush anytime
    var Pointer:Str p :> si:index first key
    if exists:p
      si:index remove p
    si:sem release
  else
    si:sem request
    if not si:log:is_open
      si:log open si:basename+".sie" append+safe
    si:log oraw key void
    si:log flush anytime
    if exists:(si:inserted first key)
      si:inserted remove (si:inserted first key)
    si:deleted insert key void
    si:sem release


method si search key -> value
  arg_rw StorageIndex si ; arg Str key value
  if in_memory
    si:sem rd_request
    var Pointer:Str p :> si:index first key
    if exists:p
      value := p
    else
      value := ""
    si:sem rd_release
  else
    si:sem request
    if exists:(si:deleted first key)
      value := ""
    eif exists:(si:inserted first key)
      value := si:inserted first key
    else
      var Pointer:Intn offset :> si:chunk from key
      if exists:offset and (si:key offset)>key
        offset :> si:chunk previous offset
      var Pointer:Intn offset2 :> si:chunk next offset
    si:sem release


export StorageIndex '. bind'
export '. insert' '. remove' '. search' '. first' '. next'


if false

  function test
    var Link:StorageIndex idx :> new StorageIndex
    idx bind "file:/tmp/test"
    if true
      for (var Int i) 1 10
        idx insert "k"+string:i "/foo/"+string:i
      idx remove "k3"
    if true
      var Str k := idx first
      while k<>""
        console k " -> " (idx search k) eol
        k := idx next k

  test