Class: Petra::PersistenceAdapters::FileAdapter

Inherits:
Adapter
  • Object
show all
Defined in:
lib/petra/persistence_adapters/file_adapter.rb

Class Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Adapter

#enqueue

Methods included from Util::Registrable

included

Class Attribute Details

.storage_directoryObject



16
17
18
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 16

def storage_directory
  ::Pathname.new(@storage_directory || '/tmp/petra')
end

Instance Method Details

#log_entries(section) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 54

def log_entries(section)
  with_transaction_lock(section.transaction.identifier) do
    section_dir = storage_file_name(*section_dirname(section))

    # If the given section has never been persisted before, we don't have to
    # search further for log entries
    return [] unless section_dir.exist?

    section_dir.children.sort.select { |f| f.extname == '.entry' }.map do |f|
      entry_hash = ::YAML.load_file(f.to_s)
      Petra::Components::LogEntry.from_hash(section, entry_hash)
    end
  end
end

#persist!Object



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 23

def persist!
  return true if queue.empty?

  # rubocop:disable Style/WhileUntilDo
  # We currently only allow entries for one transaction in the queue
  with_transaction_lock(queue.first.transaction_identifier) do
    while (entry = queue.shift) do
      identifier = create_entry_file(entry)
      entry.mark_as_persisted!(identifier)
    end
  end
  # rubocop:enable Style/WhileUntilDo
end

#reset_transaction(transaction) ⇒ Object

Removes everything that was persisted while executing the given transaction



72
73
74
75
76
77
78
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 72

def reset_transaction(transaction)
  with_transaction_lock(transaction) do
    if storage_file_name('transactions', transaction.identifier).exist?
      FileUtils.rm_r(storage_file_name('transactions', transaction.identifier))
    end
  end
end

#savepoints(transaction) ⇒ Object



45
46
47
48
49
50
51
52
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 45

def savepoints(transaction)
  with_transaction_lock(transaction.identifier) do
    return [] unless File.exist? storage_file_name('transactions', transaction.identifier)
    storage_file_name('transactions', transaction.identifier).children.select(&:directory?).map do |f|
      ::YAML.load_file(f.join('information.yml').to_s)[:savepoint]
    end
  end
end

#transaction_identifiersObject



37
38
39
40
41
42
43
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 37

def transaction_identifiers
  # Wait until no other transaction is doing stuff that might lead to inconsistent data
  with_global_lock do
    ensure_directory_existence('transactions')
    storage_file_name('transactions').children.select(&:directory?).map(&:basename).map(&:to_s)
  end
end

#with_global_lock(**options, &block) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 80

def with_global_lock(**options, &block)
  with_file_lock('global.persistence', **options, &block)
rescue Petra::LockError => e
  raise e if e.processed?
  exception = Petra::LockError.new(lock_type: 'global', lock_name: 'global.persistence', processed: true)
  raise exception, 'The global lock could not be acquired.'
end

#with_object_lock(proxy, **options, &block) ⇒ Object



97
98
99
100
101
102
103
104
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 97

def with_object_lock(proxy, **options, &block)
  key = proxy.__object_key.gsub(/[^a-zA-Z0-9]/, '-')
  with_file_lock("proxy.#{key}", **options, &block)
rescue Petra::LockError => e
  raise e if e.processed?
  exception = Petra::LockError.new(lock_type: 'object', lock_name: proxy.__object_key, processed: true)
  raise exception, "The object lock '#{proxy.__object_id}' could not be acquired."
end

#with_transaction_lock(transaction, **options, &block) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/petra/persistence_adapters/file_adapter.rb', line 88

def with_transaction_lock(transaction, **options, &block)
  identifier = transaction.is_a?(Petra::Components::Transaction) ? transaction.identifier : transaction
  with_file_lock("transaction.#{identifier}", **options, &block)
rescue Petra::LockError => e
  raise e if e.processed?
  exception = Petra::LockError.new(lock_type: 'transaction', lock_name: identifier, processed: true)
  raise exception, "The transaction lock '#{identifier}' could not be acquired."
end