예제 #1
0
func (o *Server) ObtainConfig() (err error) {
	e := NewEnvGetter(fmt.Sprintf("OORT_%s", strings.ToUpper(o.serviceName)), "_")
	envSkipSRV := e.Get("SKIP_SRV")
	// Check whether we're supposed to skip loading via srv method
	if strings.ToLower(envSkipSRV) != "true" {
		s := &srvconf.SRVLoader{
			SyndicateURL: e.Get("SYNDICATE_OVERRIDE"),
		}
		s.Record, err = GenServiceID(o.serviceName, "syndicate", "tcp")
		if err != nil {
			if e.Get("SYNDICATE_OVERRIDE") == "" {
				log.Println(err)
			} else {
				log.Fatalln("No SYNDICATE_OVERRIDE provided and", err)
			}
		}
		if e.Get("SYNDICATE_OVERRIDE") != "" {
			log.Println("Over wrote syndicate url with url from env!", e.Get("SYNDICATE_OVERRIDE"))
		}
		nc, err := s.Load()
		if err != nil {
			return err
		}
		o.ring, err = ring.LoadRing(bytes.NewReader(nc.Ring))
		if err != nil {
			return fmt.Errorf("Error while loading ring for config get via srv lookup: %s", err)
		}
		err = ring.PersistRingOrBuilder(o.ring, nil, fmt.Sprintf("%s/ring/%d-%s.ring", o.cwd, o.ring.Version(), o.serviceName))
		if err != nil {
			return err
		}
		o.localID = nc.Localid
		o.ring.SetLocalNode(o.localID)
		o.ringFile = fmt.Sprintf("%s/ring/%d-%s.ring", o.cwd, o.ring.Version(), o.serviceName)
		err = o.loadCmdCtrlConfig()
		if err != nil {
			return err
		}
	} else {
		// if you skip the srv load you have to provide all of the info in env vars!
		log.Println("Skipped SRV Config attempting to load from env")
		s, err := strconv.ParseUint(e.Get("LOCALID"), 10, 64)
		if err != nil {
			return fmt.Errorf("Unable to load env specified local id")
		}
		o.localID = s
		o.ringFile = e.Get("RING_FILE")
		o.ring, _, err = ring.RingOrBuilder(o.ringFile)
		if err != nil {
			return fmt.Errorf("Unable to road env specified ring: %s", err)
		}
		o.ring.SetLocalNode(o.localID)
		err = o.loadCmdCtrlConfig()
		if err != nil {
			return err
		}
	}
	return nil
}
예제 #2
0
파일: cmdctrl.go 프로젝트: wreese/oort
func (o *Server) RingUpdate(newversion int64, ringBytes []byte) int64 {
	o.cmdCtrlLock.Lock()
	defer o.cmdCtrlLock.Unlock()
	log.Println("Got ring update notification. Trying to update to version:", newversion)
	newring, err := ring.LoadRing(bytes.NewReader(ringBytes))
	if err != nil {
		log.Println("Error loading ring during update:", err)
		return o.Ring().Version()
	}
	if newring.Version() != newversion {
		log.Println("Provided ring version != version in ring")
		return o.Ring().Version()
	}
	fname := fmt.Sprintf("%s/ring/%d-%s.ring", o.cwd, newring.Version(), o.serviceName)
	writeBytes(fname, &ringBytes)
	o.SetRing(newring, fname)
	return o.Ring().Version()
}
예제 #3
0
func NewReplValueStore(c *ReplValueStoreConfig) *ReplValueStore {
	cfg := resolveReplValueStoreConfig(c)
	rs := &ReplValueStore{
		logError:                   cfg.LogError,
		logDebug:                   cfg.LogDebug,
		logDebugOn:                 cfg.LogDebug != nil,
		addressIndex:               cfg.AddressIndex,
		valueCap:                   int(cfg.ValueCap),
		concurrentRequestsPerStore: cfg.ConcurrentRequestsPerStore,
		failedConnectRetryDelay:    cfg.FailedConnectRetryDelay,
		ftlsConfig:                 cfg.StoreFTLSConfig,
		grpcOpts:                   cfg.GRPCOpts,
		stores:                     make(map[string]*replValueStoreAndTicketChan),
		ringServer:                 cfg.RingServer,
		ringServerGRPCOpts:         cfg.RingServerGRPCOpts,
		ringCachePath:              cfg.RingCachePath,
		ringClientID:               cfg.RingClientID,
	}
	if rs.logError == nil {
		rs.logError = flog.Default.ErrorPrintf
	}
	if rs.logDebug == nil {
		rs.logDebug = func(string, ...interface{}) {}
	}
	if rs.ringCachePath != "" {
		if fp, err := os.Open(rs.ringCachePath); err != nil {
			rs.logDebug("replValueStore: error loading cached ring %q: %s", rs.ringCachePath, err)
		} else if r, err := ring.LoadRing(fp); err != nil {
			fp.Close()
			rs.logDebug("replValueStore: error loading cached ring %q: %s", rs.ringCachePath, err)
		} else {
			fp.Close()
			rs.ring = r
		}
	}
	return rs
}
예제 #4
0
func (rs *ReplValueStore) ringServerConnector(exitChan chan struct{}) {
	sleeperTicks := 2
	sleeperTicker := time.NewTicker(time.Second)
	sleeper := func() {
		for i := sleeperTicks; i > 0; i-- {
			select {
			case <-exitChan:
				break
			case <-sleeperTicker.C:
			}
		}
		if sleeperTicks < 60 {
			sleeperTicks *= 2
		}
	}
	for {
		select {
		case <-exitChan:
			break
		default:
		}
		ringServer := rs.ringServer
		if ringServer == "" {
			var err error

			ringServer, err = oort.GetRingServer("value")
			if err != nil {
				rs.logError("replValueStore: error resolving ring service: %s", err)
				sleeper()
				continue
			}
		}
		conn, err := grpc.Dial(ringServer, rs.ringServerGRPCOpts...)
		if err != nil {
			rs.logError("replValueStore: error connecting to ring service %q: %s", ringServer, err)
			sleeper()
			continue
		}
		stream, err := synpb.NewSyndicateClient(conn).GetRingStream(context.Background(), &synpb.SubscriberID{Id: rs.ringClientID})
		if err != nil {
			rs.logError("replValueStore: error creating stream with ring service %q: %s", ringServer, err)
			sleeper()
			continue
		}
		connDoneChan := make(chan struct{})
		somethingICanTakeAnAddressOf := int32(0)
		activity := &somethingICanTakeAnAddressOf
		// This goroutine will detect when the exitChan is closed so it can
		// close the conn so that the blocking stream.Recv will get an error
		// and everything will unwind properly.
		// However, if the conn errors out on its own and exitChan isn't
		// closed, we're going to loop back around and try a new conn, but we
		// need to clear out this goroutine, which is what the connDoneChan is
		// for.
		// One last thing is that if nothing happens for fifteen minutes, we
		// can assume the conn has gone stale and close it, causing a loop
		// around to try a new conn.
		// It would be so much easier if Recv could use a timeout Context...
		go func(c *grpc.ClientConn, a *int32, cdc chan struct{}) {
			for {
				select {
				case <-exitChan:
				case <-cdc:
				case <-time.After(15 * time.Minute):
					// I'm comfortable with time.After here since it's just
					// once per fifteen minutes or new conn.
					v := atomic.LoadInt32(a)
					if v != 0 {
						atomic.AddInt32(a, -v)
						continue
					}
				}
				break
			}
			c.Close()
		}(conn, activity, connDoneChan)
		for {
			select {
			case <-exitChan:
				break
			default:
			}
			res, err := stream.Recv()
			if err != nil {
				rs.logDebug("replValueStore: error with stream to ring service %q: %s", ringServer, err)
				break
			}
			atomic.AddInt32(activity, 1)
			if res != nil {
				if r, err := ring.LoadRing(bytes.NewBuffer(res.Ring)); err != nil {
					rs.logDebug("replValueStore: error with ring received from stream to ring service %q: %s", ringServer, err)
				} else {
					// This will cache the ring if ringCachePath is not empty.
					rs.SetRing(r)
					// Resets the exponential sleeper since we had success.
					sleeperTicks = 2
					rs.logDebug("replValueStore: got new ring from stream to ring service %q: %d", ringServer, res.Version)
				}
			}
		}
		close(connDoneChan)
		sleeper()
	}
}
예제 #5
-11
파일: main.go 프로젝트: wreese/valuestore
func ringOrBuilder(fileName string) (r ring.Ring, b *ring.Builder, err error) {
	var f *os.File
	if f, err = os.Open(fileName); err != nil {
		return
	}
	var gf *gzip.Reader
	if gf, err = gzip.NewReader(f); err != nil {
		return
	}
	header := make([]byte, 16)
	if _, err = io.ReadFull(gf, header); err != nil {
		return
	}
	if string(header[:5]) == "RINGv" {
		gf.Close()
		if _, err = f.Seek(0, 0); err != nil {
			return
		}
		r, err = ring.LoadRing(f)
	} else if string(header[:12]) == "RINGBUILDERv" {
		gf.Close()
		if _, err = f.Seek(0, 0); err != nil {
			return
		}
		b, err = ring.LoadBuilder(f)
	}
	return
}