Chuck,

>> Actually _this_ should not be weird, this should be quite a normal code; the 
>> only requirement is that check-and-save, i.e., conceptually,
>> 
>> ===
>> if (TEST(eo.someRelationship().someAttribute(),newAttributeValue)) {
>>   def 
>> new=EOUtilities.createAndInsertInstance(eo.editingContext(),'SomeRelationshipTarget')
>>   new.someAttribute=newAttributeValue
>>   eo.editingContext().saveChanges()
>> }
>> ===
>> 
>> so that I can be absolutely sure that nobody stores an attribute value which 
>> -- at the moment of COMMITTing the appropriate INSERT -- would not pass the 
>> TEST

Alas, since the TEST is (slightly) more complex than A!=B, I can't use a UNIQUE 
db restraint.

One way would be to twist the DB to do the complete restraint to me, something 
like to a pseudo-code “inserted_row.attr>=MAX(SELECT attr FROM this_table WHERE 
another_attr.isValid) AND couple more similar conditions” -- frankly I am not 
sure whether the database (FrontBase) can do that at all, and if it can, 
definitely I don't know how to.

Nevertheless this is an interesting idea which I am going to pursue (if anybody 
happens to know the solution, either how to, or that it is not possible at all, 
of course I'll be grateful for an advice, before I dive into that).

Another way, the one I've tried to exploit so far, was implement the behaviour 
app-side:

> I believe that is the only way to absolutely ensure this.  I don’t think you 
> can make a rock-solid guarantee from the app code level.

Can't I? That's bad.

So far, I thought this very simple concept should be rock-solid, but probably I 
am overlooking something of importance, as so often:

=== eo's entity locks on the someRelationship FK (among others) ===
OSC.lock() // possibly superfluous; simplifies situation by serializing 
intra-instance
try {
  ec.unlock(); ec.lock() //* to make sure we get changes from other ECs now, by 
your excellent advice
  def rel=eo.someRelationship() // in DB there might be a newer value (saved 
meantime by another instance)...
  def attr=rel.someAttribute()  // ... but it is not possible that in DB is an 
_older_ value than this
  if (TEST(attr,newAttributeValue)) {
    def 
new=EOUtilities.createAndInsertInstance(eo.editingContext(),'SomeRelationshipTarget')
    new.setSomeAttribute(newAttributeValue) // once set, I NEVER change this 
value
    eo.addObjectToBothSidesOfRelationshipWithKey(new,'someRelationship')
    eo.editingContext().saveChanges() // catching optimistic exceptions and 
repeating the process if they happen
  }
} finally {
  OSC.unlock()
}
===

My reasoning is that
- intra-instance, consistency is ensured by locked (single) OSC and by //* -- I 
am sure that I see the latest eo.someRelationship and its rel.someAttribute 
before saving, and thus the TEST is reliable; my own instance, even with 
concurrent requests, can't do anything wrong
- inter-instance, the optimistic locking based on someRelationship FK should 
prevent saving in case any other instance succeeded to save its own new 
attribute meantime.

What am I overlooking, how can this pattern fail?

In fact, to decrease the probability of the optimistic locking exception, I 
force re-fetch (in my new multi-instance code, not the single-instance old 
one), like this:

===
OSC.lock() // precisely same as above
try {
  ERXEC tempec=ERXEC.newEditingContext()
  tempec.fetchTimestamp=System.currentTimeMillis() // due to this, I don't need 
"ec.unlock(); ec.lock()", for...
  def tempeo=eo.localInstanceIn(tempec)
  def rel=tempeo.someRelationship()  // ... whatever was cached in ECs, current 
FK from eo's table gets fetched now
  def attr=rel.someAttribute()       // ... just like its attribute from rel 
target's table
  if (TEST(attr,newAttributeValue)) { // precisely same as above (the only 
difference is that the values are newer...
    def new=EOUtilities.createAndInsertInstance(tempec,'SomeRelationshipTarget')
    new.setSomeAttribute(newAttributeValue)
    tempeo.addObjectToBothSidesOfRelationshipWithKey(new,'someRelationship')
    tempec.saveChanges() // ... and thus the probability of optimistic locking 
exception (caused by different relationship FK) is smaller (though of course 
not zero)
  }
} finally {
  OSC.unlock()
}
===

Are even these patters unsafe? Why?

Thanks a big lot,
OC


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to