// UnmarshalBson bson-decodes into KeyRangeQuery. func (keyRangeQuery *KeyRangeQuery) UnmarshalBson(buf *bytes.Buffer, kind byte) { switch kind { case bson.EOO, bson.Object: // valid case bson.Null: return default: panic(bson.NewBsonError("unexpected kind %v for KeyRangeQuery", kind)) } bson.Next(buf, 4) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { switch bson.ReadCString(buf) { case "Sql": keyRangeQuery.Sql = bson.DecodeString(buf, kind) case "BindVariables": // map[string]interface{} if kind != bson.Null { if kind != bson.Object { panic(bson.NewBsonError("unexpected kind %v for keyRangeQuery.BindVariables", kind)) } bson.Next(buf, 4) keyRangeQuery.BindVariables = make(map[string]interface{}) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { _k := bson.ReadCString(buf) var _v1 interface{} _v1 = bson.DecodeInterface(buf, kind) keyRangeQuery.BindVariables[_k] = _v1 } } case "Keyspace": keyRangeQuery.Keyspace = bson.DecodeString(buf, kind) case "KeyRanges": // []kproto.KeyRange if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for keyRangeQuery.KeyRanges", kind)) } bson.Next(buf, 4) keyRangeQuery.KeyRanges = make([]kproto.KeyRange, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v2 kproto.KeyRange _v2.UnmarshalBson(buf, kind) keyRangeQuery.KeyRanges = append(keyRangeQuery.KeyRanges, _v2) } } case "TabletType": keyRangeQuery.TabletType.UnmarshalBson(buf, kind) case "Session": // *Session if kind != bson.Null { keyRangeQuery.Session = new(Session) (*keyRangeQuery.Session).UnmarshalBson(buf, kind) } default: bson.Skip(buf, kind) } } }
// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(allShards []topo.SrvShard, kr key.KeyRange) ([]string, error) { shards := make([]string, 0, 1) if !kr.IsPartial() { for j := 0; j < len(allShards); j++ { shards = append(shards, allShards[j].ShardName()) } return shards, nil } for j := 0; j < len(allShards); j++ { shard := allShards[j] if key.KeyRangesIntersect(kr, shard.KeyRange) { shards = append(shards, shard.ShardName()) } } return shards, nil }
func buildBindVarCondition(bvc interface{}) (name string, onAbsent, onMismatch bool, op Operator, value interface{}, err error) { bvcinfo, ok := bvc.(map[string]interface{}) if !ok { err = NewTabletError(FAIL, "want json object for bind var conditions") return } var v interface{} v, ok = bvcinfo["Name"] if !ok { err = NewTabletError(FAIL, "Name missing in BindVarConds") return } name, ok = v.(string) if !ok { err = NewTabletError(FAIL, "want string for Name in BindVarConds") return } v, ok = bvcinfo["OnAbsent"] if !ok { err = NewTabletError(FAIL, "OnAbsent missing in BindVarConds") return } onAbsent, ok = v.(bool) if !ok { err = NewTabletError(FAIL, "want bool for OnAbsent") return } v, ok = bvcinfo["Operator"] if !ok { err = NewTabletError(FAIL, "Operator missing in BindVarConds") return } strop, ok := v.(string) if !ok { err = NewTabletError(FAIL, "want string for Operator") return } op, ok = opmap[strop] if !ok { err = NewTabletError(FAIL, "invalid Operator %s", strop) return } if op == QR_NOOP { return } v, ok = bvcinfo["Value"] if !ok { err = NewTabletError(FAIL, "Value missing in BindVarConds") return } if op >= QR_EQ && op <= QR_LE { strvalue, ok := v.(string) if !ok { err = NewTabletError(FAIL, "want string: %v", v) return } if strop[0] == 'U' { value, err = strconv.ParseUint(strvalue, 0, 64) if err != nil { err = NewTabletError(FAIL, "want uint64: %s", strvalue) return } } else if strop[0] == 'I' { value, err = strconv.ParseInt(strvalue, 0, 64) if err != nil { err = NewTabletError(FAIL, "want int64: %s", strvalue) return } } else if strop[0] == 'S' { value = strvalue } else { panic("unexpected") } } else if op == QR_MATCH || op == QR_NOMATCH { strvalue, ok := v.(string) if !ok { err = NewTabletError(FAIL, "want string: %v", v) return } value = strvalue } else if op == QR_IN || op == QR_NOTIN { kr, ok := v.(map[string]interface{}) if !ok { err = NewTabletError(FAIL, "want keyrange for Value") return } var keyrange key.KeyRange strstart, ok := kr["Start"] if !ok { err = NewTabletError(FAIL, "Start missing in KeyRange") return } start, ok := strstart.(string) if !ok { err = NewTabletError(FAIL, "want string for Start") return } keyrange.Start = key.KeyspaceId(start) strend, ok := kr["End"] if !ok { err = NewTabletError(FAIL, "End missing in KeyRange") return } end, ok := strend.(string) if !ok { err = NewTabletError(FAIL, "want string for End") return } keyrange.End = key.KeyspaceId(end) value = keyrange } v, ok = bvcinfo["OnMismatch"] if !ok { err = NewTabletError(FAIL, "OnMismatch missing in BindVarConds") return } onMismatch, ok = v.(bool) if !ok { err = NewTabletError(FAIL, "want bool for OnAbsent") return } return }
// KeyRangeFilterFunc returns a function that calls sendReply only if statements // in the transaction match the specified keyrange. The resulting function can be // passed into the BinlogStreamer: bls.Stream(file, pos, sendTransaction) -> // bls.Stream(file, pos, KeyRangeFilterFunc(sendTransaction)) func KeyRangeFilterFunc(kit key.KeyspaceIdType, keyrange key.KeyRange, sendReply sendTransactionFunc) sendTransactionFunc { isInteger := true if kit == key.KIT_BYTES { isInteger = false } return func(reply *proto.BinlogTransaction) error { matched := false filtered := make([]proto.Statement, 0, len(reply.Statements)) for _, statement := range reply.Statements { switch statement.Category { case proto.BL_SET: filtered = append(filtered, statement) case proto.BL_DDL: log.Warningf("Not forwarding DDL: %s", string(statement.Sql)) continue case proto.BL_DML: keyspaceIndex := bytes.LastIndex(statement.Sql, KEYSPACE_ID_COMMENT) if keyspaceIndex == -1 { updateStreamErrors.Add("KeyRangeStream", 1) log.Errorf("Error parsing keyspace id: %s", string(statement.Sql)) continue } idstart := keyspaceIndex + len(KEYSPACE_ID_COMMENT) idend := bytes.Index(statement.Sql[idstart:], SPACE) if idend == -1 { updateStreamErrors.Add("KeyRangeStream", 1) log.Errorf("Error parsing keyspace id: %s", string(statement.Sql)) continue } textId := string(statement.Sql[idstart : idstart+idend]) if isInteger { id, err := strconv.ParseUint(textId, 10, 64) if err != nil { updateStreamErrors.Add("KeyRangeStream", 1) log.Errorf("Error parsing keyspace id: %s", string(statement.Sql)) continue } if !keyrange.Contains(key.Uint64Key(id).KeyspaceId()) { continue } } else { data, err := base64.StdEncoding.DecodeString(textId) if err != nil { updateStreamErrors.Add("KeyRangeStream", 1) log.Errorf("Error parsing keyspace id: %s", string(statement.Sql)) continue } if !keyrange.Contains(key.KeyspaceId(data)) { continue } } filtered = append(filtered, statement) matched = true case proto.BL_UNRECOGNIZED: updateStreamErrors.Add("KeyRangeStream", 1) log.Errorf("Error parsing keyspace id: %s", string(statement.Sql)) continue } } if matched { reply.Statements = filtered } else { reply.Statements = nil } return sendReply(reply) } }