Class: Trackdown::DatabaseFingerprint

Inherits:
Object
  • Object
show all
Defined in:
lib/trackdown/database_fingerprint.rb

Overview

The identity of the MaxMind database file that answered a lookup.

build_epoch comes straight from the database's own metadata, so it costs nothing. The SHA-256 digest costs a full read of the database file, so it is computed the first time somebody asks for it and then reused by every reader bound to that exact file generation — never once per lookup.

If the file changes underneath us the digest becomes nil rather than a number that describes a file we are no longer reading.

MaxMind documents the exact build_epoch metadata field here: https://maxmind.github.io/MaxMind-DB/#build_epoch

Constant Summary collapse

READ_CHUNK_BYTES =

1 MiB

1 << 20

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path:, build_epoch: nil, captured_file_identity: CAPTURE_CURRENT_FILE_IDENTITY) ⇒ DatabaseFingerprint

Returns a new instance of DatabaseFingerprint.



25
26
27
28
29
30
31
32
33
34
# File 'lib/trackdown/database_fingerprint.rb', line 25

def initialize(path:, build_epoch: nil, captured_file_identity: CAPTURE_CURRENT_FILE_IDENTITY)
  @path = path.to_s.dup.freeze
  @build_epoch = build_epoch
  @identity = if captured_file_identity.equal?(CAPTURE_CURRENT_FILE_IDENTITY)
                current_file_identity
              else
                captured_file_identity
              end
  @mutex = Mutex.new
end

Instance Attribute Details

#build_epochObject (readonly)

Returns the value of attribute build_epoch.



23
24
25
# File 'lib/trackdown/database_fingerprint.rb', line 23

def build_epoch
  @build_epoch
end

#pathObject (readonly)

Returns the value of attribute path.



23
24
25
# File 'lib/trackdown/database_fingerprint.rb', line 23

def path
  @path
end

Instance Method Details

#built_atObject

When MaxMind built this database.



51
52
53
# File 'lib/trackdown/database_fingerprint.rb', line 51

def built_at
  Time.at(@build_epoch).utc if @build_epoch.is_a?(Numeric)
end

#cache_keyObject

Stable inside one process and suitable for sharing one lazy digest between all pooled readers that opened the same database generation.



46
47
48
# File 'lib/trackdown/database_fingerprint.rb', line 46

def cache_key
  [@path, @build_epoch, @identity].freeze
end

#changed?Boolean

Has the file been replaced since we fingerprinted it?

Returns:

  • (Boolean)


56
57
58
# File 'lib/trackdown/database_fingerprint.rb', line 56

def changed?
  current_file_identity != @identity
end

#sha256Object

The digest of the database we read, or nil if we can't honestly compute one.



61
62
63
64
65
66
67
68
69
# File 'lib/trackdown/database_fingerprint.rb', line 61

def sha256
  return @sha256 if defined?(@sha256)

  @mutex.synchronize do
    @sha256 = compute_sha256 unless defined?(@sha256)
  end

  @sha256
end

#with_build_epoch(build_epoch) ⇒ Object

Attach the metadata read by a database reader without losing the file identity captured before that reader opened the path. This is what keeps a reader that still has database A in memory from ever digesting database B after the path is replaced.



40
41
42
# File 'lib/trackdown/database_fingerprint.rb', line 40

def with_build_epoch(build_epoch)
  self.class.new(path: @path, build_epoch: build_epoch, captured_file_identity: @identity)
end