// CanLock checks if the command has the UID in it's locks list. This only // determines if the UID is in the Locks slice - not if it is or is not actually // locked. This is because we may have just added the lock and have not actually // tried locking or relocking yet. func (c *Command) CanLock(uid uid.UIDLocker) bool { for _, l := range c.Locks { if uid.IsAlso(l) { return true } } return false }
// AddLock takes a UID and adds it to the Locks slice in the correct position. // Locks should always be acquired in unique Id sequence lowest to highest to // avoid deadlocks. By using this method the Locks can easily be iterated via a // range and in the correct sequence required. // // NOTE: We cannot add the same Lock twice otherwise we would deadlock ourselves // when locking - currently we silently drop duplicate locks. // // This routine is a little cute and avoids doing any 'real' sorting to keep the // elements in unique ID sequence. We add our UID to our slice. If we have one // element only it's what we just added so we bail. // // If we have multiple elements we have the appended element on the end and need // to check where it goes, shift the trailing elements up by one then write our // new element in: // // 3 7 9 4 <- append new element 4 to end // 3 7 9 4 <- correct place: 4 goes between 3 and 7 // 3 7 7 9 <- shift 7,9 up one overwriting our appended element // 3 4 7 9 <- we now write our new element into our 'hole' // // What if we can't find an element with a unique Id greater than the one we are // inserting? // // 3 7 9 10 <- append new element 10 to end // 3 7 9 10 <- correct place: 10 goes after 9, no insert point found // 3 7 9 10 <- No shifting is done, appended element not over-written // 3 4 7 10 <- new element already in correct place, nothing else to do // // This function could be more efficient with large numbers of elements by using // a binary search to find the insertion point for the new element. However this // would make the code more complex and we don't expect to handle huge numbers // of locks with this function. func (c *Command) AddLock(uid uid.UIDLocker) { if uid == nil || c.CanLock(uid) { return } c.locksModified = true c.Locks = append(c.Locks, uid) if l := len(c.Locks); l > 1 { u := uid.UniqueId() for i := 0; i < l; i++ { if u > c.Locks[i].UniqueId() { copy(c.Locks[i+1:l], c.Locks[i:l-1]) c.Locks[i] = uid break } } } }