| 241 | } |
| 242 | |
| 243 | func updateUserCacheFieldAtVersion(userId int, field string, value interface{}, authVersion int64) error { |
| 244 | if !common.RedisEnabled { |
| 245 | return nil |
| 246 | } |
| 247 | if userId <= 0 || authVersion <= 0 { |
| 248 | return fmt.Errorf("invalid user auth version") |
| 249 | } |
| 250 | const script = ` |
| 251 | local incoming = tonumber(ARGV[1]) |
| 252 | local pending = tonumber(redis.call('GET', KEYS[2]) or '0') |
| 253 | local committed = tonumber(redis.call('GET', KEYS[3]) or '0') |
| 254 | local current = tonumber(redis.call('HGET', KEYS[1], 'AuthVersion') or '0') |
| 255 | if pending > incoming or committed > incoming or current > incoming then |
| 256 | return 0 |
| 257 | end |
| 258 | if committed < incoming then |
| 259 | redis.call('SET', KEYS[3], ARGV[1]) |
| 260 | end |
| 261 | if pending > 0 and pending <= incoming then |
| 262 | redis.call('DEL', KEYS[2]) |
| 263 | end |
| 264 | if redis.call('EXISTS', KEYS[1]) == 0 then |
| 265 | return 1 |
| 266 | end |
| 267 | if current ~= incoming then |
| 268 | return 1 |
| 269 | end |
| 270 | redis.call('HSET', KEYS[1], ARGV[2], ARGV[3], 'CacheSchema', ARGV[4]) |
| 271 | return 1` |
| 272 | result, err := common.RDB.Eval(context.Background(), script, |
| 273 | []string{getUserCacheKey(userId), getUserAuthFenceKey(userId), getUserAuthVersionKey(userId)}, |
| 274 | authVersion, field, value, userCacheSchemaVersion, |
| 275 | ).Int() |
| 276 | if err != nil { |
| 277 | return err |
| 278 | } |
| 279 | if result == 0 { |
| 280 | return ErrUserAuthCachePending |
| 281 | } |
| 282 | return nil |
| 283 | } |