4

I have a tree T, nodes of which can be addressed by their paths (payloads of nodes contain some names that can be glued together into a path). What I would like to have is some mechanism (algorithm, auxiliary data structure etc.) that will allow, given the path P0, lock an entire sub-tree in such a fashion that:

  • attempts to lock on any path P1 (where P1 starts with P0, i.e. P1 belongs to the locked subtree) will result in lock for P1 being the one for P0 (well, it might be not the very same lock, but operations on P1 should wait until P0 lock is free);
  • but when P0 lock is released, any lock for P2, where P2 starts with P0, but not P2 starts with P1, i.e. P2 subtree and P1 subtree are different, different locks will be granted for those two paths, and so on.

I tackled this task for a couple of times, but I wound up with an over-complicated code that was messy and used some kind of tree for storing locks itself, which was even heavier that the tree I tried to lock.

In case my question is unclear, please let me know if you'd like to see some drawings/diagrams or anything that would help.

tkroman
  • 4,811
  • 1
  • 26
  • 46
  • 1
    Just trying to clarify: Lets say `A` is the root, with two children `B` & `C`. When `A` is locked, `B` & `C` can not be locked (they are in the subtree of `A`), but if `A` is not locked, `B` & `C` can be locked separately. Is this correct? – shapiro yaacov Jul 14 '15 at 09:25
  • @shapiro.yaacov, yes, that is correct. The first condition is pretty simple to implement, this is the second part that gives me the headache. – tkroman Jul 14 '15 at 09:28
  • You probably want to look at how databases lock their b-trees. No idea how that actually works, but I'd assume they had to solve this problem efficiently one way or another. – Voo Jul 14 '15 at 09:38

3 Answers3

1

Disclaimer: This is very similar to a HW assignment I did in 2009, so I remember the basic idea, not the details. In any case, I suggest the following idea:

Each node in the tree has it's own lock. Every locking action starts from the root of the tree, and follows down towards the desired node, locking each node on the way down. If it encounters a locked node (that isn't the root), the locking action is terminated (unsuccessfully), or set to wait and try again (like busy wait). If the root itself is locked, it might be a temporary lock for another action taking place. If the root is not locked but an inner node is, it is really locked.
Unlocking might be different, not sure if following the path down from the root is necessary. (it might be, so this is worth checking).

EDIT:
While working up the tree after the required node is locked, also mark the nodes on the path to the tree as ones that have some in their subtree locked. This way when you are locking a node you can know if there is a node in that subtree that is already locked.

shapiro yaacov
  • 2,308
  • 2
  • 26
  • 39
  • The described scheme doesn't handle the part whee you check if anything below the desired node is locked. Actually it seems like a rather inefficient implementation of a single global lock that's taken while a lock operation is in progress (you can always only lock a single subnode at the same time) – Voo Jul 14 '15 at 11:29
  • Seems like you could then avoid the heavy cost of one lock per node, by just having one condition variable to wait on (for everybody who's waiting on a subnode) and an atomic integer. With that you also avoid the whole locking of the root node all the times. – Voo Jul 14 '15 at 11:50
  • @Voo - you still need to lock the path from the root to the required node for you to update the values in nodes on that path, otherwise you're in for a messy time (what happens when two threads want to lock a node and it's child?) – shapiro yaacov Jul 14 '15 at 11:53
  • atomic compare exchange. – Voo Jul 14 '15 at 12:06
  • @Voo - please elaborate. compare_exchange (weak or strong) is great for **a** node. Not for a path of nodes. – shapiro yaacov Jul 14 '15 at 14:03
  • If the count is larger than 0 the node is locked, if not it's free. You still need one real lock for the conditional waits and have to instantiate locks for all the nodes you *really* want to lock, but in a large tree that should give substantial improvements not just performance but also space-wise – Voo Jul 15 '15 at 17:16
  • Every node will need a lock and a boolean, that is the space cost of my solution. Sorry if that was misunderstood. – shapiro yaacov Jul 15 '15 at 20:01
1

I don't believe OP is still waiting for new answers, so this one is rather for future visitors of this page. The question is about mechanisms, but I would like to recommend a software solution.

Locktopus allows to lock subtrees. Additionally, it can lock multiple resources (atomically) for exclusive (write) or shared (read) access.

0

I might be missing something but i think your requirements are easily solved by first computing the inverse transitive closure of your tree which can be computed in linear time.

The basic idea is that knowing if a node is safe to operate on, can be reduce to knowing if any of its parent haven't been locked.

To do so, you keep a set of locked nodes. Locking a sub-tree is done by simply adding its root to the locked_nodes set, and unlocking a subtree is done by removing its root from the same set ( booth O(1) operations) Given a node, to know if the node (or equivalently the sub-tree rooted on that node) can be operated on :

Intersection(parents(node),locked_nodes) = empty_set

The set "parent(node)" is extracted from the inverse transitive closure.

GreyGeek
  • 918
  • 5
  • 14
  • How do you deal with a case where a node wants to be locked, but one of the nodes in its subtree is already locked? If you'd check the path from each node to the root (and see if the required node is on that path), it could take `O(n logn)`. – shapiro yaacov Jul 14 '15 at 13:12
  • You can compute the transitive closure, and check if any node in the transitive closure of your given node is already locked. This give you a check in constant time. But from the what I understand from your description, I dont understand why you would need to check for locked subtrees before locking a node.can you clarify? – GreyGeek Jul 14 '15 at 15:30
  • Imho, the use of a lock is to make sure no one touches any node in that subtree. This means you can not lock a subtree if some part of it is already locked. It would imply you are allowed to alter all nodes in that subtree, when the part of it already locked should really be un reachable to you – shapiro yaacov Jul 14 '15 at 20:13
  • @shapiro.yaacov ok got it, so in that case you need booth the transitive closure and and the inverse transitive closure as i said in the previous comment – GreyGeek Jul 14 '15 at 20:51