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 }