Class: Ci::BuildTraceChunks::Redis

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

Constant Summary collapse

CHUNK_REDIS_TTL =
1.week
LUA_APPEND_CHUNK =
<<~EOS.freeze
  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


50
51
52
53
54
# File 'app/models/ci/build_trace_chunks/redis.rb', line 50

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

#available?Boolean

Returns:

  • (Boolean)

34
35
36
# File 'app/models/ci/build_trace_chunks/redis.rb', line 34

def available?
  true
end

#data(model) ⇒ Object


38
39
40
41
42
# File 'app/models/ci/build_trace_chunks/redis.rb', line 38

def data(model)
  Gitlab::Redis::SharedState.with do |redis|
    redis.get(key(model))
  end
end

#delete_data(model) ⇒ Object


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

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

#delete_keys(keys) ⇒ Object


70
71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/ci/build_trace_chunks/redis.rb', line 70

def delete_keys(keys)
  return if keys.empty?

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

  Gitlab::Redis::SharedState.with 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


66
67
68
# File 'app/models/ci/build_trace_chunks/redis.rb', line 66

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

#set_data(model, new_data) ⇒ Object


44
45
46
47
48
# File 'app/models/ci/build_trace_chunks/redis.rb', line 44

def set_data(model, new_data)
  Gitlab::Redis::SharedState.with do |redis|
    redis.set(key(model), new_data, ex: CHUNK_REDIS_TTL)
  end
end

#size(model) ⇒ Object


56
57
58
59
60
# File 'app/models/ci/build_trace_chunks/redis.rb', line 56

def size(model)
  Gitlab::Redis::SharedState.with do |redis|
    redis.strlen(key(model))
  end
end