Beispiel #1
0
// executeCmd synchronously runs Store.ExecuteCmd. The store is looked
// up from the store map if specified by header.Replica; otherwise,
// the command is being executed locally, and the replica is
// determined via lookup of header.Key in the ranges slice.
func (db *LocalDB) executeCmd(method string, args storage.Request, reply storage.Response) {
	// If the replica isn't specified in the header, look it up.
	var err error
	var store *storage.Store
	// If we aren't given a Replica, then a little bending over
	// backwards here. We need to find the Store, but all we have is the
	// Key. So find its Range locally, and pull out its Replica which we
	// use to find the Store.  This lets us use the same codepath below
	// (store.ExecuteCmd) for both locally and remotely originated
	// commands.
	header := args.Header()
	if header.Replica.NodeID == 0 {
		if repl := db.lookupReplica(header.Key); repl != nil {
			header.Replica = *repl
		} else {
			err = util.Errorf("unable to lookup range replica for key %q", string(header.Key))
		}
	}
	if err == nil {
		store, err = db.GetStore(&header.Replica)
	}
	if err != nil {
		reply.Header().Error = err
	} else {
		store.ExecuteCmd(method, args, reply)
	}
}
Beispiel #2
0
// executeCmd looks up the store specified by header.Replica, and runs
// Store.ExecuteCmd.
func (n *Node) executeCmd(method string, args storage.Request, reply storage.Response) error {
	store, err := n.localDB.GetStore(&args.Header().Replica)
	if err != nil {
		return err
	}
	store.ExecuteCmd(method, args, reply)
	return nil
}
Beispiel #3
0
func (db *DistDB) routeRPCInternal(method string, args storage.Request, replyChan interface{}) {
	// Verify permissions.
	if err := db.verifyPermissions(method, args.Header()); err != nil {
		sendErrorReply(err, replyChan)
		return
	}

	// Retry logic for lookup of range by key and RPCs to range replicas.
	go func() {
		retryOpts := util.RetryOptions{
			Tag:         fmt.Sprintf("routing %s rpc", method),
			Backoff:     retryBackoff,
			MaxBackoff:  maxRetryBackoff,
			Constant:    2,
			MaxAttempts: 0, // retry indefinitely
		}
		err := util.RetryWithBackoff(retryOpts, func() (bool, error) {
			rangeMeta, err := db.rangeCache.LookupRangeMetadata(args.Header().Key)
			if err == nil {
				err = db.sendRPC(rangeMeta.Replicas, method, args, replyChan)
			}
			if err != nil {
				// Range metadata might be out of date - evict it.
				db.rangeCache.EvictCachedRangeMetadata(args.Header().Key)

				// If retryable, allow outer loop to retry.
				if retryErr, ok := err.(util.Retryable); ok && retryErr.CanRetry() {
					log.Warningf("failed to invoke %s: %v", method, err)
					return false, nil
				}
			}
			return true, err
		})
		if err != nil {
			sendErrorReply(err, replyChan)
		}
	}()
}
Beispiel #4
0
// routeRPC verifies permissions and looks up the appropriate range
// based on the supplied key and sends the RPC according to the
// specified options. routeRPC sends asynchronously and returns a
// response value on the replyChan channel when the call is
// complete.
func (db *DistDB) routeRPC(method string, args storage.Request, replyChan interface{}) {
	if isTransactional(method) {
		db.coordinator.addRequest(args.Header())
	}
	db.routeRPCInternal(method, args, replyChan)
}