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  }