Class: Triglav::Agent::StorageFile

Inherits:
Object
  • Object
show all
Defined in:
lib/triglav/agent/storage_file.rb

Overview

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#fpObject (readonly)

Returns the value of attribute fp



14
15
16
# File 'lib/triglav/agent/storage_file.rb', line 14

def fp
  @fp
end

Class Method Details

.get(path, key) ⇒ Object

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']

Parameters:

  • path (String)
  • key (Object)


175
176
177
178
# 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) ⇒ Object

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')

Parameters:

  • path (String)
  • key (Object)
  • val (Object)

Returns:

  • (Object)

    holded value



155
156
157
158
159
160
161
162
163
164
165
166
# 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) ⇒ Hash

Load storage file

StorageFile.load($setting.status_file)

Parameters:

  • path (String)

Returns:

  • (Hash)


44
45
46
# File 'lib/triglav/agent/storage_file.rb', line 44

def self.load(path)
  open(path) {|fp| fp.load }
end

.merge!(path, key, val) ⇒ Object

Merge Hash value with existing Hash value.

Parameters:

  • path (String)
  • key (Object)
  • val (Hash)

Returns:

  • (Object)

    holded value



112
113
114
115
116
117
118
119
120
121
122
# 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

.open(path, &block) ⇒ Object

Open storage file

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

Parameters:

  • path (String)
  • block (Block)


58
59
60
61
62
63
64
65
66
67
68
# 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, &block) ⇒ Object

Open storage file to read

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

Parameters:

  • path (String)
  • block (Block)


78
79
80
81
82
83
84
85
86
87
# 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) ⇒ Object

Keep specified keys, and remove others

Parameters:

  • path (String)
  • parent (Array)

    keys of hash

  • keys (Array)


185
186
187
188
189
190
191
192
193
194
195
196
197
# 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) ⇒ Object

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'

Parameters:

  • path (String)
  • key (Object)
  • val (Object)


97
98
99
100
101
102
103
104
# 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) ⇒ Boolean

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'

Parameters:

  • path (String)
  • key (Object)
  • val (Object)

Returns:

  • (Boolean)

    true if set (not exist), false if not set (exists)



133
134
135
136
137
138
139
140
141
142
# 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

Instance Method Details

#dump(hash) ⇒ Object

Dump to storage file

Parameters:

  • hash (Hash)


34
35
36
# File 'lib/triglav/agent/storage_file.rb', line 34

def dump(hash)
  File.write(@fp.path, YAML.dump(hash))
end

#loadHash

Load storage file

Returns:

  • (Hash)


23
24
25
26
27
28
29
# 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