Class: LittleGhost::Artifacts::WorkspaceStore
- Inherits:
-
Object
- Object
- LittleGhost::Artifacts::WorkspaceStore
- Defined in:
- lib/little_ghost/artifacts/workspace_store.rb
Overview
Writes immutable artifacts beneath one named Workspace path. The store applies per-artifact, total-byte, and count limits before exposing a file. It does not remove files; the Workspace provider owns their lifetime.
Defined Under Namespace
Classes: ContextControl
Constant Summary collapse
- PLATFORM_OPEN_FLAGS =
case RUBY_PLATFORM when /darwin/ {close_on_exec: 0x0100_0000} when /linux/ {close_on_exec: 0x0008_0000} end&.freeze
- OPENAT =
:nodoc:
if PLATFORM_OPEN_FLAGS # :nodoc: Fiddle::Function.new( Fiddle::Handle::DEFAULT["openat"], [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VARIADIC], Fiddle::TYPE_INT ) end
- UNLINKAT =
:nodoc:
if PLATFORM_OPEN_FLAGS # :nodoc: Fiddle::Function.new( Fiddle::Handle::DEFAULT["unlinkat"], [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT], Fiddle::TYPE_INT ) end
- DEFAULT_MAX_ARTIFACT_BYTES =
Default maximum size of one artifact: 32 MiB.
32 * 1024 * 1024
- DEFAULT_MAX_TOTAL_BYTES =
Default cumulative store budget: 64 MiB.
64 * 1024 * 1024
- DEFAULT_MAX_ARTIFACTS =
Default maximum number of unique artifacts.
100
Instance Method Summary collapse
-
#initialize(workspace:, path: :artifacts, max_artifact_bytes: DEFAULT_MAX_ARTIFACT_BYTES, max_total_bytes: DEFAULT_MAX_TOTAL_BYTES, max_artifacts: DEFAULT_MAX_ARTIFACTS) ⇒ WorkspaceStore
constructor
Uses the already-open
workspaceand a configured namedpath. -
#size ⇒ Object
Number of unique artifacts in this store.
-
#total_bytes ⇒ Object
Number of bytes reserved by unique artifacts in this store.
-
#write(data:, name: nil, media_type: nil, metadata: {}, context: nil) ⇒ Object
Materializes
dataonce for an identical name, media type, and byte sequence. -
#write_batch(entries, context: nil) ⇒ Object
Atomically materializes an Array of write keyword Hashes.
Constructor Details
#initialize(workspace:, path: :artifacts, max_artifact_bytes: DEFAULT_MAX_ARTIFACT_BYTES, max_total_bytes: DEFAULT_MAX_TOTAL_BYTES, max_artifacts: DEFAULT_MAX_ARTIFACTS) ⇒ WorkspaceStore
Uses the already-open workspace and a configured named path.
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/little_ghost/artifacts/workspace_store.rb', line 55 def initialize( workspace:, path: :artifacts, max_artifact_bytes: DEFAULT_MAX_ARTIFACT_BYTES, max_total_bytes: DEFAULT_MAX_TOTAL_BYTES, max_artifacts: DEFAULT_MAX_ARTIFACTS ) raise ToolError, "Artifact workspace path is unavailable" unless workspace @workspace = workspace @path = path.to_sym @max_artifact_bytes = positive_integer(max_artifact_bytes, :max_artifact_bytes) @max_total_bytes = positive_integer(max_total_bytes, :max_total_bytes) @max_artifacts = positive_integer(max_artifacts, :max_artifacts) @mutex = Mutex.new @artifacts = {} @total_bytes = 0 @namespace = SecureRandom.hex(8).freeze @root, @root_identity = validate_root! end |
Instance Method Details
#size ⇒ Object
Number of unique artifacts in this store.
119 |
# File 'lib/little_ghost/artifacts/workspace_store.rb', line 119 def size = @mutex.synchronize { @artifacts.length } |
#total_bytes ⇒ Object
Number of bytes reserved by unique artifacts in this store.
116 |
# File 'lib/little_ghost/artifacts/workspace_store.rb', line 116 def total_bytes = @mutex.synchronize { @total_bytes } |
#write(data:, name: nil, media_type: nil, metadata: {}, context: nil) ⇒ Object
Materializes data once for an identical name, media type, and byte
sequence. Concurrent calls share one descriptor and consume one budget.
78 79 80 |
# File 'lib/little_ghost/artifacts/workspace_store.rb', line 78 def write(data:, name: nil, media_type: nil, metadata: {}, context: nil) write_batch([{data:, name:, media_type:, metadata:}], context:).fetch(0) end |
#write_batch(entries, context: nil) ⇒ Object
Atomically materializes an Array of write keyword Hashes. If any new artifact fails, every file and budget reservation created by this call is rolled back; previously cached artifacts remain unchanged.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/little_ghost/artifacts/workspace_store.rb', line 85 def write_batch(entries, context: nil) raise ArgumentError, "artifact batch must be an array" unless entries.is_a?(Array) context&.check! control = context_control(context) prepared = entries.map { |entry| prepare_entry(entry) } @mutex.synchronize do control&.check! created = [] begin prepared.map do |entry| control&.check! digest = entry.fetch(:digest) next @artifacts.fetch(digest) if @artifacts.key?(digest) reserve!(entry.fetch(:data).bytesize) record = entry.merge(materialized: false) created << record artifact = materialize(**entry, control:) @artifacts[digest] = artifact record[:materialized] = true artifact end.freeze rescue => error rollback_batch(created, error:) raise end end end |