Class: Raif::ArchiveStorage::FileSystem

Inherits:
Object
  • Object
show all
Defined in:
lib/raif/archive_storage/file_system.rb

Overview

Local-disk reference implementation of the archive storage adapter contract (Raif.config.archive_storage): write returns a location string and raises on any failure; delete and delete_prefix are idempotent (a missing object or prefix succeeds) and wrap any filesystem failure in Raif::Errors::ArchiveStorageError. Only write is required of every adapter; delete supports cleanup of an invalid just-uploaded object and delete_prefix supports Raif::Archive.purge_partition!, so hosts implement them only when they use the corresponding feature. Used by Raif's own test suite and suitable for small hosts; production hosts typically supply their own adapter (e.g. S3-backed, passing checksum_sha256 on the PUT so the store verifies integrity server-side).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root:) ⇒ FileSystem

Returns a new instance of FileSystem.



20
21
22
# File 'lib/raif/archive_storage/file_system.rb', line 20

def initialize(root:)
  @root = Pathname.new(root)
end

Instance Attribute Details

#rootObject (readonly)

Returns the value of attribute root.



18
19
20
# File 'lib/raif/archive_storage/file_system.rb', line 18

def root
  @root
end

Instance Method Details

#delete(key:) ⇒ Object

Idempotent single-object deletion: a missing object is a successful no-op. Used for best-effort cleanup of a just-uploaded object whose cull was aborted (see Raif::ArchiveModelCompletionsJob).



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/raif/archive_storage/file_system.rb', line 44

def delete(key:)
  path = path_for(key)
  begin
    File.unlink(path)
  rescue Errno::ENOENT
    # Already gone: deletion is idempotent.
  rescue SystemCallError => e
    raise Raif::Errors::ArchiveStorageError, "failed to delete #{key}: #{e.class}: #{e.message}"
  end

  true
end

#delete_prefix(prefix:) ⇒ Object

Idempotent prefix deletion returning the number of objects removed; a missing prefix is a successful no-op returning 0. Used by Raif::Archive.purge_partition! for complete erasure of a partition, crash-orphaned uploads included.



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/raif/archive_storage/file_system.rb', line 61

def delete_prefix(prefix:)
  dir = contained_path(prefix, kind: "prefix")
  return 0 unless dir.exist?

  begin
    object_count = dir.glob("**/*", File::FNM_DOTMATCH).count(&:file?)
    FileUtils.remove_entry(dir)
    object_count
  rescue SystemCallError => e
    raise Raif::Errors::ArchiveStorageError, "failed to delete prefix #{prefix}: #{e.class}: #{e.message}"
  end
end

#write(key:, io:, checksum_sha256:) ⇒ Object

Verifies the written bytes against checksum_sha256 before returning, the local-disk equivalent of a remote store's server-side upload integrity verification (e.g. S3 checking checksum_sha256 on the PUT).



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/raif/archive_storage/file_system.rb', line 27

def write(key:, io:, checksum_sha256:)
  path = path_for(key)
  path.dirname.mkpath
  IO.copy_stream(io, path)

  written_checksum = Digest::SHA256.file(path).hexdigest
  if written_checksum != checksum_sha256
    raise Raif::Errors::ArchiveStorageError,
      "checksum mismatch after writing #{key}: expected #{checksum_sha256}, wrote #{written_checksum}"
  end

  path.to_s
end