I'm interesting in modeling relations between documents in CouchDB. Let say that i have three documents A,B and C. These documents may refer to each other, but there is an application constraint that cyclic dependency must not occur.
Lets take a example (-> is a marker for dependency):
A -> B
C
Two clients (C1, C2) try concurrent modification:
C1 = B -> C
C2 = C -> A
If C1 and C2 are succeed there will be cycle. The question is how to prevent it?
I was thinking about it and it seems that i need a kind of coarse grained lock for documents and atomic bulk update. The problem is atomic bulk update. CouchDB supports bulk update, but without rollback in case of version conflict. What it means:
Let say we have document V. This document represents global version (coarse grained lock)and holds version of related documents (A,B,C) for a given document revision.
V { _rev: 1, versions: [[A,1],[B,1],[C,1]] }
C1 and C2 work concurrently:
1.) C1 = get V
2.) C2 = get V
3.) C1 = get A.1, B.1, C1
4.) C2 = get A.1, B.1, C1
5.) C1 = make dependency check (everything is OK)
6.) C2 = make dependency check (everything is OK)
7.) C1 = update V regarding to intended B->C dependency {versions: [[A,1],[B,2],[C,2]] } (everything is OK)
8.) C1 = update B
9.) C2 = trying update V regarding to intended C->A dependency {versions: [[A,2],[B,1],[C,2]] } (this step will FAIL, because of CouchDB optimistic locking)
Everything is fine and nice until C1 crashes between step 7. and 8. Now the bulk insert/update coming to scene.
7.) C1 = update V regarding to intended B->C dependency {versions: [[A,1],[B,2],[C,2]] } (everything is OK) and update B
What a nice solution, unfortunately it doesn't work at all, because of bulk insert/update semantics in CouchDB http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API#Transactional_Semantics_with_Bulk_Updates. The bulk insert/update is not atomic operation.
Is there any workaround for it? May i bypass it somehow? Do i miss something important?