github.com/mailru/activerecord@v1.12.2/pkg/tarantool/box.go (about)

     1  package tarantool
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/mailru/activerecord/pkg/activerecord"
     8  )
     9  
    10  var DefaultOptionCreator = func(sic activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error) {
    11  	return NewOptions(sic.Addr, sic.Mode, WithTimeout(sic.Timeout), WithCredential(sic.User, sic.Password))
    12  }
    13  
    14  func Box(ctx context.Context, shard int, instType activerecord.ShardInstanceType, configPath string, optionCreator func(activerecord.ShardInstanceConfig) (activerecord.OptionInterface, error)) (*Connection, error) {
    15  	if optionCreator == nil {
    16  		optionCreator = DefaultOptionCreator
    17  	}
    18  
    19  	clusterInfo, err := activerecord.ConfigCacher().Get(
    20  		ctx,
    21  		configPath,
    22  		DefaultConnectionParams,
    23  		optionCreator,
    24  	)
    25  	if err != nil {
    26  		return nil, fmt.Errorf("can't get cluster %s info: %w", configPath, err)
    27  	}
    28  
    29  	if clusterInfo.Shards() < shard {
    30  		return nil, fmt.Errorf("invalid shard num %d, max = %d", shard, clusterInfo.Shards())
    31  	}
    32  
    33  	var (
    34  		configBox activerecord.ShardInstance
    35  		ok        bool
    36  	)
    37  
    38  	switch instType {
    39  	case activerecord.ReplicaInstanceType:
    40  		configBox, ok = clusterInfo.NextReplica(shard)
    41  		if !ok {
    42  			return nil, fmt.Errorf("replicas not set")
    43  		}
    44  	case activerecord.ReplicaOrMasterInstanceType:
    45  		configBox, ok = clusterInfo.NextReplica(shard)
    46  		if ok {
    47  			break
    48  		}
    49  
    50  		fallthrough
    51  	case activerecord.MasterInstanceType:
    52  		configBox = clusterInfo.NextMaster(shard)
    53  	}
    54  
    55  	conn, err := activerecord.ConnectionCacher().GetOrAdd(configBox, func(options interface{}) (activerecord.ConnectionInterface, error) {
    56  		octopusOpt, ok := options.(*ConnectionOptions)
    57  		if !ok {
    58  			return nil, fmt.Errorf("invalit type of options %T, want Options", options)
    59  		}
    60  
    61  		return GetConnection(ctx, octopusOpt)
    62  	})
    63  	if err != nil {
    64  		return nil, fmt.Errorf("error from connectionCacher: %w", err)
    65  	}
    66  
    67  	box, ex := conn.(*Connection)
    68  	if !ex {
    69  		return nil, fmt.Errorf("invalid connection type %T, want *tarantool.Connection", conn)
    70  	}
    71  
    72  	return box, nil
    73  }
    74  
    75  func CheckShardInstance(ctx context.Context, instance activerecord.ShardInstance) (activerecord.OptionInterface, error) {
    76  	opts, ok := instance.Options.(*ConnectionOptions)
    77  	if !ok {
    78  		return nil, fmt.Errorf("invalit type of options %T, want Options", instance.Options)
    79  	}
    80  
    81  	var err error
    82  	c := activerecord.ConnectionCacher().Get(instance)
    83  	if c == nil {
    84  		c, err = GetConnection(ctx, opts)
    85  		if err != nil {
    86  			return nil, fmt.Errorf("error from connectionCacher: %w", err)
    87  		}
    88  	}
    89  
    90  	conn, ok := c.(*Connection)
    91  	if !ok {
    92  		return nil, fmt.Errorf("invalid connection type %T, want *tarantool.Connection", conn)
    93  	}
    94  
    95  	var res []bool
    96  
    97  	if err = conn.Call17Typed("dostring", []interface{}{"return box.info.ro"}, &res); err != nil {
    98  		return nil, fmt.Errorf("can't get instance status: %w", err)
    99  	}
   100  
   101  	if len(res) == 1 {
   102  		ret := res[0]
   103  		switch ret {
   104  		case false:
   105  			return NewOptions(opts.server, activerecord.ModeMaster)
   106  		default:
   107  			return NewOptions(opts.server, activerecord.ModeReplica)
   108  		}
   109  	}
   110  
   111  	return nil, fmt.Errorf("can't parse instance status: %w", err)
   112  }