Пример #1
0
// Split will split the rows into subset for each distribution
func (rs *RowSplitter) Split(result [][][]sqltypes.Value, rows [][]sqltypes.Value) error {
	if rs.KeyspaceIdType == pb.KeyspaceIdType_UINT64 {
		for _, row := range rows {
			v := sqltypes.MakeNumeric(row[rs.ValueIndex].Raw())
			i, err := v.ParseUint64()
			if err != nil {
				return fmt.Errorf("Non numerical value: %v", err)
			}
			k := key.Uint64Key(i).Bytes()
			for i, kr := range rs.KeyRanges {
				if key.KeyRangeContains(kr, k) {
					result[i] = append(result[i], row)
					break
				}
			}
		}
	} else {
		for _, row := range rows {
			k := row[rs.ValueIndex].Raw()
			for i, kr := range rs.KeyRanges {
				if key.KeyRangeContains(kr, k) {
					result[i] = append(result[i], row)
					break
				}
			}
		}
	}
	return nil
}
Пример #2
0
func (krval *bvcKeyRange) eval(bv interface{}, op Operator, onMismatch bool) bool {
	switch op {
	case QRIn:
		switch num, status := getuint64(bv); status {
		case QROK:
			k := key.Uint64Key(num).Bytes()
			return key.KeyRangeContains((*topodatapb.KeyRange)(krval), k)
		case QROutOfRange:
			return false
		}
		// Not a number. Check string.
		switch str, status := getstring(bv); status {
		case QROK:
			return key.KeyRangeContains((*topodatapb.KeyRange)(krval), []byte(str))
		}
	case QRNotIn:
		switch num, status := getuint64(bv); status {
		case QROK:
			k := key.Uint64Key(num).Bytes()
			return !key.KeyRangeContains((*topodatapb.KeyRange)(krval), k)
		case QROutOfRange:
			return true
		}
		// Not a number. Check string.
		switch str, status := getstring(bv); status {
		case QROK:
			return !key.KeyRangeContains((*topodatapb.KeyRange)(krval), []byte(str))
		}
	default:
		panic("unexpected:")
	}
	return onMismatch
}
Пример #3
0
// Split will split the rows into subset for each distribution
func (rs *RowSplitter) Split(result [][][]sqltypes.Value, rows [][]sqltypes.Value) error {
	for _, row := range rows {
		k, err := rs.KeyResolver.keyspaceID(row)
		if err != nil {
			return err
		}
		for i, kr := range rs.KeyRanges {
			if key.KeyRangeContains(kr, k) {
				result[i] = append(result[i], row)
				break
			}
		}
	}
	return nil
}
Пример #4
0
func getShardForKeyspaceID(allShards []*pb.ShardReference, keyspaceID []byte) (string, error) {
	if len(allShards) == 0 {
		return "", vterrors.FromError(vtrpc.ErrorCode_BAD_INPUT,
			fmt.Errorf("No shards found for this tabletType"),
		)
	}

	for _, shardReference := range allShards {
		if key.KeyRangeContains(shardReference.KeyRange, keyspaceID) {
			return shardReference.Name, nil
		}
	}
	return "", vterrors.FromError(vtrpc.ErrorCode_BAD_INPUT,
		fmt.Errorf("KeyspaceId %v didn't match any shards %+v", hex.EncodeToString(keyspaceID), allShards),
	)
}
Пример #5
0
// Route returns which shard (specified by the index of the list of shards
// passed in NewRowRouter) contains the given row.
func (rr *RowRouter) Route(row []sqltypes.Value) (int, error) {
	if len(rr.keyRanges) == 1 {
		// Fast path when there is only one destination shard.
		return 0, nil
	}

	k, err := rr.keyResolver.keyspaceID(row)
	if err != nil {
		return -1, err
	}
	for i, kr := range rr.keyRanges {
		if key.KeyRangeContains(kr, k) {
			return i, nil
		}
	}
	return -1, fmt.Errorf("no shard's key range includes the keyspace id: %v for the row: %#v", k, row)
}
Пример #6
0
// 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(keyrange, sendTransaction))
// TODO(erez): Remove 'KeyspaceIdType' from here: it's no longer used.
func KeyRangeFilterFunc(unused key.KeyspaceIdType, keyrange *pb.KeyRange, sendReply sendTransactionFunc) sendTransactionFunc {
	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", statement.Sql)
				continue
			case proto.BL_DML:
				keyspaceID, err := sqlannotation.ExtractKeySpaceID(string(statement.Sql))
				if err != nil {
					if handleExtractKeySpaceIDError(err) {
						continue
					} else {
						// TODO(erez): Stop filtered-replication here, and alert.
						// Currently we skip.
						continue
					}
				}
				if !key.KeyRangeContains(keyrange, keyspaceID) {
					// Skip keyspace ids that don't belong to the destination shard.
					continue
				}
				filtered = append(filtered, statement)
				matched = true
			case proto.BL_UNRECOGNIZED:
				updateStreamErrors.Add("KeyRangeStream", 1)
				log.Errorf("Error parsing keyspace id: %s", statement.Sql)
				continue
			}
		}
		if matched {
			reply.Statements = filtered
		} else {
			reply.Statements = nil
		}
		return sendReply(reply)
	}
}
Пример #7
0
// Recv is part of sqltypes.ResultStream interface.
func (f *v3KeyRangeFilter) Recv() (*sqltypes.Result, error) {
	r, err := f.input.Recv()
	if err != nil {
		return nil, err
	}

	rows := make([][]sqltypes.Value, 0, len(r.Rows))
	for _, row := range r.Rows {
		ksid, err := f.resolver.keyspaceID(row)
		if err != nil {
			return nil, err
		}

		if key.KeyRangeContains(f.keyRange, ksid) {
			rows = append(rows, row)
		}
	}
	r.Rows = rows
	return r, nil
}
Пример #8
0
// 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 *pb.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 !key.KeyRangeContains(keyrange, key.Uint64Key(id).Bytes()) {
						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 !key.KeyRangeContains(keyrange, 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)
	}
}