github.com/mailru/activerecord@v1.12.2/pkg/octopus/options.go (about) 1 package octopus 2 3 import ( 4 "fmt" 5 "hash/crc32" 6 "time" 7 8 "github.com/mailru/activerecord/pkg/activerecord" 9 "github.com/mailru/activerecord/pkg/iproto/iproto" 10 ) 11 12 // Константы определяющие дефолтное поведение конектора к octopus-у 13 const ( 14 DefaultTimeout = 20 * time.Millisecond 15 DefaultConnectionTimeout = 20 * time.Millisecond 16 DefaultRedialInterval = 50 * time.Millisecond 17 DefaultPingInterval = 1 * time.Second 18 DefaultPoolSize = 1 19 ) 20 21 // Используется для подсчета connectionID 22 var crc32table = crc32.MakeTable(0x4C11DB7) 23 24 // ServerModeType - тип используемый для описания режима работы инстанса. см. ниже 25 type ServerModeType uint8 26 27 // Режим работы конкретного инстанса. Мастер или реплика. 28 // При селекте из реплики быдет выставляться флаг readonly. Более подробно можно прочитать в доке. 29 const ( 30 ModeMaster ServerModeType = iota 31 ModeReplica 32 ) 33 34 // ConnectionOptions - опции используемые для подключения 35 type ConnectionOptions struct { 36 *activerecord.GroupHash 37 server string 38 Mode ServerModeType 39 poolCfg *iproto.PoolConfig 40 } 41 42 // NewOptions - cоздание структуры с опциями и дефолтными значениями. Для мидификации значений по умолчанию, 43 // надо передавать опции в конструктор 44 func NewOptions(server string, mode ServerModeType, opts ...ConnectionOption) (*ConnectionOptions, error) { 45 if server == "" { 46 return nil, fmt.Errorf("invalid param: server is empty") 47 } 48 49 octopusOpts := &ConnectionOptions{ 50 server: server, 51 Mode: mode, 52 poolCfg: &iproto.PoolConfig{ 53 Size: DefaultPoolSize, 54 ConnectTimeout: DefaultConnectionTimeout, 55 DialTimeout: DefaultConnectionTimeout, 56 RedialInterval: DefaultRedialInterval, 57 MaxRedialInterval: DefaultRedialInterval, 58 ChannelConfig: &iproto.ChannelConfig{ 59 WriteTimeout: DefaultTimeout, 60 RequestTimeout: DefaultTimeout, 61 PingInterval: DefaultPingInterval, 62 }, 63 }, 64 } 65 66 octopusOpts.GroupHash = activerecord.NewGroupHash(crc32.New(crc32table)) 67 68 for _, opt := range opts { 69 if err := opt.apply(octopusOpts); err != nil { 70 return nil, fmt.Errorf("error apply options: %w", err) 71 } 72 } 73 74 err := octopusOpts.UpdateHash("S", server) 75 if err != nil { 76 return nil, fmt.Errorf("can't get pool: %w", err) 77 } 78 79 return octopusOpts, nil 80 } 81 82 // UpdateHash - функция расчета ConnectionID, необходима для шаринга конектов между моделями. 83 func (o *ConnectionOptions) UpdateHash(data ...interface{}) error { 84 if err := o.GroupHash.UpdateHash(data...); err != nil { 85 return fmt.Errorf("can't calculate group hash: %w", err) 86 } 87 88 return nil 89 } 90 91 // GetConnectionID - получение ConnecitionID. После первого получения, больше нельзя его модифицировать. Можно только новый Options создать 92 func (o *ConnectionOptions) GetConnectionID() string { 93 return o.GroupHash.GetHash() 94 } 95 96 // InstanceMode - метод для получения режима аботы инстанса RO или RW 97 func (o *ConnectionOptions) InstanceMode() activerecord.ServerModeType { 98 return activerecord.ServerModeType(o.Mode) 99 } 100 101 // ConnectionOption - интерфейс которому должны соответствовать опции передаваемые в конструктор 102 type ConnectionOption interface { 103 apply(*ConnectionOptions) error 104 } 105 106 type optionConnectionFunc func(*ConnectionOptions) error 107 108 func (o optionConnectionFunc) apply(c *ConnectionOptions) error { 109 return o(c) 110 } 111 112 // WithTimeout - опция для изменений таймаутов 113 func WithTimeout(request, connection time.Duration) ConnectionOption { 114 return optionConnectionFunc(func(octopusCfg *ConnectionOptions) error { 115 octopusCfg.poolCfg.ConnectTimeout = connection 116 octopusCfg.poolCfg.DialTimeout = connection 117 octopusCfg.poolCfg.ChannelConfig.WriteTimeout = request 118 octopusCfg.poolCfg.ChannelConfig.RequestTimeout = request 119 120 return octopusCfg.UpdateHash("T", request, connection) 121 }) 122 } 123 124 // WithIntervals - опция для изменения интервалов 125 func WithIntervals(redial, maxRedial, ping time.Duration) ConnectionOption { 126 return optionConnectionFunc(func(octopusCfg *ConnectionOptions) error { 127 octopusCfg.poolCfg.RedialInterval = redial 128 octopusCfg.poolCfg.MaxRedialInterval = maxRedial 129 octopusCfg.poolCfg.ChannelConfig.PingInterval = ping 130 131 return octopusCfg.UpdateHash("I", redial, maxRedial, ping) 132 }) 133 } 134 135 // WithPoolSize - опция для изменения размера пулла подключений 136 func WithPoolSize(size int) ConnectionOption { 137 return optionConnectionFunc(func(octopusCfg *ConnectionOptions) error { 138 octopusCfg.poolCfg.Size = size 139 140 return octopusCfg.UpdateHash("s", size) 141 }) 142 } 143 144 // WithPoolLogger - опция для логера конекшен пула 145 func WithPoolLogger(logger iproto.Logger) ConnectionOption { 146 return optionConnectionFunc(func(octopusCfg *ConnectionOptions) error { 147 octopusCfg.poolCfg.Logger = logger 148 octopusCfg.poolCfg.ChannelConfig.Logger = logger 149 150 return octopusCfg.UpdateHash("L", logger) 151 }) 152 } 153 154 //go:generate mockery --name MockServerLogger --with-expecter=true --inpackage 155 type MockServerLogger interface { 156 Debug(fmt string, args ...any) 157 DebugSelectRequest(ns uint32, indexnum uint32, offset uint32, limit uint32, keys [][][]byte, fixtures ...SelectMockFixture) 158 DebugUpdateRequest(ns uint32, primaryKey [][]byte, updateOps []Ops, fixtures ...UpdateMockFixture) 159 DebugInsertRequest(ns uint32, needRetVal bool, insertMode InsertMode, tuple TupleData, fixtures ...InsertMockFixture) 160 DebugDeleteRequest(ns uint32, primaryKey [][]byte, fixtures ...DeleteMockFixture) 161 DebugCallRequest(procName string, args [][]byte, fixtures ...CallMockFixture) 162 } 163 164 type MockServerOption interface { 165 apply(*MockServer) error 166 } 167 168 type optionFunc func(*MockServer) error 169 170 func (o optionFunc) apply(c *MockServer) error { 171 return o(c) 172 } 173 174 // WithHost - опция для изменения сервера в конфиге 175 func WithHost(host, port string) MockServerOption { 176 return optionFunc(func(oms *MockServer) error { 177 oms.host = host 178 oms.port = port 179 return nil 180 }) 181 } 182 183 func WithLogger(logger MockServerLogger) MockServerOption { 184 return optionFunc(func(oms *MockServer) error { 185 oms.logger = logger 186 return nil 187 }) 188 } 189 190 func WithIprotoLogger(logger iproto.Logger) MockServerOption { 191 return optionFunc(func(oms *MockServer) error { 192 oms.iprotoLogger = logger 193 return nil 194 }) 195 }