WvStreams
unimountgen.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * Defines a UniConfGen that manages a tree of UniConfGen instances.
6  */
7 #include "unimountgen.h"
8 #include "wvmoniker.h"
9 #include "wvhash.h"
10 #include "wvstrutils.h"
11 #include "unilistiter.h"
12 #include "wvstringtable.h"
13 #include <assert.h>
14 
15 /***** UniMountGen *****/
16 
18 {
19  // nothing special
20 }
21 
22 
24 {
25  zap();
26 }
27 
28 
30 {
31  UniGenMount *found = findmount(key);
32  if (!found)
33  {
34  // if there are keys that _do_ have a mount under this one,
35  // then we consider it to exist (as a key with a blank value)
36  if (has_subkey(key, NULL))
37  return "";
38 
39  return WvString::null;
40  }
41 
42  return found->gen->get(trimkey(found->key, key));
43 }
44 
45 
46 void UniMountGen::set(const UniConfKey &key, WvStringParm value)
47 {
48  UniGenMount *found = findmount(key);
49  if (!found)
50  return;
51  found->gen->set(trimkey(found->key, key), value);
52 }
53 
54 
56 {
57  UniGenMount *mount;
58  WvString key;
59  UniConfPairList pairs;
60 
62  : mount(_mount)
63  {
64  if (mount)
65  key = mount->key;
66  }
67 };
68 
69 
70 void UniMountGen::setv(const UniConfPairList &pairs)
71 {
72  UniGenMountPairsDict mountpairs(mounts.count());
73 
74  {
75  MountList::Iter m(mounts);
76  for (m.rewind(); m.next(); )
77  mountpairs.add(new UniGenMountPairs(m.ptr()), true);
78  }
79 
80  {
81  UniConfPairList::Iter pair(pairs);
82  for (pair.rewind(); pair.next(); )
83  {
84  UniGenMount *found = findmount(pair->key());
85  if (!found)
86  continue;
87  UniConfPair *trimmed = new UniConfPair(trimkey(found->key,
88  pair->key()),
89  pair->value());
90  mountpairs[found->key]->pairs.add(trimmed, true);
91  }
92  }
93 
94  UniGenMountPairsDict::Iter i(mountpairs);
95  for (i.rewind(); i.next(); )
96  i->mount->gen->setv(i->pairs);
97 }
98 
99 
101 {
102  UniGenMount *found = findmount(key);
103  //fprintf(stdout, "unimountgen:exists:found %p\n", found);
104  if (found && found->gen->exists(trimkey(found->key, key)))
105  return true;
106  else
107  //if there's something mounted and set on a subkey, this key must
108  //*exist* along the way
109  return has_subkey(key, found);
110 }
111 
112 
114 {
115  UniGenMount *found = findmount(key);
116 // fprintf(stdout, "haschildren:found %p\n", found);
117  if (found && found->gen->haschildren(trimkey(found->key, key)))
118  return true;
119 
120  // if we get here, the generator we used didn't have a subkey. We want
121  // to see if there's anyone mounted at a subkey of the requested key; if
122  // so, then we definitely have a subkey.
123  return has_subkey(key, found);
124 }
125 
126 
127 bool UniMountGen::has_subkey(const UniConfKey &key, UniGenMount *found)
128 {
129  MountList::Iter i(mounts);
130  for (i.rewind(); i.next(); )
131  {
132  if (key.suborsame(i->key) && key < i->key)
133  {
134  //fprintf(stdout, "%s has_subkey %s : true\n", key.printable().cstr(),
135  // i->key.printable().cstr());
136  return true;
137  }
138 
139  // the list is sorted innermost-first. So if we find the key
140  // we started with, we've finished searching all children of it.
141  if (found && (i->gen == found->gen))
142  break;
143  }
144 
145  //fprintf(stdout, "%s has_subkey false \n", key.printable().cstr());
146  return false;
147 }
148 
150 {
151  hold_delta();
152 
153  bool result = true;
154 
155  MountList::Iter i(mounts);
156  for (i.rewind(); i.next(); )
157  result = result && i->gen->refresh();
158 
159  unhold_delta();
160  return result;
161 }
162 
163 
165 {
166  hold_delta();
167 
168  MountList::Iter i(mounts);
169  for (i.rewind(); i.next();)
170  i->gen->commit();
171 
172  unhold_delta();
173 }
174 
175 
177  WvStringParm moniker, bool refresh)
178 {
179  IUniConfGen *gen = wvcreate<IUniConfGen>(moniker);
180  if (gen)
181  mountgen(key, gen, refresh); // assume always succeeds for now
182 #if DEBUG
183  assert(gen && "Moniker doesn't get us a generator!");
184 #endif
185  if (gen && !gen->exists("/"))
186  gen->set("/", "");
187  return gen;
188 }
189 
190 
192  IUniConfGen *gen, bool refresh)
193 {
194  if (!gen)
195  return NULL;
196 
197  UniGenMount *newgen = new UniGenMount(gen, key);
198  gen->add_callback(this, wv::bind(&UniMountGen::gencallback, this,
199  newgen->key, _1, _2));
200 
201  hold_delta();
202  delta(key, WvString());
203 
204  makemount(key);
205 
206  if (gen && refresh)
207  gen->refresh();
208 
209  mounts.prepend(newgen, true);
210 
211  delta(key, get(key));
212  unhold_delta();
213  if (!gen->exists("/"))
214  gen->set("/", "");
215  return gen;
216 }
217 
218 
219 void UniMountGen::unmount(IUniConfGen *gen, bool commit)
220 {
221  if (!gen)
222  return;
223 
224  MountList::Iter i(mounts);
225 
226  for (i.rewind(); i.next() && i->gen != gen; )
227  ;
228 
229  if (i->gen != gen)
230  return;
231 
232  hold_delta();
233 
234  if (commit)
235  gen->commit();
236  gen->del_callback(this);
237 
238  UniConfKey key(i->key);
239  IUniConfGen *next = NULL;
240 
241  delta(key, WvString());
242 
243  // Find the first generator mounted past the one we're removing (if
244  // any). This way we can make sure that each generator still has keys
245  // leading up to it (in case they lost their mountpoint due to the
246  // unmounted generator)
247  i.xunlink();
248  if (i.next())
249  next = i->gen;
250 
251  for (i.rewind(); i.next() && i->gen != next; )
252  {
253  if (key.suborsame(i->key) && key != i->key)
254  {
255  makemount(i->key);
256  delta(i->key, get(i->key));
257  }
258  }
259 
260  unhold_delta();
261 }
262 
263 
264 void UniMountGen::zap()
265 {
266  while (!mounts.isempty())
267  unmount(mounts.first()->gen, false);
268 }
269 
270 
272  UniConfKey *mountpoint)
273 {
274  MountList::Iter i(mounts);
275 
276  for (i.rewind(); i.next(); )
277  {
278  if (i->key.suborsame(key))
279  {
280  if (mountpoint)
281  *mountpoint = i->key;
282  return i->gen;
283  }
284  }
285 
286  return NULL;
287 }
288 
289 
291 {
292  MountList::Iter i(mounts);
293 
294  for (i.rewind(); i.next(); )
295  {
296  if (i->key == key)
297  return true;
298  }
299 
300  return false;
301 }
302 
303 static int wvstrcmp(const WvString *l, const WvString *r)
304 {
305  return strcmp(*l, *r);
306 }
307 
309 {
310  UniGenMount *found = findmount(key);
311  if (found)
312  return found->gen->iterator(trimkey(found->key, key));
313  else
314  {
315  // deal with elements mounted on nothingness.
316  // FIXME: this is really a hack, and should (somehow) be dealt with
317  // in a more general way.
318  ListIter *it = new ListIter(this);
319 
320  MountList::Iter i(mounts);
321  WvStringTable t(10);
322  for (i.rewind(); i.next(); )
323  {
324  if (key.numsegments() < i->key.numsegments()
325  && key.suborsame(i->key))
326  {
327  // trim off any stray segments coming between the virtual
328  // "key" we're iterating over and the mount
329  UniConfKey k1 = i->key.first(key.numsegments() + 1);
330  UniConfKey k2 = k1.last(); // final "key" should be size 1
331 
332  if (!t[k2])
333  t.add(new WvString(k2), true);
334  }
335  }
336  WvStringTable::Sorter s(t, &::wvstrcmp);
337  for (s.rewind(); s.next();)
338  it->add(*s);
339 
340  return it;
341  }
342 }
343 
344 
345 // FIXME: this function will be rather slow if you try to iterate over multiple
346 // generators and the latency level is high (as is the case with e.g.: the tcp generator).
347 // the fast path will only kick in if you iterate over a single generator.
349 {
350  UniGenMount *found = findmountunder(key);
351  if (found)
352  return found->gen->recursiveiterator(trimkey(found->key, key));
353  else
354  return UniConfGen::recursiveiterator(key);
355 }
356 
357 
358 UniMountGen::UniGenMount *UniMountGen::findmount(const UniConfKey &key)
359 {
360  // Find the needed generator and keep it as a lastfound
361  MountList::Iter i(mounts);
362  for (i.rewind(); i.next(); )
363  {
364  if (i->key.suborsame(key))
365  return i.ptr();
366  }
367 
368  return NULL;
369 }
370 
371 
372 UniMountGen::UniGenMount *UniMountGen::findmountunder(const UniConfKey &key)
373 {
374  UniMountGen::UniGenMount * foundmount = NULL;
375  int num_found_mounts = 0;
376 
377  // Find the needed generator and keep it as a lastfound
378  MountList::Iter i(mounts);
379  for (i.rewind(); i.next(); )
380  {
381  // key lies beneath mount (only care about the first)
382  if (i->key.suborsame(key) && !foundmount)
383  {
384  foundmount = i.ptr();
385  num_found_mounts++;
386  }
387  // mount lies beneath key
388  else if (key.suborsame(i->key))
389  {
390  num_found_mounts++;
391  }
392  }
393 
394  if (num_found_mounts == 1 && foundmount)
395  return foundmount;
396 
397  return NULL;
398 }
399 
400 
401 void UniMountGen::gencallback(const UniConfKey &base, const UniConfKey &key,
402  WvStringParm value)
403 {
404  delta(UniConfKey(base, key), value);
405 }
406 
407 
408 void UniMountGen::makemount(const UniConfKey &key)
409 {
410  // Create any keys needed leading up to the mount generator so that the
411  // mountpoint exists
412  UniConfKey::Iter i(key);
413  UniConfKey points;
414 
415  for (i.rewind(); i.next(); )
416  {
417  points.append(*i);
418  if (get(points).isnull())
419  set(points, "");
420  }
421 
422  // Set the mountpoint in the sub generator instead of on the generator
423  // itself (since set will set it on the generator, instead of making the
424  // mountpoint)
425  UniGenMount *found = findmount(points.removelast());
426  if (!found)
427  return;
428 
429  if (found->gen->get(trimkey(found->key, key)).isnull())
430  found->gen->set(trimkey(found->key, key), "");
431 }
UniMountGen::~UniMountGen
virtual ~UniMountGen()
Destroys the UniConf tree along with all uncommitted data.
Definition: unimountgen.cc:23
UniMountGen::ismountpoint
virtual bool ismountpoint(const UniConfKey &key)
Determines if a key is a mountpoint.
Definition: unimountgen.cc:290
IUniConfGen::set
virtual void set(const UniConfKey &key, WvStringParm value)=0
Stores a string value for a key into the registry.
IUniConfGen::exists
virtual bool exists(const UniConfKey &key)=0
Without fetching its value, returns true if a key exists.
UniMountGen::mount
virtual IUniConfGen * mount(const UniConfKey &key, WvStringParm moniker, bool refresh)
Mounts a generator at a key using a moniker.
Definition: unimountgen.cc:176
UniMountGen::get
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
Definition: unimountgen.cc:29
UniMountGen::refresh
virtual bool refresh()
Refreshes information about a key recursively.
Definition: unimountgen.cc:149
UniConfKey::removelast
UniConfKey removelast(int n=1) const
Returns the path formed by removing the last n segments of this path.
Definition: uniconfkey.h:346
UniMountGen::UniMountGen
UniMountGen()
Creates an empty UniConf tree with no mounted stores.
Definition: unimountgen.cc:17
UniListIter
An iterator that iterates through a constant list of keys.
Definition: unilistiter.h:27
UniListIter::add
void add(const UniConfKey &k, WvStringParm v=WvString::null)
Add a key/value pair to the list that gets returned by this iterator.
Definition: unilistiter.cc:16
UniConfGen::recursiveiterator
virtual Iter * recursiveiterator(const UniConfKey &key)
Like iterator(), but the returned iterator is recursive, that is, it will return children of the imme...
Definition: uniconfgen.cc:260
IUniConfGen::ListIter
::UniListIter ListIter
An iterator over a constant list of keys (see below)
Definition: uniconfgen.h:160
UniMountGen::setv
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
Definition: unimountgen.cc:70
UniMountGen::whichmount
virtual IUniConfGen * whichmount(const UniConfKey &key, UniConfKey *mountpoint)
Finds the generator that owns a key.
Definition: unimountgen.cc:271
UniMountGen::haschildren
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
Definition: unimountgen.cc:113
UniConfGen::unhold_delta
void unhold_delta()
Resumes notifications when each hold_delta() has been matched.
Definition: uniconfgen.cc:38
WvStringTable
Definition: wvstringtable.h:17
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
IUniConfGen
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:39
UniConfKey::Iter
An iterator over the segments of a key.
Definition: uniconfkey.h:463
wvstrutils.h
UniConfKey
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
UniMountGen::UniGenMount
Definition: unimountgen.h:22
UniMountGen::commit
virtual void commit()
Commits any changes.
Definition: unimountgen.cc:164
UniConfKey::suborsame
bool suborsame(const UniConfKey &key) const
Returns true if 'key' is a the same, or a subkey, of this UniConfKey.
Definition: uniconfkey.cc:294
UniMountGen::unmount
virtual void unmount(IUniConfGen *gen, bool commit)
Unmounts the generator at a key and releases it.
Definition: unimountgen.cc:219
UniConfGen::delta
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
UniMountGen::mountgen
virtual IUniConfGen * mountgen(const UniConfKey &key, IUniConfGen *gen, bool refresh)
Mounts a generator at a key.
Definition: unimountgen.cc:191
IUniConfGen::commit
virtual void commit()=0
Commits any changes.
UniConfKey::first
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition: uniconfkey.h:314
UniMountGen::recursiveiterator
virtual Iter * recursiveiterator(const UniConfKey &key)
Like iterator(), but the returned iterator is recursive, that is, it will return children of the imme...
Definition: unimountgen.cc:348
UniMountGen::set
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
Definition: unimountgen.cc:46
UniMountGen::exists
virtual bool exists(const UniConfKey &key)
Without fetching its value, returns true if a key exists.
Definition: unimountgen.cc:100
IUniConfGen::del_callback
virtual void del_callback(void *cookie)=0
Removes a callback for change notification.
IUniConfGen::refresh
virtual bool refresh()=0
Refreshes information about a key recursively.
UniMountGen::UniGenMountPairs
Definition: unimountgen.cc:55
IUniConfGen::add_callback
virtual void add_callback(void *cookie, const UniConfGenCallback &callback)=0
Adds a callback for change notification.
UniMountGen::iterator
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
Definition: unimountgen.cc:308
UniConfKey::last
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
UniConfKey::numsegments
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
UniConfPair
Represents a simple key-value pair.
Definition: uniconfpair.h:16
UniConfGen::hold_delta
void hold_delta()
Pauses notifications until matched with a call to unhold_delta().
Definition: uniconfgen.cc:32
UniConfKey::append
void append(const UniConfKey &other)
Appends a path to this path.
Definition: uniconfkey.cc:130
UniConfGen::Iter
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:323