class Triglav::Agent::StorageFile

Thread and inter-process safe YAML file storage

StorageFile.open($setting.status_file) do |fp|
  status = fp.load
  status['foo'] = 'bar'
  fp.dump(status)
end

Attributes

fp[R]

Public Class Methods

get(path, key) click to toggle source

Get value of the given key from storage file

StorageFile.get($setting.status_file, 'foo') # like h['foo'] = 'bar'
StorageFile.get($setting.status_file, ['a','b']) # like hash['a']['b']

@param [String] path @param [Object] key

# File lib/triglav/agent/storage_file.rb, line 175
def self.get(path, key)
  keys = Array(key)
  readopen(path) {|fp| fp.load.dig(*keys) }
end
getsetnx(path, key, val) click to toggle source

Set key to hold val if key does not exist and returns the holded value

This is a kind of atomic short hand of

StorageFile.setnx($setting.status_file, 'foo', 'bar')
StorageFile.get($setting.status_file, 'foo')

@param [String] path @param [Object] key @param [Object] val @return [Object] holded value

# File lib/triglav/agent/storage_file.rb, line 155
def self.getsetnx(path, key, val)
  keys = Array(key)
  open(path) do |fp|
    params = fp.load
    if curr = params.dig(*keys)
      return curr
    end
    HashUtil.setdig(params, keys, val)
    fp.dump(params)
    return val
  end
end
load(path) click to toggle source

Load storage file

StorageFile.load($setting.status_file)

@param [String] path @return [Hash]

# File lib/triglav/agent/storage_file.rb, line 44
def self.load(path)
  open(path) {|fp| fp.load }
end
merge!(path, key, val) click to toggle source

Merge Hash value with existing Hash value.

@param [String] path @param [Object] key @param [Hash] val @return [Object] holded value

# File lib/triglav/agent/storage_file.rb, line 112
def self.merge!(path, key, val)
  keys = Array(key)
  open(path) do |fp|
    params = fp.load
    _val = params.dig(*keys) || {}
    _val.merge!(val) 
    HashUtil.setdig(params, keys, _val)
    fp.dump(params)
    return true
  end
end
new(fp) click to toggle source
# File lib/triglav/agent/storage_file.rb, line 16
        def initialize(fp)
  @fp = fp
end
open(path) { |storage_file| ... } click to toggle source

Open storage file

StorageFile.open($setting.status_file) do |fp|
  status = fp.load
  status['foo'] = 'bar'
  fp.dump(status)
end

@param [String] path @param [Block] block

# File lib/triglav/agent/storage_file.rb, line 58
def self.open(path, &block)
  # Use RDONLY instead of WRONLY not to TRUNCate contents
  fp = File.open(path, (File::RDONLY | File::CREAT))
  fp.flock(File::LOCK_EX)
  begin
    return yield(StorageFile.new(fp))
  ensure
    fp.flock(File::LOCK_UN)
    fp.close rescue nil
  end
end
readopen(path) { |storage_file| ... } click to toggle source

Open storage file to read

StorageFile.readopen($setting.status_file) do |fp|
  status = fp.load
end

@param [String] path @param [Block] block

# File lib/triglav/agent/storage_file.rb, line 78
def self.readopen(path, &block)
  fp = File.open(path, (File::RDONLY | File::CREAT))
  fp.flock(File::LOCK_SH)
  begin
    return yield(StorageFile.new(fp))
  ensure
    fp.flock(File::LOCK_UN)
    fp.close rescue nil
  end
end
select!(path, parents = [], keys) click to toggle source

Keep specified keys, and remove others

@param [String] path @param [Array] parent keys of hash @param [Array] keys

# File lib/triglav/agent/storage_file.rb, line 185
def self.select!(path, parents = [], keys)
  open(path) do |fp|
    params = fp.load
    if dig = (parents.empty? ? params : params.dig(*parents))
      removes = dig.keys - keys
      unless removes.empty?
        $logger.info { "Remove from status: #{{parent_keys: parents, keys: removes}}" }
        removes.each {|k| dig.delete(k) }
      end
    end
    fp.dump(params)
  end
end
set(path, key, val) click to toggle source

Set storage file with given key, value

StorageFile.set($setting.status_file, 'foo', 'bar') # like h['foo'] = 'bar'
StorageFile.set($setting.status_file, ['a','b'], 'bar') # like h['a']['b'] = 'bar'

@param [String] path @param [Object] key @param [Object] val

# File lib/triglav/agent/storage_file.rb, line 97
def self.set(path, key, val)
  keys = Array(key)
  open(path) do |fp|
    params = fp.load
    HashUtil.setdig(params, keys, val)
    fp.dump(params)
  end
end
setnx(path, key, val) click to toggle source

Set key to hold val if key does not exist

StorageFile.setnx($setting.status_file, 'foo', 'bar') # like h['foo'] = 'bar'
StorageFile.setnx($setting.status_file, ['a','b'], 'bar') # like h['a']['b'] = 'bar'

@param [String] path @param [Object] key @param [Object] val @return [Boolean] true if set (not exist), false if not set (exists)

# File lib/triglav/agent/storage_file.rb, line 133
def self.setnx(path, key, val)
  keys = Array(key)
  open(path) do |fp|
    params = fp.load
    return false if params.dig(*keys)
    HashUtil.setdig(params, keys, val)
    fp.dump(params)
    return true
  end
end

Public Instance Methods

dump(hash) click to toggle source

Dump to storage file

@param [Hash] hash

# File lib/triglav/agent/storage_file.rb, line 34
def dump(hash)
  File.write(@fp.path, YAML.dump(hash))
end
load() click to toggle source

Load storage file

@return [Hash]

# File lib/triglav/agent/storage_file.rb, line 23
def load
  if !(content = @fp.read).empty?
    YAML.load(content) # all keys must be symbols
  else
    {}
  end
end