github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/datastore/mysql/options.go (about) 1 package mysql 2 3 import ( 4 "fmt" 5 "time" 6 ) 7 8 const ( 9 errQuantizationTooLarge = "revision quantization interval (%s) must be less than GC window (%s)" 10 11 defaultGarbageCollectionWindow = 24 * time.Hour 12 defaultGarbageCollectionInterval = time.Minute * 3 13 defaultGarbageCollectionMaxOperationTime = time.Minute 14 defaultMaxOpenConns = 20 15 defaultConnMaxIdleTime = 30 * time.Minute 16 defaultConnMaxLifetime = 30 * time.Minute 17 defaultWatchBufferLength = 128 18 defaultWatchBufferWriteTimeout = 1 * time.Second 19 defaultQuantization = 5 * time.Second 20 defaultMaxRevisionStalenessPercent = 0.1 21 defaultEnablePrometheusStats = false 22 defaultMaxRetries = 8 23 defaultGCEnabled = true 24 defaultCredentialsProviderName = "" 25 ) 26 27 type mysqlOptions struct { 28 revisionQuantization time.Duration 29 gcWindow time.Duration 30 gcInterval time.Duration 31 gcMaxOperationTime time.Duration 32 maxRevisionStalenessPercent float64 33 watchBufferLength uint16 34 watchBufferWriteTimeout time.Duration 35 tablePrefix string 36 enablePrometheusStats bool 37 maxOpenConns int 38 connMaxIdleTime time.Duration 39 connMaxLifetime time.Duration 40 analyzeBeforeStats bool 41 maxRetries uint8 42 lockWaitTimeoutSeconds *uint8 43 gcEnabled bool 44 credentialsProviderName string 45 } 46 47 // Option provides the facility to configure how clients within the 48 // MySQL datastore interact with the running MySQL database. 49 type Option func(*mysqlOptions) 50 51 func generateConfig(options []Option) (mysqlOptions, error) { 52 computed := mysqlOptions{ 53 gcWindow: defaultGarbageCollectionWindow, 54 gcInterval: defaultGarbageCollectionInterval, 55 gcMaxOperationTime: defaultGarbageCollectionMaxOperationTime, 56 watchBufferLength: defaultWatchBufferLength, 57 watchBufferWriteTimeout: defaultWatchBufferWriteTimeout, 58 maxOpenConns: defaultMaxOpenConns, 59 connMaxIdleTime: defaultConnMaxIdleTime, 60 connMaxLifetime: defaultConnMaxLifetime, 61 revisionQuantization: defaultQuantization, 62 maxRevisionStalenessPercent: defaultMaxRevisionStalenessPercent, 63 enablePrometheusStats: defaultEnablePrometheusStats, 64 maxRetries: defaultMaxRetries, 65 gcEnabled: defaultGCEnabled, 66 credentialsProviderName: defaultCredentialsProviderName, 67 } 68 69 for _, option := range options { 70 option(&computed) 71 } 72 73 // Run any checks on the config that need to be done 74 if computed.revisionQuantization >= computed.gcWindow { 75 return computed, fmt.Errorf( 76 errQuantizationTooLarge, 77 computed.revisionQuantization, 78 computed.gcWindow, 79 ) 80 } 81 82 return computed, nil 83 } 84 85 // WatchBufferLength is the number of entries that can be stored in the watch 86 // buffer while awaiting read by the client. 87 // 88 // This value defaults to 128. 89 func WatchBufferLength(watchBufferLength uint16) Option { 90 return func(mo *mysqlOptions) { 91 mo.watchBufferLength = watchBufferLength 92 } 93 } 94 95 // WatchBufferWriteTimeout is the maximum timeout for writing to the watch buffer, 96 // after which the caller to the watch will be disconnected. 97 func WatchBufferWriteTimeout(watchBufferWriteTimeout time.Duration) Option { 98 return func(mo *mysqlOptions) { mo.watchBufferWriteTimeout = watchBufferWriteTimeout } 99 } 100 101 // RevisionQuantization is the time bucket size to which advertised 102 // revisions will be rounded. 103 // 104 // This value defaults to 5 seconds. 105 func RevisionQuantization(quantization time.Duration) Option { 106 return func(mo *mysqlOptions) { 107 mo.revisionQuantization = quantization 108 } 109 } 110 111 // MaxRevisionStalenessPercent is the amount of time, expressed as a percentage of 112 // the revision quantization window, that a previously computed rounded revision 113 // can still be advertised after the next rounded revision would otherwise be ready. 114 // 115 // This value defaults to 0.1 (10%). 116 func MaxRevisionStalenessPercent(stalenessPercent float64) Option { 117 return func(mo *mysqlOptions) { 118 mo.maxRevisionStalenessPercent = stalenessPercent 119 } 120 } 121 122 // GCWindow is the maximum age of a passed revision that will be considered 123 // valid. 124 // 125 // This value defaults to 24 hours. 126 func GCWindow(window time.Duration) Option { 127 return func(mo *mysqlOptions) { 128 mo.gcWindow = window 129 } 130 } 131 132 // GCInterval is the interval at which garbage collection will occur. 133 // 134 // This value defaults to 3 minutes. 135 func GCInterval(interval time.Duration) Option { 136 return func(mo *mysqlOptions) { 137 mo.gcInterval = interval 138 } 139 } 140 141 // MaxRetries is the maximum number of times a retriable transaction will be 142 // client-side retried. 143 // 144 // Default: 10 145 func MaxRetries(maxRetries uint8) Option { 146 return func(mo *mysqlOptions) { 147 mo.maxRetries = maxRetries 148 } 149 } 150 151 // TablePrefix allows defining a MySQL table name prefix. 152 // 153 // No prefix is set by default 154 func TablePrefix(prefix string) Option { 155 return func(mo *mysqlOptions) { 156 mo.tablePrefix = prefix 157 } 158 } 159 160 // WithEnablePrometheusStats marks whether Prometheus metrics provided by Go's database/sql package 161 // are enabled. 162 // 163 // Prometheus metrics are disabled by default. 164 func WithEnablePrometheusStats(enablePrometheusStats bool) Option { 165 return func(mo *mysqlOptions) { 166 mo.enablePrometheusStats = enablePrometheusStats 167 } 168 } 169 170 // ConnMaxIdleTime is the duration after which an idle connection will be 171 // automatically closed. 172 // See https://pkg.go.dev/database/sql#DB.SetConnMaxIdleTime/ 173 // 174 // This value defaults to having no maximum. 175 func ConnMaxIdleTime(idle time.Duration) Option { 176 return func(mo *mysqlOptions) { 177 mo.connMaxIdleTime = idle 178 } 179 } 180 181 // ConnMaxLifetime is the duration since creation after which a connection will 182 // be automatically closed. 183 // See https://pkg.go.dev/database/sql#DB.SetConnMaxLifetime 184 // 185 // This value defaults to having no maximum. 186 func ConnMaxLifetime(lifetime time.Duration) Option { 187 return func(mo *mysqlOptions) { 188 mo.connMaxLifetime = lifetime 189 } 190 } 191 192 // MaxOpenConns is the maximum size of the connection pool. 193 // See https://pkg.go.dev/database/sql#DB.SetMaxOpenConns 194 // 195 // This value defaults to having no maximum. 196 func MaxOpenConns(conns int) Option { 197 return func(mo *mysqlOptions) { 198 mo.maxOpenConns = conns 199 } 200 } 201 202 // DebugAnalyzeBeforeStatistics signals to the Statistics method that it should 203 // run Analyze Table on the relationships table before returning statistics. 204 // This should only be used for debug and testing. 205 // 206 // Disabled by default. 207 func DebugAnalyzeBeforeStatistics() Option { 208 return func(mo *mysqlOptions) { 209 mo.analyzeBeforeStats = true 210 } 211 } 212 213 // OverrideLockWaitTimeout sets the lock wait timeout on each new connection established 214 // with the databases. As an OLTP service, the default of 50s is unbearably long to block 215 // a write for our service, so we suggest setting this value to the minimum of 1 second. 216 // 217 // Uses server default by default. 218 func OverrideLockWaitTimeout(seconds uint8) Option { 219 return func(mo *mysqlOptions) { 220 mo.lockWaitTimeoutSeconds = &seconds 221 } 222 } 223 224 // GCEnabled indicates whether garbage collection is enabled. 225 // 226 // GC is enabled by default. 227 func GCEnabled(isGCEnabled bool) Option { 228 return func(mo *mysqlOptions) { 229 mo.gcEnabled = isGCEnabled 230 } 231 } 232 233 // GCMaxOperationTime is the maximum operation time of a garbage collection 234 // pass before it times out. 235 // 236 // This value defaults to 1 minute. 237 func GCMaxOperationTime(time time.Duration) Option { 238 return func(mo *mysqlOptions) { 239 mo.gcMaxOperationTime = time 240 } 241 } 242 243 // CredentialsProviderName is the name of the CredentialsProvider implementation to use 244 // for dynamically retrieving the datastore credentials at runtime 245 // 246 // Empty by default. 247 func CredentialsProviderName(credentialsProviderName string) Option { 248 return func(mo *mysqlOptions) { mo.credentialsProviderName = credentialsProviderName } 249 }