Skip to content
Snippets Groups Projects
base_cluster_invoker.go 3.01 KiB
Newer Older
vito.he's avatar
vito.he committed
package cluster_impl
vito.he's avatar
vito.he committed

import (
	gxnet "github.com/AlexStocks/goext/net"
	jerrors "github.com/juju/errors"
vito.he's avatar
vito.he committed
	"github.com/tevino/abool"
)

import (
	"github.com/dubbo/go-for-apache-dubbo/cluster"
vito.he's avatar
vito.he committed
	"github.com/dubbo/go-for-apache-dubbo/common"
	"github.com/dubbo/go-for-apache-dubbo/protocol"
	"github.com/dubbo/go-for-apache-dubbo/version"
vito.he's avatar
vito.he committed
)

type baseClusterInvoker struct {
	directory      cluster.Directory
	availablecheck bool
	destroyed      *abool.AtomicBool
}

vito.he's avatar
vito.he committed
func newBaseClusterInvoker(directory cluster.Directory) baseClusterInvoker {
vito.he's avatar
vito.he committed
	return baseClusterInvoker{
		directory:      directory,
		availablecheck: true,
vito.he's avatar
vito.he committed
		destroyed:      abool.NewBool(false),
	}
}
vito.he's avatar
vito.he committed
func (invoker *baseClusterInvoker) GetUrl() common.URL {
vito.he's avatar
vito.he committed
	return invoker.directory.GetUrl()
}

func (invoker *baseClusterInvoker) Destroy() {
	//this is must atom operation
	if invoker.destroyed.SetToIf(false, true) {
		invoker.directory.Destroy()
	}
}

func (invoker *baseClusterInvoker) IsAvailable() bool {
vito.he's avatar
vito.he committed
	//TODO:sticky connection
vito.he's avatar
vito.he committed
	return invoker.directory.IsAvailable()
}

//check invokers availables
func (invoker *baseClusterInvoker) checkInvokers(invokers []protocol.Invoker, invocation protocol.Invocation) error {
	if len(invokers) == 0 {
		ip, _ := gxnet.GetLocalIP()
vito.he's avatar
vito.he committed
		return jerrors.Errorf("Failed to invoke the method %v . No provider available for the service %v from "+
			"registry %v on the consumer %v using the dubbo version %v .Please check if the providers have been started and registered.",
vito.he's avatar
vito.he committed
			invocation.MethodName(), invoker.directory.GetUrl().SubURL.Key(), invoker.directory.GetUrl().String(), ip, version.Version)
	}
	return nil

}

//check cluster invoker is destroyed or not
func (invoker *baseClusterInvoker) checkWhetherDestroyed() error {
	if invoker.destroyed.IsSet() {
		ip, _ := gxnet.GetLocalIP()
		return jerrors.Errorf("Rpc cluster invoker for %v on consumer %v use dubbo version %v is now destroyed! can not invoke any more. ",
			invoker.directory.GetUrl().Service(), ip, version.Version)
	}
	return nil
}

func (invoker *baseClusterInvoker) doSelect(lb cluster.LoadBalance, invocation protocol.Invocation, invokers []protocol.Invoker, invoked []protocol.Invoker) protocol.Invoker {
	//todo:ticky connect 粘纸连接
	if len(invokers) == 1 {
		return invokers[0]
	}
vito.he's avatar
vito.he committed
	selectedInvoker := lb.Select(invokers, invocation)

	//judge to if the selectedInvoker is invoked

	if !selectedInvoker.IsAvailable() || !invoker.availablecheck || isInvoked(selectedInvoker, invoked) {
		// do reselect
		var reslectInvokers []protocol.Invoker

		for _, invoker := range invokers {
			if !invoker.IsAvailable() {
				continue
			}

			if !isInvoked(invoker, invoked) {
				reslectInvokers = append(reslectInvokers, invoker)
			}
		}

		if len(reslectInvokers) > 0 {
vito.he's avatar
vito.he committed
			return lb.Select(reslectInvokers, invocation)
		} else {
			return nil
		}
	}
	return selectedInvoker

}

func isInvoked(selectedInvoker protocol.Invoker, invoked []protocol.Invoker) bool {
	if len(invoked) > 0 {
		for _, i := range invoked {
			if i == selectedInvoker {
				return true
			}
		}
	}
	return false
}