예제 #1
0
파일: store.go 프로젝트: tomzhang/p2
func (s consulStore) Delete(id rcf.ID) error {
	key := kp.RollPath(id.String())
	_, err := s.kv.Delete(key, nil)
	if err != nil {
		return consulutil.NewKVError("delete", key, err)
	}
	return nil
}
예제 #2
0
파일: store.go 프로젝트: tomzhang/p2
func (s consulStore) Lock(id rcf.ID, session string) (bool, error) {
	key := kp.LockPath(kp.RollPath(id.String()))
	success, _, err := s.kv.Acquire(&api.KVPair{
		Key:     key,
		Value:   []byte(session),
		Session: session,
	}, nil)
	if err != nil {
		return false, consulutil.NewKVError("acquire", key, err)
	}
	return success, nil
}
예제 #3
0
파일: store.go 프로젝트: tomzhang/p2
func (s consulStore) Put(u rollf.Update) error {
	b, err := json.Marshal(u)
	if err != nil {
		return err
	}

	key := kp.RollPath(u.NewRC.String())
	success, _, err := s.kv.CAS(&api.KVPair{
		Key:   kp.RollPath(u.NewRC.String()),
		Value: b,
		// it must not already exist
		ModifyIndex: 0,
	}, nil)
	if err != nil {
		return consulutil.NewKVError("cas", key, err)
	}
	if !success {
		return fmt.Errorf("update with new RC ID %s already exists", u.NewRC)
	}
	return nil
}
예제 #4
0
파일: farm.go 프로젝트: tomzhang/p2
// close one child
func (rlf *Farm) releaseChild(id fields.ID) {
	rlf.logger.WithField("ru", id).Infoln("Releasing update")
	close(rlf.children[id].quit)
	delete(rlf.children, id)

	// if our lock is active, attempt to gracefully release it
	if rlf.lock != nil {
		err := rlf.lock.Unlock(kp.LockPath(kp.RollPath(id.String())))
		if err != nil {
			rlf.logger.WithField("ru", id).Warnln("Could not release update lock")
		}
	}
}
예제 #5
0
파일: store.go 프로젝트: tomzhang/p2
func (s consulStore) Get(id rcf.ID) (rollf.Update, error) {
	key := kp.RollPath(id.String())
	kvp, _, err := s.kv.Get(key, nil)
	if err != nil {
		return rollf.Update{}, consulutil.NewKVError("get", key, err)
	}

	var ret rollf.Update
	err = json.Unmarshal(kvp.Value, &ret)
	if err != nil {
		return rollf.Update{}, err
	}
	return ret, nil
}
예제 #6
0
파일: farm.go 프로젝트: tomzhang/p2
// Start is a blocking function that monitors Consul for updates. The Farm will
// attempt to claim updates as they appear and, if successful, will start
// goroutines for those updatesto do their job. Closing the quit channel will
// cause this function to return, releasing all locks it holds.
//
// Start is not safe for concurrent execution. Do not execute multiple
// concurrent instances of Start.
func (rlf *Farm) Start(quit <-chan struct{}) {
	subQuit := make(chan struct{})
	defer close(subQuit)
	rlWatch, rlErr := rlf.rls.Watch(subQuit)

START_LOOP:
	for {
		select {
		case <-quit:
			rlf.logger.NoFields().Infoln("Halt requested, releasing updates")
			rlf.releaseChildren()
			return
		case session := <-rlf.sessions:
			if session == "" {
				// our session has expired, we must assume our locked children
				// have all been released and that someone else may have
				// claimed them by now
				rlf.logger.NoFields().Errorln("Session expired, releasing updates")
				rlf.lock = nil
				rlf.releaseChildren()
			} else {
				// a new session has been acquired - only happens after an
				// expiration message, so len(children)==0
				rlf.logger.WithField("session", session).Infoln("Acquired new session")
				lock := rlf.kps.NewUnmanagedLock(session, "")
				rlf.lock = &lock
				// TODO: restart the watch so that you get updates right away?
			}
		case err := <-rlErr:
			rlf.logger.WithError(err).Errorln("Could not read consul updates")
		case rlFields := <-rlWatch:
			rlf.logger.WithField("n", len(rlFields)).Debugln("Received update update")
			if rlf.lock == nil {
				// we can't claim new nodes because our session is invalidated.
				// raise an error and ignore this update
				rlf.logger.NoFields().Warnln("Received update update, but do not have session to acquire locks")
				continue
			}

			// track which children were found in the returned set
			foundChildren := make(map[fields.ID]struct{})
			for _, rlField := range rlFields {
				rlLogger := rlf.logger.SubLogger(logrus.Fields{
					"ru": rlField.NewRC,
				})
				rcField, err := rlf.rcs.Get(rlField.NewRC)
				if err != nil {
					rlLogger.WithError(err).Errorln("Could not read new RC")
					continue
				}
				rlLogger = rlLogger.SubLogger(logrus.Fields{
					"pod": rcField.Manifest.ID(),
				})
				if _, ok := rlf.children[rlField.NewRC]; ok {
					// this one is already ours, skip
					rlLogger.NoFields().Debugln("Got update already owned by self")
					foundChildren[rlField.NewRC] = struct{}{}
					continue
				}

				err = rlf.lock.Lock(kp.LockPath(kp.RollPath(rlField.NewRC.String())))
				if _, ok := err.(kp.AlreadyLockedError); ok {
					// someone else must have gotten it first - log and move to
					// the next one
					rlLogger.NoFields().Debugln("Lock on update was denied")
					continue
				} else if err != nil {
					rlLogger.NoFields().Errorln("Got error while locking update - session may be expired")
					// stop processing this update and go back to the select
					// chances are this error is a network problem or session
					// expiry, and all the others in this update would also fail
					continue START_LOOP
				}

				// at this point the ru is ours, time to spin it up
				rlLogger.NoFields().Infoln("Acquired lock on new update, spawning")

				newChild := rlf.factory.New(rlField, rlLogger, *rlf.lock)
				childQuit := make(chan struct{})
				rlf.children[rlField.NewRC] = childRU{ru: newChild, quit: childQuit}
				foundChildren[rlField.NewRC] = struct{}{}

				go func(id fields.ID) {
					if !newChild.Run(childQuit) {
						// returned false, farm must have asked us to quit
						return
					}
					// our lock on this RU won't be released until it's deleted,
					// so if we fail to delete it, we have to retry
					for err := rlf.rls.Delete(id); err != nil; err = rlf.rls.Delete(id) {
						rlLogger.WithError(err).Errorln("Could not delete update")
						time.Sleep(1 * time.Second)
					}
				}(rlField.NewRC) // do not close over rlField, it's a loop variable
			}

			// now remove any children that were not found in the result set
			rlf.logger.NoFields().Debugln("Pruning updates that have disappeared")
			for id := range rlf.children {
				if _, ok := foundChildren[id]; !ok {
					rlf.releaseChild(id)
				}
			}
		}
	}
}