Class: Ci::BuildTraceChunk

Inherits:
ApplicationRecord show all
Extended by:
Gitlab::Ci::Model
Includes:
Checksummable, FastDestroyAll, Gitlab::ExclusiveLeaseHelpers
Defined in:
app/models/ci/build_trace_chunk.rb

Constant Summary collapse

CHUNK_SIZE =
128.kilobytes
WRITE_LOCK_RETRY =
10
WRITE_LOCK_SLEEP =
0.01.seconds
WRITE_LOCK_TTL =
1.minute
FailedToPersistDataError =
Class.new(StandardError)

Constants included from Gitlab::ExclusiveLeaseHelpers

Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError

Constants included from FastDestroyAll

FastDestroyAll::ForbiddenActionError

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Ci::Model

model_name, table_name_prefix

Methods included from Gitlab::ExclusiveLeaseHelpers

#in_lock

Methods included from Checksummable

#crc32

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Class Method Details

.all_storesObject


30
31
32
# File 'app/models/ci/build_trace_chunk.rb', line 30

def all_stores
  @all_stores ||= self.data_stores.keys
end

.begin_fast_destroyObject

FastDestroyAll concerns


46
47
48
49
50
51
52
53
# File 'app/models/ci/build_trace_chunk.rb', line 46

def begin_fast_destroy
  all_stores.each_with_object({}) do |store, result|
    relation = public_send(store) # rubocop:disable GitlabSecurity/PublicSend
    keys = get_store_class(store).keys(relation)

    result[store] = keys if keys.present?
  end
end

.finalize_fast_destroy(keys) ⇒ Object

FastDestroyAll concerns


57
58
59
60
61
# File 'app/models/ci/build_trace_chunk.rb', line 57

def finalize_fast_destroy(keys)
  keys.each do |store, value|
    get_store_class(store).delete_keys(value)
  end
end

.get_store_class(store) ⇒ Object


39
40
41
42
# File 'app/models/ci/build_trace_chunk.rb', line 39

def get_store_class(store)
  @stores ||= {}
  @stores[store] ||= "Ci::BuildTraceChunks::#{store.capitalize}".constantize.new
end

.persistable_storeObject


34
35
36
37
# File 'app/models/ci/build_trace_chunk.rb', line 34

def persistable_store
  # get first available store from the back of the list
  all_stores.reverse.find { |store| get_store_class(store).available? }
end

Instance Method Details

#append(new_data, offset) ⇒ Object

Raises:

  • (ArgumentError)

75
76
77
78
79
80
81
82
83
# File 'app/models/ci/build_trace_chunk.rb', line 75

def append(new_data, offset)
  raise ArgumentError, 'New data is missing' unless new_data
  raise ArgumentError, 'Offset is out of range' if offset < 0 || offset > size
  raise ArgumentError, 'Chunk size overflow' if CHUNK_SIZE < (offset + new_data.bytesize)

  in_lock(*lock_params) { unsafe_append_data!(new_data, offset) }

  schedule_to_persist! if full?
end

#dataObject


64
65
66
# File 'app/models/ci/build_trace_chunk.rb', line 64

def data
  @data ||= get_data.to_s
end

#end_offsetObject


93
94
95
# File 'app/models/ci/build_trace_chunk.rb', line 93

def end_offset
  start_offset + size
end

#live?Boolean

Returns:

  • (Boolean)

115
116
117
# File 'app/models/ci/build_trace_chunk.rb', line 115

def live?
  redis?
end

#persist_data!Object


101
102
103
# File 'app/models/ci/build_trace_chunk.rb', line 101

def persist_data!
  in_lock(*lock_params) { unsafe_persist_data! }
end

#persisted?Boolean

Returns:

  • (Boolean)

111
112
113
# File 'app/models/ci/build_trace_chunk.rb', line 111

def persisted?
  !redis?
end

#rangeObject


97
98
99
# File 'app/models/ci/build_trace_chunk.rb', line 97

def range
  (start_offset...end_offset)
end

#schedule_to_persist!Object


105
106
107
108
109
# File 'app/models/ci/build_trace_chunk.rb', line 105

def schedule_to_persist!
  return if persisted?

  Ci::BuildTraceChunkFlushWorker.perform_async(id)
end

#sizeObject


85
86
87
# File 'app/models/ci/build_trace_chunk.rb', line 85

def size
  @size ||= @data&.bytesize || current_store.size(self) || data&.bytesize
end

#start_offsetObject


89
90
91
# File 'app/models/ci/build_trace_chunk.rb', line 89

def start_offset
  chunk_index * CHUNK_SIZE
end

#truncate(offset = 0) ⇒ Object

Raises:

  • (ArgumentError)

68
69
70
71
72
73
# File 'app/models/ci/build_trace_chunk.rb', line 68

def truncate(offset = 0)
  raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0
  return if offset == size # Skip the following process as it doesn't affect anything

  self.append("", offset)
end