Hi,

the path-cache of sim/flight-gear is not designed for removing nodes. If you remove a node and query it by it's name you probably get this removed node, independent if another node with the same name has been created meanwhile. This due to the path-cache of each node, which stores links to nodes by it's name to speed up the access. But if a node is removed, it is only removed in the path cache of the parent (and in this step the index is ignored, too).

The enclosed propbug.nas shows this bug. Just copy it to your data/Nasal folder and start flightgear. It should display

   --------------- propbug.nas ----------------

   set /foo/bar/a/b to 1

   dump getNode("foo").getNode("bar/a/b")
   b {DOUBLE} = 1

   remove child b from foo/bar/a

   dump getNode("foo/bar/a")
   a {NONE} = nil

   set /foo/bar/a/b to 2

   dump getNode("foo/bar/a")
   a {NONE} = nil
   a/b {DOUBLE} = 2

   dump getNode("foo").getNode("bar/a/b")
   b {DOUBLE} = 2

   --------------- propbug.nas ----------------

on the console, but it displays:

   --------------- propbug.nas ----------------

   set /foo/bar/a/b to 1

   dump getNode("foo").getNode("bar/a/b")
   b {DOUBLE} = 1

   remove child b from foo/bar/a


   dump getNode("foo/bar/a")
   a {NONE} = nil

   set /foo/bar/a/b to 2

   dump getNode("foo/bar/a")
   a {NONE} = nil
   a/b {DOUBLE} = 2

   dump getNode("foo").getNode("bar/a/b")
   b {NONE} = nil

   --------------- propbug.nas ----------------

The last line is different. The Node /foo/bar/a/b is set to 2, but is displayed to be nil.

The enclosed patch corrects this. It's the same patch I posted earlier, but reviewed/overhauled by Melchior (Thanks!).

What it does:
- make every node maintain list of properties that link to it
- add functions to erase node by address from hash bucket/entry in their path caches, so that all references can be removed - if a node is removed, it (and all children, grandchildren, ...) calls all linked properties to remove them from their path-cache


This fixes problems with the aerotow over multiplayer and maybe some other problems, where nodes are queried by name.

Please commit.

Maik



