Class: OpenASN::Dataset

Inherits:
Object
  • Object
show all
Defined in:
lib/openasn/dataset.rb

Overview

Owns the live Snapshot and its lifecycle. Concurrency model (the whole point of this class — do not "simplify" it):

* Readers call #snapshot and get whatever is current. The swap is a
single ivar assignment — atomic under MRI's GVL — so readers see
either the old complete snapshot or the new complete snapshot,
never partial state. No locks on the read path, ever.
* The lazy first load and explicit reloads are serialized with a
Mutex so N threads arriving on a cold process build one snapshot,
not N.
* Multi-process reality (puma workers): the updater process writes
new files atomically; OTHER processes notice via a cheap periodic
freshness probe (#maybe_reload_from_disk — a File.mtime call at
most every RELOAD_CHECK_INTERVAL seconds, amortized to ~zero) and
rebuild their in-memory snapshot from disk.

Constant Summary collapse

RELOAD_CHECK_INTERVAL =

seconds

300
STALE_AFTER =

boot-time "kick a refresh" threshold (documented in README "Updates")

7 * 86_400

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Dataset

Returns a new instance of Dataset.



23
24
25
26
27
28
29
# File 'lib/openasn/dataset.rb', line 23

def initialize(config)
  @config = config
  @snapshot = nil
  @load_mutex = Mutex.new
  @last_disk_check = 0.0
  @loaded_manifest_mtime = nil
end

Instance Method Details

#eager_load!Object



38
39
40
41
# File 'lib/openasn/dataset.rb', line 38

def eager_load!
  load!
  nil
end

#infoObject



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/openasn/dataset.rb', line 60

def info
  snap = snapshot
  {
    build_id: snap.build_id,
    built_at: Time.at(snap.build_ts).utc,
    loaded_at: snap.loaded_at,
    origin: snap.origin,
    memory_mode: @config.memory_mode,
    records: snap.record_counts,
    tier_b_status: snap.tier_b_status
  }
end

#loaded?Boolean

Returns:

  • (Boolean)


53
# File 'lib/openasn/dataset.rb', line 53

def loaded? = !@snapshot.nil?

#reload!Object

Called by the updater after it wrote new files: rebuild + swap now.



44
45
46
47
48
49
50
51
# File 'lib/openasn/dataset.rb', line 44

def reload!
  @load_mutex.synchronize do
    @snapshot = Snapshot.build(@config)
    @loaded_manifest_mtime = manifest_mtime
    @last_disk_check = monotonic_now
    @snapshot
  end
end

#snapshotObject



31
32
33
34
35
36
# File 'lib/openasn/dataset.rb', line 31

def snapshot
  snap = @snapshot
  return snap if snap && !disk_check_due?

  snap ? maybe_reload_from_disk : load!
end

#stale?Boolean

Returns:

  • (Boolean)


55
56
57
58
# File 'lib/openasn/dataset.rb', line 55

def stale?
  snap = snapshot
  snap.age_seconds > STALE_AFTER
end