diff options
| -rw-r--r-- | appl/cmd/ndb/registry.b | 97 | ||||
| -rw-r--r-- | dis/ndb/registry.dis | bin | 8483 -> 9244 bytes | |||
| -rw-r--r-- | man/4/registry | 9 |
3 files changed, 95 insertions, 11 deletions
diff --git a/appl/cmd/ndb/registry.b b/appl/cmd/ndb/registry.b index f720781f..7c6b8a88 100644 --- a/appl/cmd/ndb/registry.b +++ b/appl/cmd/ndb/registry.b @@ -82,8 +82,20 @@ Filter: adt { remove: fn(f: self ref Filter); }; -filters: list of ref Filter; +Event: adt { + id: int; # fid reading from Qevents + vers: int; # last change seen + m: ref Tmsg.Read; # outstanding read request + + new: fn(id: int): ref Event; + find: fn(id: int): ref Event; + remove: fn(e: self ref Event); + queue: fn(e: self ref Event, m: ref Tmsg.Read): string; + post: fn(vers: int); +}; +filters: list of ref Filter; +events: list of ref Event; services := array[9] of ref Service; nservices := 0; @@ -105,11 +117,11 @@ init(nil: ref Draw->Context, args: list of string) if(daytime == nil) loaderr(Daytime->PATH); styx = load Styx Styx->PATH; - if (styx == nil) + if(styx == nil) loaderr(Styx->PATH); styx->init(); styxservers = load Styxservers Styxservers->PATH; - if (styxservers == nil) + if(styxservers == nil) loaderr(Styxservers->PATH); styxservers->init(styx); @@ -170,7 +182,7 @@ Serve: error(sys->sprint("fatal read error: %s\n", m.error)); break Serve; Open => - (fid, mode, d, e) := srv.canopen(m); + (fid, nil, nil, e) := srv.canopen(m); if((err = e) != nil) break; if(fid.qtype & Sys->QTDIR) @@ -219,6 +231,9 @@ open(m: ref Tmsg.Open, fid: ref Fid) svc := Service.new(fid.uname); svc.fid = fid.fid; fid.open(m.mode, (big ((svc.id << Shift)|Qsvc), 0, Sys->QTFILE)); + Qevent => + Event.new(fid.fid); + fid.open(m.mode, (fid.path, 0, Sys->QTFILE)); * => fid.open(m.mode, (fid.path, 0, fid.qtype)); } @@ -246,7 +261,16 @@ read(m: ref Tmsg.Read, fid: ref Fid): string } srv.reply(styxservers->readbytes(m, fid.data)); Qevent => - return "not implemented yet"; + e := Event.find(fid.fid); + if(e.vers == rootvers) + return e.queue(m); + else{ + s := sys->sprint("%8.8d\n", rootvers); + e.vers = rootvers; + m.offset = big 0; + srv.reply(styxservers->readstr(m, s)); + return nil; + } * => return Egreg; } @@ -267,7 +291,7 @@ write(m: ref Tmsg.Write, fid: ref Fid): string return "bad syntax"; # first write names the service (possibly with attributes) if(svc.name == nil){ - if((e := svcnameok(hd toks)) != nil) + if(svcnameok(hd toks) != nil) return "bad service name"; svc.name = hd toks; toks = tl toks; @@ -278,6 +302,7 @@ write(m: ref Tmsg.Write, fid: ref Fid): string svc.vers++; for(; toks != nil; toks = tl tl toks) svc.set(hd toks, hd tl toks); + Event.post(++rootvers); Qfind => s := string m.data; toks := str->unquoted(s); @@ -310,10 +335,13 @@ clunk(fid: ref Fid) case path & Mask { Qsvc => svc := Service.find(path >> Shift); - if(svc != nil && svc.fid == fid.fid && int svc.get("persist") == 0) + if(svc != nil && svc.fid == fid.fid && int svc.get("persist") == 0){ svc.remove(); + Event.post(rootvers); + } Qevent => - ; # remove queued events? + if((e := Event.find(fid.fid)) != nil) + e.remove(); Qfind => if((f := Filter.find(fid.fid)) != nil) f.remove(); @@ -327,6 +355,7 @@ remove(fid: ref Fid): string svc := Service.find(path >> Shift); if(fid.uname == svc.owner){ svc.remove(); + Event.post(rootvers); return nil; } } @@ -425,12 +454,12 @@ navigator(navops: chan of ref Navop) d: array of int; case path & Mask { Qroot => - Nstatic: con 3; + Nstatic: con 4; d = array[Nstatic + nservices] of int; d[0] = Qnew; d[1] = Qindex; d[2] = Qfind; -# d[3] = Qevent; + d[3] = Qevent; for(i := 0; i < nservices; i++) if(services[i].name != nil) d[i + Nstatic] = (services[i].id<<Shift) | Qsvc; @@ -439,7 +468,7 @@ navigator(navops: chan of ref Navop) n.reply <-= (nil, Enotdir); break; } - for (i := n.offset; i < len d; i++) + for(i := n.offset; i < len d; i++) n.reply <-= dirgen(d[i]); n.reply <-= (nil, nil); } @@ -621,6 +650,52 @@ Filter.match(f: self ref Filter, attrs: list of (string, string)): int return i == len f.attrs; } +Event.new(id: int): ref Event +{ + e := ref Event(id, rootvers, nil); + events = e::events; + return e; +} + +Event.find(id: int): ref Event +{ + for(l := events; l != nil; l = tl l) + if((hd l).id == id) + return hd l; + return nil; +} + +Event.remove(e: self ref Event) +{ + rl: list of ref Event; + for(l := events; l != nil; l = tl l) + if((hd l).id != e.id) + rl = hd l :: rl; + events = rl; +} + +Event.queue(e: self ref Event, m: ref Tmsg.Read): string +{ + if(e.m != nil) + return "concurrent read for event fid"; + m.offset = big 0; + e.m = m; + return nil; +} + +Event.post(vers: int) +{ + s := sys->sprint("%8.8d\n", vers); + for(l := events; l != nil; l = tl l){ + e := hd l; + if(e.vers < vers && e.m != nil){ + srv.reply(styxservers->readstr(e.m, s)); + e.vers = vers; + e.m = nil; + } + } +} + dbload(db: ref Db) { ptr: ref Attrdb->Dbptr; diff --git a/dis/ndb/registry.dis b/dis/ndb/registry.dis Binary files differindex f96234aa..dcf0fafa 100644 --- a/dis/ndb/registry.dis +++ b/dis/ndb/registry.dis diff --git a/man/4/registry b/man/4/registry index c952d3d6..a8b852d9 100644 --- a/man/4/registry +++ b/man/4/registry @@ -116,6 +116,15 @@ so that several processes can set different filters simultaneously. (Note that after the write, the file offset must be set to zero using .IR sys-seek (2) before reading.) +.TP +.B event +A read-only text file that can be used to detect when changes are made to the registry. +Reading from it blocks until a change is made. At that point, the read completes and returns a +string with a newline terminated decimal version number representing +the number of changes made to the registry, which matches +.B Qid.vers +for the registry directory. +Multiple changes are coalesced into one report. .PP A service file created by .B new |