Index: props.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/props/props.cxx,v
retrieving revision 1.26
diff -u -p -r1.26 props.cxx
--- props.cxx   22 Oct 2006 13:08:09 -0000      1.26
+++ props.cxx   8 Feb 2007 21:23:29 -0000
@@ -911,6 +911,21 @@ SGPropertyNode::getChildren (const char 
 
 
 /**
+ * Remove this node from all nodes that link to it in their path cache.
+ */
+void
+SGPropertyNode::remove_from_path_caches ()
+{
+  for (unsigned int i = 0; i < _linkedNodes.size(); i++)
+    _linkedNodes[i]->erase(this);
+
+  _linkedNodes.clear();
+  for (unsigned int i = 0; i < _children.size(); ++i)
+    _children[i]->remove_from_path_caches();
+}
+
+
+/**
  * Remove child by position.
  */
 SGPropertyNode_ptr
@@ -927,8 +942,8 @@ SGPropertyNode::removeChild (int pos, bo
   if (keep) {
     _removedChildren.push_back(node);
   }
-  if (_path_cache)
-     _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into 
account!
+
+  node->remove_from_path_caches();
   node->setAttribute(REMOVED, true);
   node->clearValue();
   fireChildRemoved(node);
@@ -967,6 +982,24 @@ SGPropertyNode::removeChildren (const ch
 }
 
 
+/**
+  * Remove a linked node.
+  */
+bool
+SGPropertyNode::remove_linked_node (hash_table * node)
+{
+  for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
+    if (_linkedNodes[i] == node) {
+      vector<hash_table *>::iterator it = _linkedNodes.begin();
+      it += i;
+      _linkedNodes.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
+
 const char *
 SGPropertyNode::getDisplayName (bool simplify) const
 {
@@ -2210,6 +2243,20 @@ SGPropertyNode::hash_table::bucket::eras
   }
 }
 
+bool
+SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
+{
+  for (int i = 0; i < _length; i++) {
+    if (_entries[i]->get_value() == node) {
+      for (++i; i < _length; i++) {
+        _entries[i-1] = _entries[i];
+      }
+      _length--;
+      return true;
+    }
+  }
+  return false;
+}
 
 SGPropertyNode::hash_table::hash_table ()
   : _data_length(0),
@@ -2254,6 +2301,7 @@ SGPropertyNode::hash_table::put (const c
   }
   entry * e = _data[index]->get_entry(key, true);
   e->set_value(value);
+  value->add_linked_node(this);
 }
 
 void
@@ -2264,7 +2312,19 @@ SGPropertyNode::hash_table::erase (const
   unsigned int index = hashcode(key) % _data_length;
   if (_data[index] == 0)
     return;
+  _data[index]->get_entry(key, true)->get_value()->remove_linked_node(this);
   _data[index]->erase(key);
+  _data[index] = 0;
+}
+
+bool
+SGPropertyNode::hash_table::erase (SGPropertyNode * node)
+{
+  for (unsigned int d = 0; d < _data_length; d++)
+    if (_data[d] && _data[d]->erase(node))
+      return true;
+
+  return false;
 }
 
 unsigned int
Index: props.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/SimGear/simgear/props/props.hxx,v
retrieving revision 1.18
diff -u -p -r1.18 props.hxx
--- props.hxx   14 Mar 2006 15:55:24 -0000      1.18
+++ props.hxx   8 Feb 2007 21:23:29 -0000
@@ -1183,6 +1183,12 @@ private:
   void trace_write () const;
 
 
+  /**
+   * Remove this node from all nodes that link to it in their path cache.
+   */
+  void remove_from_path_caches();
+
+
   class hash_table;
 
   int _index;
@@ -1193,6 +1199,7 @@ private:
   SGPropertyNode * _parent;
   vector<SGPropertyNode_ptr> _children;
   vector<SGPropertyNode_ptr> _removedChildren;
+  vector<hash_table *> _linkedNodes;
   mutable string _path;
   mutable string _buffer;
   hash_table * _path_cache;
@@ -1223,9 +1230,16 @@ private:
   vector <SGPropertyChangeListener *> * _listeners;
 
 
+  /**
+    * Register/unregister node that links to this node in its path cache.
+    */
+  void add_linked_node (hash_table * node) { _linkedNodes.push_back(node); }
+  bool remove_linked_node (hash_table * node);
+
+
 
   /**
-   * A very simple hash table with no remove functionality.
+   * A very simple hash table.
    */
   class hash_table {
   public:
@@ -1255,7 +1269,8 @@ private:
       bucket ();
       ~bucket ();
       entry * get_entry (const char * key, bool create = false);
-      void erase(const char * key);
+      void erase (const char * key);
+      bool erase (SGPropertyNode * node);
     private:
       int _length;
       entry ** _entries;
@@ -1267,7 +1282,8 @@ private:
     ~hash_table ();
     SGPropertyNode * get (const char * key);
     void put (const char * key, SGPropertyNode * value);
-    void erase(const char * key);
+    void erase (const char * key);
+    bool erase (SGPropertyNode * node);
 
   private:
     unsigned int hashcode (const char * key);
settimer(func {
        print("--------------- propbug.nas ----------------");

        print("\nset /foo/bar/a/b to 1");
        setprop("/foo/bar/a/b", 1);

        print("\ndump getNode(\"foo\").getNode(\"bar/a/b\")");
        props.dump(props.globals.getNode("foo").getNode("bar/a/b"));

        print("\nremove child b from foo/bar/a");
        props.globals.getNode("/foo/bar/a").removeChild("b", 0);

        settimer(func {
                print("\ndump getNode(\"foo/bar/a\")");
                props.dump(props.globals.getNode("/foo/bar/a"));

                print("\nset /foo/bar/a/b to 2");
                setprop("foo/bar/a", "b", 2);

                print("\ndump getNode(\"foo/bar/a\")");
                props.dump(props.globals.getNode("foo/bar/a"));

                print("\ndump getNode(\"foo\").getNode(\"bar/a/b\")");
                props.dump(props.globals.getNode("foo").getNode("bar/a/b"));
                print("\n--------------- propbug.nas ----------------");
        }, 1);
}, 1);

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/flightgear-devel

Reply via email to