예제 #1
0
func (s *sandbox) DeleteTestConn(shard string, conn tabletconn.TabletConn) {
	s.sandmu.Lock()
	defer s.sandmu.Unlock()
	conns, ok := s.TestConns[shard]
	if !ok {
		panic(fmt.Sprintf("unknown shard: %v", shard))
	}
	delete(conns, conn.EndPoint().Uid)
	s.TestConns[shard] = conns
}
예제 #2
0
// WrapError adds the connection context to an error.
func (sdc *ShardConn) WrapError(in error, conn tabletconn.TabletConn) (wrapped error) {
	if in == nil {
		return nil
	}
	var endPoint topo.EndPoint
	if conn != nil {
		endPoint = conn.EndPoint()
	}
	return fmt.Errorf(
		"%v, shard: (%s.%s.%s), host: %s",
		in, sdc.keyspace, sdc.shard, sdc.tabletType, endPoint.Host)
}
예제 #3
0
// markDown closes conn and temporarily marks the associated
// end point as unusable.
func (sdc *ShardConn) markDown(conn tabletconn.TabletConn) {
	sdc.mu.Lock()
	defer sdc.mu.Unlock()
	if conn != sdc.conn {
		return
	}
	sdc.balancer.MarkDown(conn.EndPoint().Uid)

	// Launch as goroutine so we don't block
	go sdc.conn.Close()
	sdc.conn = nil
}
예제 #4
0
// markDown closes conn and temporarily marks the associated
// end point as unusable.
func (sdc *ShardConn) markDown(conn tabletconn.TabletConn, reason string) {
	sdc.mu.Lock()
	defer sdc.mu.Unlock()
	if conn != sdc.conn {
		return
	}
	sdc.balancer.MarkDown(conn.EndPoint().Uid, reason)

	go func(conn tabletconn.TabletConn) {
		danglingTabletConn.Add(1)
		conn.Close()
		danglingTabletConn.Add(-1)
	}(sdc.conn)
	sdc.conn = nil
}
예제 #5
0
// StreamExecute executes a streaming query on vttablet. The retry rules are the same as Execute.
func (sdc *ShardConn) StreamExecute(ctx context.Context, query string, bindVars map[string]interface{}, transactionID int64) (<-chan *mproto.QueryResult, tabletconn.ErrFunc) {
	var usedConn tabletconn.TabletConn
	var erFunc tabletconn.ErrFunc
	var results <-chan *mproto.QueryResult
	err := sdc.withRetry(ctx, func(conn tabletconn.TabletConn) error {
		results, erFunc = conn.StreamExecute(ctx, query, bindVars, transactionID)
		usedConn = conn
		return erFunc()
	}, transactionID, true)
	if err != nil {
		return results, func() error { return err }
	}
	inTransaction := (transactionID != 0)
	return results, func() error { return sdc.WrapError(erFunc(), usedConn.EndPoint(), inTransaction) }
}
예제 #6
0
// StreamExecute executes a streaming query for the specified keyspace, shard, and tablet type.
func (dg *discoveryGateway) StreamExecute(ctx context.Context, keyspace, shard string, tabletType pbt.TabletType, query string, bindVars map[string]interface{}, transactionID int64) (<-chan *mproto.QueryResult, tabletconn.ErrFunc) {
	var usedConn tabletconn.TabletConn
	var erFunc tabletconn.ErrFunc
	var results <-chan *mproto.QueryResult
	err := dg.withRetry(ctx, keyspace, shard, tabletType, func(conn tabletconn.TabletConn) error {
		var err error
		results, erFunc, err = conn.StreamExecute2(ctx, query, bindVars, transactionID)
		usedConn = conn
		return err
	}, transactionID, true)
	if err != nil {
		return results, func() error { return err }
	}
	inTransaction := (transactionID != 0)
	return results, func() error {
		return WrapError(erFunc(), keyspace, shard, tabletType, usedConn.EndPoint(), inTransaction)
	}
}
예제 #7
0
// WrapError returns ShardConnError which preserves the original error code if possible,
// adds the connection context
// and adds a bit to determine whether the keyspace/shard needs to be
// re-resolved for a potential sharding event.
func (sdc *ShardConn) WrapError(in error, conn tabletconn.TabletConn, inTransaction bool) (wrapped error) {
	if in == nil {
		return nil
	}
	shardIdentifier := fmt.Sprintf("%s.%s.%s", sdc.keyspace, sdc.shard, sdc.tabletType)
	if conn != nil {
		shardIdentifier += fmt.Sprintf(", %+v", conn.EndPoint())
	}

	code := tabletconn.ERR_NORMAL
	serverError, ok := in.(*tabletconn.ServerError)
	if ok {
		code = serverError.Code
	}

	shardConnErr := &ShardConnError{
		Code:            code,
		ShardIdentifier: shardIdentifier,
		InTransaction:   inTransaction,
		Err:             in.Error(),
	}
	return shardConnErr
}