Esempio n. 1
0
// 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
}