Class: Ci::BuildTraceChunks::RedisBase

Inherits:
Object
  • Object
show all
Defined in:
app/models/ci/build_trace_chunks/redis_base.rb

Direct Known Subclasses

Redis, RedisTraceChunks

Constant Summary collapse

CHUNK_REDIS_TTL =
1.week
LUA_APPEND_CHUNK =
<<~EOS
  local key, new_data, offset = KEYS[1], ARGV[1], ARGV[2]
  local length = new_data:len()
  local expire = #{CHUNK_REDIS_TTL.seconds}
  local current_size = redis.call("strlen", key)
  offset = tonumber(offset)

  if offset == 0 then
    -- overwrite everything
    redis.call("set", key, new_data, "ex", expire)
    return redis.call("strlen", key)
  elseif offset > current_size then
    -- offset range violation
    return -1
  elseif offset + length >= current_size then
    -- efficiently append or overwrite and append
    redis.call("expire", key, expire)
    return redis.call("setrange", key, offset, new_data)
  else
    -- append and truncate
    local current_data = redis.call("get", key)
    new_data = current_data:sub(1, offset) .. new_data
    redis.call("set", key, new_data, "ex", expire)
    return redis.call("strlen", key)
  end
EOS

Instance Method Summary collapse

Instance Method Details

#append_data(model, new_data, offset) ⇒ Object


46
47
48
49
50
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 46

def append_data(model, new_data, offset)
  with_redis do |redis|
    redis.eval(LUA_APPEND_CHUNK, keys: [key(model)], argv: [new_data, offset])
  end
end

#data(model) ⇒ Object


34
35
36
37
38
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 34

def data(model)
  with_redis do |redis|
    redis.get(key(model))
  end
end

#delete_data(model) ⇒ Object


58
59
60
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 58

def delete_data(model)
  delete_keys([[model.build_id, model.chunk_index]])
end

#delete_keys(keys) ⇒ Object


66
67
68
69
70
71
72
73
74
75
76
77
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 66

def delete_keys(keys)
  return if keys.empty?

  keys = keys.map { |key| key_raw(*key) }

  with_redis do |redis|
    # https://gitlab.com/gitlab-org/gitlab/-/issues/224171
    Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
      redis.del(keys)
    end
  end
end

#keys(relation) ⇒ Object


62
63
64
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 62

def keys(relation)
  relation.pluck(:build_id, :chunk_index)
end

#set_data(model, new_data) ⇒ Object


40
41
42
43
44
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 40

def set_data(model, new_data)
  with_redis do |redis|
    redis.set(key(model), new_data, ex: CHUNK_REDIS_TTL)
  end
end

#size(model) ⇒ Object


52
53
54
55
56
# File 'app/models/ci/build_trace_chunks/redis_base.rb', line 52

def size(model)
  with_redis do |redis|
    redis.strlen(key(model))
  end
end