func NewCassandraHostList(initialHostList []CassandraHost, useAutodiscovery bool, shutdown chan int) *CassandraHostList { up := make(map[string]CassandraHost) dwn := make(map[string]CassandraHost) var mtx sync.Mutex avail := make([]string, 0) ret := &CassandraHostList{up, dwn, avail, shutdown, mtx, 0, false} for _, val := range initialHostList { ret.Down[val.String()] = val } // TODO: configurable whether or not to poll, poll frequency pollForever := config.Get().Settings().PollServersForever ret.StartPollingServers(true, pollForever, time.Duration(5)*time.Second) // comb the up list to include only up nodes if useAutodiscovery { go ret.NodeAutoDiscovery(time.Duration(10) * time.Second) // TODO: make configurable } return ret }
// Process the arguments of a thrift call off the TProtocol and store it for future access // NOTE: this actually reads from the inbound protocol, so you will have to call the WriteArgs(TProtocol) method to // write those back to an upstream server or whatever those args were originally meant for func (p *ArgsRetainingProcessor) ReadArgs(iprot thrift.TProtocol) (success bool, err thrift.TException) { // ok, so this may look a little silly/stupid/insane, but, we're doing it this way (using reflect) to // generalize over the generated thrift bindings, which are pretty rigid and offer little extensibility t1 := time.Now() defer func() { t := config.Get().Timer("cassbounce.server.cassutils.ArgsRetainingProcessor.ReadArgs") t.Update(uint64(time.Now().Sub(t1))) }() // run the constructor which will return for us an interface{} args := p.constructor() // reflect the type of the interface{} (which is some args instance) typ := reflect.TypeOf(args) // get its "Read" method meth, isValid := typ.MethodByName("Read") if !isValid { // should never fail, unless the thrift bindings have changed drastically log.Print("ArgsRetainingProcessor:ReadArgs error getting valid Read method from ", typ) return } // build args for the "Read" method argsArgs := []reflect.Value{reflect.ValueOf(args), reflect.ValueOf(iprot)} // call that "Read" method and get its first return value (Read only returns one Value) ret := meth.Func.Call(argsArgs) // if it is non-nil, then it is (should be) some TProtocolException if !ret[0].IsNil() { // there was an error reading the arguments // try casting it to the actual TProtocolException concreteExc, ok := ret[0].Interface().(thrift.TProtocolException) if !ok { // should never fail... unless the thrift bindings have changed drastically log.Print("ArgsRetainingProcessor:ReadArgs error getting valid TProtocolException from Read method") return } err = concreteExc } else { p.gotArgs = true p.argsTypCache = typ p.args = args } return p.gotArgs, err }
func main() { flag.Parse() // global shutdown signal - a number is sent over when services should shut down shutdown := make(chan int) // settings settings := config.NewAppSettings() // settings.InitialServerList = initial settings.NodeAutodiscovery = *nodeAutodiscovery settings.ListenAddress = *listenAddress settings.PollServersForever = *pollServers settings.PoolRecycleDuration = time.Duration(*poolRecycleDuration) * time.Second settings.PoolRecycleJitter = *poolRecycleJitter settings.PoolSize = *poolSize settings.PoolConnectionAcquireTimeout = time.Duration(*poolConnectionAcquireTimeout) * time.Millisecond settings.PoolConnectionAcquireRetries = *poolConnectionAcquireRetries config.Get().SetSettings(settings) // global app app := server.New() app.ShutdownChan = shutdown // host list set up (this must happen after the global app object is set up) initial := parseInitialServerList(*initialServerList) // this will block until at least one successful connection can be established outboundHostList := server.NewCassandraHostList(initial, *nodeAutodiscovery, shutdown) app.SetHostList(outboundHostList) // listen forever err := app.Listen() if err != nil { log.Fatal("Could not listen on interface: ", settings.ListenAddress, " error: ", err) os.Exit(1) } }