[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sqlite-dev
Subject:    Re: [sqlite-dev] w/w concurrency (was sqlite 4 LSM storage)
From:       Paul Ruizendaal <pnr () planet ! nl>
Date:       2012-07-13 12:14:06
Message-ID: 660B4292-2629-4522-AF52-8F77E701FFAF () planet ! nl
[Download RAW message or body]


On 12 Jul 2012, at 3:16 , Howard Chu wrote:

> Paul Ruizendaal wrote:
> > 
> > On 11 Jul 2012, at 18:44 , Jonathan S. Shapiro wrote:
> > 
> > > I have also been thinking about this. The problem with multiple writer
> concurrency is that it requires relatively fine-grain locking.
> 
> Yes. And a deadlock detector.

I'm not yet convinced of either assertion. Does it really require fine-grain locking \
and is a deadlock detector unavoidable?

At this point it is perhaps good to note that w/w concurrency (full "snapshot \
isolation") is full ACID, but is not always serializable, and it does not need to be.

Example of three transactions under w/w snapshot isolation:

TX0:
set a=0
set b=0
commit

TX1:
set a=a+1               TX2:
set c=a+b                set b=b+2
commit                    set d=a+b
                                commit

TX1 and TX2 do not conflict and the resulting database state is:
a=1
b=2
c=1
d=2

This outcome is impossible if TX1 occurred either before or after TX2.


> Yeah, "one committer at a time" sounds nice. I've been looking for ways to
> accomplish this in MDB as well, but ultimately I don't believe it's realistic.
Are you sure? If you keep track of the txn number of current read transactions, you \
could defer placing old pages onto the free list until all the txns referring to it \
commit or roll back. You also keep a txn number in each record's payload, it is the \
txn number of the txn that wrote the record. A write transaction acts as a read \
transaction but keeps its updates in a memory tree (the C* tree, or "write set"). \
Upon commit it acquires a global write lock and tests that each on disk element also \
in the write set has a lower or equal txn number, and if so it writes all elements as \
usual. If not, the txn fails and no update takes place (or perhaps is retried).

In fairness, one could view the record txn number as a record level lock, so it is a \
form of fine grained locking. Also, if there are foreign key constraints the front \
end should perform a dummy write on the foreign tuple to make sure that a parallel \
modification is detected (in effect, a dummy write acts if a write lock was in \
place).

A slightly more risky variant is not to keep a record txn number, but to store both a \
'before' and 'after' value in the write set. The check would then be that on commit \
time the record is still the same -- perhaps written many times in between, but now \
the same as it was when the transaction started. This could even be done as an even \
finer grained lock: field level locking.

> I have the feeling that writing the conflict detection handler will drive you
> batty; if you write a very simple-minded one it will lead to too many txn retries.
The very essence of SQLite is doing simple-minded, but highly usable things. Yes, I \
guess that if you have a lengthy write transaction that updates a "hot spot" it would \
fail all the time: the hotspot would nearly always have another (quick) write \
transaction committing before the lengthy one gets its work done. Such a query could \
perhaps take out a global write lock in order to complete (just as every write \
transaction is doing in current SQLite and MDB) -- this would be similar to BEGIN \
IMMEDIATE in nature: http://www.sqlite.org/lang_transaction.html

Paul


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic