Class: Prometheus::EnumeratedStore::PidEnumerator

Inherits:
Object
  • Object
show all
Defined in:
lib/prometheus/enumerated_store/pid_enumerator.rb

Constant Summary collapse

MAX_INSTANCES =
1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir:) ⇒ PidEnumerator

Returns a new instance of PidEnumerator.



15
16
17
18
19
20
21
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 15

def initialize(dir:)
  @dir = dir

  @lock_path = File.join(@dir, 'enumetated_instances.lock')
  @instances_path = File.join(@dir, 'enumetated_instances.json')
  reset
end

Instance Attribute Details

#dirObject (readonly)

Returns the value of attribute dir.



13
14
15
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 13

def dir
  @dir
end

#instances_pathObject (readonly)

Returns the value of attribute instances_path.



13
14
15
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 13

def instances_path
  @instances_path
end

#lock_pathObject (readonly)

Returns the value of attribute lock_path.



13
14
15
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 13

def lock_path
  @lock_path
end

Instance Method Details

#alive?(pid) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
85
86
87
88
89
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 82

def alive?(pid)
  return nil if pid <= 1

  Process.getpgid(pid)
  true
rescue Errno::ESRCH
  false
end

#clean_dead_instances(data) ⇒ Object



74
75
76
77
78
79
80
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 74

def clean_dead_instances(data)
  data.select do |pid, num|
    next nil if num.to_i <= 0 || num.to_i > MAX_INSTANCES

    alive?(pid.to_i)
  end
end

#find_minimal_number(data) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 66

def find_minimal_number(data)
  values = data.values
  current = data[Process.pid.to_s] || (1..MAX_INSTANCES).find{|i| !values.include?(i) }
  raise "Unable to find any number between 1 and #{MAX_INSTANCES}" unless current

  data[Process.pid.to_s] = current
end

#obtain_enumerated_numberObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 51

def obtain_enumerated_number
  with_lock do |tmpfilename|
    break @obtained if @obtained # double check-lock

    raw_data = read_instances
    data = JSON.parse(raw_data) || {} # set {} if "null" in file
    data = clean_dead_instances(data)

    current = find_minimal_number(data)
    File.write(tmpfilename, data.to_json) # We are inside tmpdir
    File.rename(tmpfilename, instances_path)
    current
  end
end

#obtainedObject



47
48
49
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 47

def obtained
  @obtained ||= obtain_enumerated_number
end

#read_instancesObject



39
40
41
42
43
44
45
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 39

def read_instances
  raw = File.read(instances_path).strip
  raw.empty? ? '{}' : raw
rescue Errno::ENOENT
  # there is no file yet
  '{}'
end

#resetObject



23
24
25
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 23

def reset
  @obtained = nil
end

#with_lockObject



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/prometheus/enumerated_store/pid_enumerator.rb', line 27

def with_lock
  File.open(lock_path, File::RDWR | File::CREAT, 0o644) do |file|
    file.flock(File::LOCK_EX)
    Dir.chdir(@dir) do
      tmpfilename = ".tmp-#{$$}-#{rand(0x100000000).to_s(36)}.json"
      yield(tmpfilename)
    ensure
      File.delete(tmpfilename) rescue nil
    end
  end
end