Hi Dan,

OK, I think I've got this one nailed. The problem in in the definition
of the Retract intrinsic Userfunction in Funcall.java. It potentially
needs to do several things: it always removes a fact, but also may
need to undefinstance an object tied to that fact. So it uses
findFactById() to look up the fact, then operates on it in several
ways. Eventually it calls a package-private version of Rete.retract()
called _retract() which accepts the fact ValueVector itself as an
argument. This method is dangerous, because Bad Things will happen if
you call it with an invalid fact as an argument; one of the bad things
is the double-retraction problem that leads to the Corrupted Negcnt
exception (which always means there's a bug in the engine someplace.)
Anyway, it's dangerous, which is why it's package-private in the first
place.

Anyhow, Retract.call() makes a mistake in that it is not synchronized
with the Rete network; as a result, there is a possiblity that in
between the time the fact is looked up with findFactById and the time
it  is presented to _retract, some other thread will have already
retracted it. Then the Bad Things happen; this is precisely what was
happening in your scenario.

So, to fix it, it has to block modifications of the Rete network
inbetween those two statements.  THis means synchronizing on the
object returned by Rete.getCompiler(); so change the middle of
Retract.call() in Funcall.java to look like this:

        ...
        for (int i=1; i< vv.size(); i++) 
          {
            synchronized (engine.getCompiler())
              {
                //insides of "for" loop
              }
          }
      }


and you should see the problem go away. Let me know if this works for you.


Re: changes in ReflectFunctions outlines below: I don't think they're
necessary or warranted. 


I think Larner, Dan wrote:
> 
> I've done a little more checking into the ReteException
> I was getting while running my modified pumps example.  
> It turns out that I can cause the exception to occur regardless 
> of my addition or removal of objects...
> 
> One can start with Jess5.0a2 as delivered, and replace the line
>     rete.executeCommand("(run)");
> in jess\examples\pumps\MainInJava.java with 
>     while (true) rete.executeCommand("(run 1)");
> 
> After a while, you'll get:
> Rete Exception in routine NodeNot2::RunTestsVaryLeft while executing rule 
> LHS: [NodeNot2 ntests=1 [Test2:
> test=EQ;tokenIdx=0;leftIdx=7;leftSubIdx=-1;rightIdx=2;rightSubIdx=1] 
> ;usecount = 1] while executing defrule raise-rate-if-low.
>   Message: Corrupted Negcnt (< 0)  at line 0:  ( run 1 ) .

> 
> ===================================================================
> Here are the potential changes to jess\relect\ReflectFunctions.java
> that I mentioned.  Note that I'm not suggesting people blindly apply
> these - my knowledge of the JESS internals is insufficient to know
> what the full effects of these changes might be.

> 
> Change
> ------
> public Value call(ValueVector vv, Context context) throws ReteException
> 
> To
> --
> public synchronized Value call(ValueVector vv, Context context) throws
> ReteException
> 
> 
> Change the definition of undefine to
> -------------------------------------
> 
> // make undefine synchronized so we don't undefine while in use via
> propertyChange or ???
> 
> synchronized Value undefine(Object o) throws ReteException
>   {


---------------------------------------------------------
Ernest Friedman-Hill  
Distributed Systems Research        Phone: (925) 294-2154
Sandia National Labs                FAX:   (925) 294-2234
Org. 8920, MS 9214                  [EMAIL PROTECTED]
PO Box 969                  http://herzberg.ca.sandia.gov
Livermore, CA 94550

---------------------------------------------------------------------
To unsubscribe, send the words 'unsubscribe jess-users [EMAIL PROTECTED]'
in the BODY of a message to [EMAIL PROTECTED], NOT to the
list. List problems? Notify [EMAIL PROTECTED]
---------------------------------------------------------------------

Reply via email to