// Reserve will reserve an item with the id in the DefaultReservation for the given amount of // time. func (dr *DefaultReservation) Reserve(d time.Duration) error { log.Debugf("[Sync:Reservation] Attempting to reserve '%s' for %s...", dr.id, d) lockpath := constructPath(dr.path, dr.id) // Check if the reservation already exists b, _, err := zookeeper.Get(lockpath) if err == nil { // It exists, check if expired var expired time.Time expired.GobDecode(b) log.Debugf("[Sync:Reservation] Read existing node for '%s', expires at %s", dr.id, expired) if expired.Before(time.Now()) { log.Debugf("[Sync:Reservation] Deleting expired lock '%s'", dr.id) // It has expired, delete the node and get the reservation as usual zookeeper.Delete(lockpath, -1) } else { return ErrReserved } } expires := time.Now().Add(d) expiresBytes, err := expires.GobEncode() if err != nil { return err } for { _, err = zookeeper.Create(lockpath, expiresBytes, 0, dr.acl) if err == gozk.ErrNoNode { createParents(dr.path) } else if err == nil { break } else { log.Warnf("[Reservation] ZK error creating ephemeral lock node for reservation: %v", err) return err } } log.Debugf("[Sync:Reservation] Created lock node for '%s', expires at %s", dr.id, expires) return nil }
// findLowestSequenceNode within a particular lock path func findLowestSequenceNode(path string, seq int) (lowestSeq int, prevSeqPath string, err error) { // Read all the children of the node // This is why we create sequential nodes under a parent node based on the lock ID // If not, say we stored all ephemeral locks under a higher level parent, // we would be checking nodes of every lock currently in play, rather than locks // on this ID children, _, err := zookeeper.Children(path) if err != nil { return -1, "", err } var ttl time.Time lowestSeq = seq prevSeq := 0 prevSeqPath = "" for _, p := range children { // Check if this lock has timed out data, _, _ := zookeeper.Get(path + "/" + p) if len(data) > 0 { ttl.GobDecode(data) if ttl.Before(time.Now()) { log.Tracef("[RegionLock] Deleting expired lock '%s'", path+"/"+p) zookeeper.Delete(path+"/"+p, -1) continue } } s, err := parseSeq(p) if err != nil { return -1, "", err } if s < lowestSeq { lowestSeq = s } if s < seq && s > prevSeq { prevSeq = s prevSeqPath = p } } return lowestSeq, prevSeqPath, err }