Random musings on random stuff.
This is a reply, basepost
Quite probably yes :-)
However initially I thought I'd start off with trying to get single values right :-) (A single value can be a dict of course, but your point holds for arbitrary unrelated values)
I suspect the way to deal with that might be to do something like:
S = Store()Which seems pretty nice/simple. It'd be useful for the commit failure to indicate which value was broken by a concurrent update, but not necessary.
D = S.using("account_one", "account_two", "myaccount")
D["myaccount"].set(D["account_one"].value+D["account_two"].value)
D["account_one"].set(0)
D["account_two"].set(0)
D.commit()
> The tricky part is that other threads asking for the value should getI think this approach deals with this naturally. cf:
> the old value until the commit has been done - so you need to know
> which thread 'value' is being asked for from.
def get(self, key): # in StoreThis means that the value in 2 threads for the same checked out value names can be different, but they get warning of this when they try to commit.
return self.store[key].clone()
...
def clone(self): # in Value
return Value(self.version, self.value,self.store,self.key)
...
def set(self, key, value):
if not (self.store[key].version > value.version):
self.store[key] = Value(value.version+1, value.value, self, key)
value.version= value.version+1
else:
raise ConcurrentUpdate
S = Store()I did think that this would work with the current code but changing the value to something more complex - like this:
D = S.using("account_one", "account_two", "myaccount")
D["myaccount"].set(D["account_one"].value+D["account_two"].value)
D["account_one"].set(0)
E = S.using("account_one", "myaccount")
E["myaccount"].set(E["myaccount"].value-100)
E["account_one"].set(100)
E.commit()
D["account_two"].set(0)
D.commit()
S = Store()But in practice, because I'm not doing a copy here of self.value:
D = S.using("accounts")
D.set({"account_one":50, "account_two":100, "myaccount":0})
D.commit()
print "here"
S.dump()
X = D.value
X["myaccount"] = X["account_one"] + X["account_two"]
X["account_one"] = 0
X["account_two"] = 0
D.set(X)
D.commit()
S.dump()
print "Committed", D.value["myaccount"]
def clone(self): # in ValueI end up with accidental concurrent access, which is easy to fix, for
return Value(self.version, self.value,self.store,self.key)
import copyAs well as here:
....
def clone(self): # in Value
return Value(self.version, copy.deepcopy(self.value),
self.store, self.key)
S = Store()Fails as follows:
D = S.using("accounts")
D.set({"account_one":50, "account_two":100, "myaccount":0})
D.commit() # First
S.dump()
X = D.value
X["myaccount"] = X["account_one"] + X["account_two"]
X["account_one"] = 0
E = S.using("accounts")
Y = E.value
Y["myaccount"] = Y["myaccount"]-100
Y["account_one"]= 100
E.set(Y)
E.commit() # Second
S.dump()
X["account_two"] = 0
D.set(X)
D.commit() # Third
S.dump()
print "Committed", D.value["myaccount"]
accounts : Value(1, {'account_two': 100, 'myaccount': 0, 'account_one': 50})(which is of course the error wanted - since we want to be able to detect failure)
accounts : Value(2, {'account_two': 100, 'myaccount': -100, 'account_one':
100})
Traceback (most recent call last):
File "./NewSTM.py", line 70, in <module>
D.commit() # Third
File "./NewSTM.py", line 20, in commit
self.store.set(self.key, self)
File "./NewSTM.py", line 37, in set
raise ConcurrentUpdate
__main__.ConcurrentUpdate