func updateCurrentTsFromResponse(bucket string, currentTs *protobuf.TsVbuuid, res *protobuf.TimestampResponse) *protobuf.TsVbuuid { currentTsList := res.GetCurrentTimestamps() for _, ts := range currentTsList { if ts != nil && !ts.IsEmpty() && ts.GetBucket() == bucket { if currentTs == nil { currentTs = ts.Clone() } else { currentTs = currentTs.Union(ts) } } } return currentTs }
func updateActiveTsFromResponse(bucket string, activeTs *protobuf.TsVbuuid, res *protobuf.TopicResponse) *protobuf.TsVbuuid { activeTsList := res.GetActiveTimestamps() for _, ts := range activeTsList { if ts != nil && !ts.IsEmpty() && ts.GetBucket() == bucket { if activeTs == nil { activeTs = ts.Clone() } else { activeTs = activeTs.Union(ts) } } } return activeTs }
func updateRollbackTsFromResponse(bucket string, rollbackTs *protobuf.TsVbuuid, res *protobuf.TopicResponse) *protobuf.TsVbuuid { rollbackTsList := res.GetRollbackTimestamps() for _, ts := range rollbackTsList { if ts != nil && !ts.IsEmpty() && ts.GetBucket() == bucket { if rollbackTs == nil { rollbackTs = ts.Clone() } else { rollbackTs = rollbackTs.Union(ts) } } } return rollbackTs }
// go-routine handles data path. func (kvdata *KVData) runScatter( ts *protobuf.TsVbuuid, mutch <-chan *mc.DcpEvent) { // NOTE: panic will bubble up from vbucket-routine to kvdata. defer func() { if r := recover(); r != nil { fmsg := "%v ##%x runScatter() crashed: %v\n" logging.Errorf(fmsg, kvdata.logPrefix, kvdata.opaque, r) logging.Errorf("%s", logging.StackTrace()) } kvdata.publishStreamEnd() kvdata.feed.PostFinKVdata(kvdata.bucket) close(kvdata.finch) logging.Infof("%v ##%x ... stopped\n", kvdata.logPrefix, kvdata.opaque) }() // stats eventCount, addCount, delCount := int64(0), int64(0), int64(0) tsCount := int64(0) heartBeat := time.After(kvdata.syncTimeout) fmsg := "%v ##%x heartbeat (%v) loaded ...\n" logging.Infof(fmsg, kvdata.logPrefix, kvdata.opaque, kvdata.syncTimeout) loop: for { select { case m, ok := <-mutch: if ok == false { // upstream has closed break loop } kvdata.scatterMutation(m, ts) eventCount++ case <-heartBeat: vrs := make([]*VbucketRoutine, 0, len(kvdata.vrs)) for _, vr := range kvdata.vrs { vrs = append(vrs, vr) } heartBeat = nil // propogate the sync-pulse via separate routine so that // the data-path is not blocked. go func() { // during cleanup, as long as the vbucket-routines are // shutdown this routine will eventually exit. for _, vr := range vrs { vr.SyncPulse() } if err := kvdata.ReloadHeartbeat(); err != nil { fmsg := "%v ##%x ReloadHeartbeat(): %v\n" logging.Errorf(fmsg, kvdata.logPrefix, kvdata.opaque, err) } }() case msg := <-kvdata.sbch: cmd := msg[0].(byte) switch cmd { case kvCmdAddEngines: opaque := msg[1].(uint16) respch := msg[4].(chan []interface{}) if msg[2] != nil { for uuid, engine := range msg[2].(map[uint64]*Engine) { if _, ok := kvdata.engines[uuid]; !ok { fmsg := "%v ##%x new engine added %v" logging.Infof(fmsg, kvdata.logPrefix, opaque, uuid) } kvdata.engines[uuid] = engine } } if msg[3] != nil { rv := msg[3].(map[string]c.RouterEndpoint) for raddr, endp := range rv { fmsg := "%v ##%x updated endpoint %q" logging.Infof(fmsg, kvdata.logPrefix, opaque, raddr) kvdata.endpoints[raddr] = endp } } curSeqnos := make(map[uint16]uint64) if kvdata.engines != nil || kvdata.endpoints != nil { engines, endpoints := kvdata.engines, kvdata.endpoints for _, vr := range kvdata.vrs { curSeqno, err := vr.AddEngines(opaque, engines, endpoints) if err != nil { panic(err) } curSeqnos[vr.vbno] = curSeqno } } addCount++ respch <- []interface{}{curSeqnos, nil} case kvCmdDelEngines: opaque := msg[1].(uint16) engineKeys := msg[2].([]uint64) respch := msg[3].(chan []interface{}) for _, vr := range kvdata.vrs { if err := vr.DeleteEngines(opaque, engineKeys); err != nil { panic(err) } } for _, engineKey := range engineKeys { delete(kvdata.engines, engineKey) fmsg := "%v ##%x deleted engine %q" logging.Infof(fmsg, kvdata.logPrefix, opaque, engineKey) } delCount++ respch <- []interface{}{nil} case kvCmdTs: _ /*opaque*/ = msg[1].(uint16) ts = ts.Union(msg[2].(*protobuf.TsVbuuid)) respch := msg[3].(chan []interface{}) tsCount++ respch <- []interface{}{nil} case kvCmdGetStats: respch := msg[1].(chan []interface{}) stats := kvdata.newStats() stats.Set("events", float64(eventCount)) stats.Set("addInsts", float64(addCount)) stats.Set("delInsts", float64(delCount)) stats.Set("tsCount", float64(tsCount)) statVbuckets := make(map[string]interface{}) for i, vr := range kvdata.vrs { stats, err := vr.GetStatistics() if err != nil { panic(err) } statVbuckets[strconv.Itoa(int(i))] = stats } stats.Set("vbuckets", statVbuckets) respch <- []interface{}{map[string]interface{}(stats)} case kvCmdResetConfig: config, respch := msg[1].(c.Config), msg[2].(chan []interface{}) if cv, ok := config["syncTimeout"]; ok && heartBeat != nil { kvdata.syncTimeout = time.Duration(cv.Int()) kvdata.syncTimeout *= time.Millisecond logging.Infof( "%v ##%x heart-beat settings reloaded: %v\n", kvdata.logPrefix, kvdata.opaque, kvdata.syncTimeout) heartBeat = time.After(kvdata.syncTimeout) } for _, vr := range kvdata.vrs { if err := vr.ResetConfig(config); err != nil { panic(err) } } kvdata.config = kvdata.config.Override(config) respch <- []interface{}{nil} case kvCmdReloadHeartBeat: respch := msg[1].(chan []interface{}) heartBeat = time.After(kvdata.syncTimeout) respch <- []interface{}{nil} case kvCmdClose: for _, vr := range kvdata.vrs { vr.Close() } respch := msg[1].(chan []interface{}) respch <- []interface{}{nil} break loop } } } }