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 ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com
This email sent to [email protected]