%%% Version = 1.1 %% %% OzStore: A Persistent dictionary %% %% Author: Kevin Glynn (glynn@info.ucl.ac.be) %% functor import Application Util at 'x-ozlib://keving/lib/Util.ozf' Gdbm at 'x-oz://contrib/gdbm' Pickle Connection System Property OS DPInit define {Property.put 'print.width' 1000} {Property.put 'print.depth' 1000} {Property.put 'dp.tcpHardLimit' 2000} {Property.put 'dp.tcpWeakLimit' 1800} %% OzStoreTicket = 'http://www.info.ucl.ac.be/~glynn/OzStoreTicket' DefaultOzStoreTicket = {OS.getEnv 'HOME'}#'/public_html/OzStoreTicket' OzStoreHeader = 'OzStore Request Ticket' DefaultDBName = {OS.getEnv 'HOME'}#'/.ozstore.db' Verbosity = {NewCell 0} %% To set verbosity on the fly. Trace = {Util.mkTrace cell(Verbosity) nothing} TraceInfo = {Util.mkTraceInfo cell(Verbosity) nothing} Args = try {Application.getArgs record(verbose(single char:&v type:int default:0) % verbosity init(single char:[&i] default:false) ozstoreticket(single char:[&t] type:atom default:DefaultOzStoreTicket) dbname(single char:[&n] type:atom default:DefaultDBName) ipaddr(single char:[&a] type:atom default:unit) port(single char:[&p] type:int default: ~1) help(single char:[&? &h] default:false) ) } catch _ then {System.showInfo 'Unrecognised arguments'} optRec(help:true) end if Args.help then {System.showInfo "Usage: "#{Property.get 'application.url'}#" [option]"} {System.showInfo "Options:"} {System.showInfo "\t"#"-v , --verbose "#"\t\t"#"Verbosity level"} {System.showInfo "\t"#"-i, --init"#"\t\t\t\t"#"Create Empty Database"} {System.showInfo "\t"#"-t , --ticket "#"\t"#"Ticket File (default: "#DefaultOzStoreTicket#')'} {System.showInfo "\t"#"-n , --dbname "#"\t\t"#"Database Name (default: "#DefaultDBName#')'} {System.showInfo "\t"#"-a , --ipaddr "#"\t"#"Force this address in tickets (default: ask system)"} {System.showInfo "\t"#"-p , --port "#"\t\t"#"Force listen on this port (default: system picks)"} {System.showInfo "\t"#"-h, --help"#"\t\t\t\t"#"This help"} {Application.exit 0} end %% Must set before first call to Trace ..... Verbosity := Args.verbose if Args.ipaddr \= unit orelse Args.port > 0 then InitP = if Args.port > 0 then init(port:Args.port) else init end InitAP = if Args.ipaddr \= unit then {AdjoinAt InitP ip {Atom.toString Args.ipaddr}} else InitP end in if {Not {DPInit.init InitAP}} then if Args.ipaddr \= unit then {System.showInfo 'Could not set my IP Address to '#Args.ipaddr} end if Args.port > 0 then {System.showInfo 'Could not set my Port to '#Args.port} end {Application.exit 1} end end %% First, try to shutdown any running ozstore try {Send {Connection.take {Pickle.load Args.ozstoreticket}} shutdown} catch E then {Trace 5 'Attempt to shut down previous incarnation failed'#E} %% Well, we tried! skip end DictS DictP = {NewPort DictS} RequestTicket = {Connection.offerUnlimited DictP} {Pickle.saveWithHeader RequestTicket Args.ozstoreticket OzStoreHeader 0} {TraceInfo 3 'Ticket is '#RequestTicket} DB = {Gdbm.new if Args.init then new(Args.dbname mode:[owner]) else create(Args.dbname mode:[owner]) end} %%PersistentDictionary = {NewDictionary} UniqueMarker = {NewName} {TraceInfo 3 'OzStore starting ....'} for R in DictS do {Trace 3 'Processing'#R} thread case R of shutdown then {TraceInfo 3 'Shutting down upon request'} {Gdbm.close DB} {Application.exit 0} [] put(Key Val) then {Gdbm.put DB Key Val} [] get(Key Val) then Entry = {Gdbm.condGet DB Key UniqueMarker} in %% If client is in tempFail then the bind will block %% don't need thread here because each request is processed in a thread! %%thread try Val = if Entry \= UniqueMarker then success(Entry) else error('keyNotInDictionary'(Key)) end catch _ then %% Don't care if the client has failed (permFail) skip end %%end [] remove(Key) then {Gdbm.remove DB Key} [] verbose(NewVerbose) then if {IsInt NewVerbose} then {TraceInfo 3 'NewVerbose Level :'#NewVerbose} Verbosity := NewVerbose else {Trace 3 'Invalid NewVerbose Level :'#NewVerbose} end end end end end