evt-entity_cache 0.13.0.0 → 0.14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/entity_cache.rb +17 -15
- data/lib/entity_cache/controls.rb +12 -3
- data/lib/entity_cache/controls/entity.rb +27 -1
- data/lib/entity_cache/controls/persist_interval.rb +2 -22
- data/lib/entity_cache/controls/record.rb +33 -12
- data/lib/entity_cache/controls/storage/persistent.rb +8 -26
- data/lib/entity_cache/controls/storage/persistent/example.rb +41 -0
- data/lib/entity_cache/controls/storage/persistent/not_implemented.rb +19 -0
- data/lib/entity_cache/controls/storage/persistent/write.rb +25 -0
- data/lib/entity_cache/controls/storage/temporary.rb +14 -2
- data/lib/entity_cache/controls/subject.rb +2 -4
- data/lib/entity_cache/controls/time.rb +1 -12
- data/lib/entity_cache/controls/version.rb +5 -11
- data/lib/entity_cache/defaults.rb +2 -2
- data/lib/entity_cache/record.rb +36 -30
- data/lib/entity_cache/record/destructure.rb +29 -0
- data/lib/entity_cache/record/log_text.rb +9 -0
- data/lib/entity_cache/record/transformer.rb +26 -0
- data/lib/entity_cache/store/persistent/null.rb +15 -0
- data/lib/entity_cache/store/persistent/substitute.rb +64 -0
- data/lib/entity_cache/store/persistent/telemetry.rb +16 -0
- data/lib/entity_cache/store/temporary.rb +47 -0
- data/lib/entity_cache/store/temporary/build.rb +48 -0
- data/lib/entity_cache/store/temporary/build/defaults.rb +28 -0
- data/lib/entity_cache/{storage → store}/temporary/scope/exclusive.rb +1 -1
- data/lib/entity_cache/store/temporary/scope/global.rb +34 -0
- data/lib/entity_cache/store/temporary/scope/thread.rb +35 -0
- data/lib/entity_cache/store/temporary/substitute.rb +36 -0
- data/lib/entity_cache/substitute.rb +33 -17
- metadata +20 -58
- data/lib/entity_cache/entity_cache.rb +0 -83
- data/lib/entity_cache/error.rb +0 -3
- data/lib/entity_cache/storage/persistent.rb +0 -81
- data/lib/entity_cache/storage/persistent/none.rb +0 -15
- data/lib/entity_cache/storage/persistent/substitute.rb +0 -51
- data/lib/entity_cache/storage/persistent/telemetry.rb +0 -38
- data/lib/entity_cache/storage/temporary.rb +0 -56
- data/lib/entity_cache/storage/temporary/build.rb +0 -42
- data/lib/entity_cache/storage/temporary/scope/defaults.rb +0 -32
- data/lib/entity_cache/storage/temporary/scope/error.rb +0 -9
- data/lib/entity_cache/storage/temporary/scope/shared.rb +0 -31
data/lib/entity_cache/record.rb
CHANGED
@@ -1,44 +1,50 @@
|
|
1
1
|
class EntityCache
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
Record = Struct.new(
|
3
|
+
:id,
|
4
|
+
:entity,
|
5
|
+
:version,
|
6
|
+
:time,
|
7
|
+
:persisted_version,
|
8
|
+
:persisted_time
|
9
|
+
)
|
10
|
+
|
11
|
+
class Record
|
12
|
+
dependency :clock, Clock::UTC
|
13
|
+
|
14
|
+
def configure
|
15
|
+
Clock::UTC.configure(self)
|
8
16
|
end
|
9
17
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
includes = Array(includes)
|
16
|
-
|
17
|
-
includes.each do |attribute|
|
18
|
-
value = public_send attribute
|
19
|
-
|
20
|
-
if value.nil? && attribute == :version
|
21
|
-
value = NoStream.version
|
22
|
-
end
|
23
|
-
|
24
|
-
responses << value
|
25
|
-
end
|
18
|
+
def self.build(id, entity, version, time, persisted_version: nil, persisted_time: nil)
|
19
|
+
instance = new(id, entity, version, time, persisted_version, persisted_time)
|
20
|
+
instance.configure
|
21
|
+
instance
|
22
|
+
end
|
26
23
|
|
27
|
-
|
24
|
+
def self.destructure(instance, includes=nil)
|
25
|
+
Destructure.(instance, includes)
|
28
26
|
end
|
29
27
|
|
30
28
|
def age_milliseconds
|
31
|
-
Clock::UTC.elapsed_milliseconds(time,
|
29
|
+
Clock::UTC.elapsed_milliseconds(time, clock.now)
|
32
30
|
end
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
def persisted_age_milliseconds
|
33
|
+
if persisted_time.nil?
|
34
|
+
nil
|
35
|
+
else
|
36
|
+
Clock::UTC.elapsed_milliseconds(
|
37
|
+
persisted_time,
|
38
|
+
time
|
39
|
+
)
|
38
40
|
end
|
41
|
+
end
|
39
42
|
|
40
|
-
|
41
|
-
|
43
|
+
def persisted_age_versions
|
44
|
+
if persisted_version.nil?
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
version - persisted_version
|
42
48
|
end
|
43
49
|
end
|
44
50
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class EntityCache
|
2
|
+
class Record
|
3
|
+
module Destructure
|
4
|
+
def self.call(record, includes=nil)
|
5
|
+
record ||= NoStream.record
|
6
|
+
|
7
|
+
return record.entity if includes.nil?
|
8
|
+
|
9
|
+
return_values = Array(includes).map do |attribute|
|
10
|
+
record.public_send(attribute)
|
11
|
+
end
|
12
|
+
|
13
|
+
return record.entity, *return_values
|
14
|
+
end
|
15
|
+
|
16
|
+
module NoStream
|
17
|
+
def self.record
|
18
|
+
@record ||= build_record
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build_record
|
22
|
+
record = Record.new
|
23
|
+
record.version = MessageStore::NoStream.name
|
24
|
+
record
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class EntityCache
|
2
|
+
class Record
|
3
|
+
module LogText
|
4
|
+
def self.get(record)
|
5
|
+
"Entity: #{record&.entity.class}, Version: #{record&.version.inspect}, Time: #{record&.time.inspect}, Persisted Version: #{record&.persisted_version.inspect}, Persisted Time: #{record&.persisted_time.inspect}"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class EntityCache
|
2
|
+
class Record
|
3
|
+
module Transformer
|
4
|
+
def self.raw_data(instance)
|
5
|
+
raw_data = instance.to_h
|
6
|
+
|
7
|
+
entity = raw_data.delete(:entity)
|
8
|
+
copied_entity = Transform::Copy.(entity)
|
9
|
+
|
10
|
+
raw_data[:entity] = copied_entity
|
11
|
+
|
12
|
+
raw_data
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.instance(raw_data)
|
16
|
+
instance = Record.new
|
17
|
+
|
18
|
+
raw_data.each do |attribute, value|
|
19
|
+
instance.public_send("#{attribute}=", value)
|
20
|
+
end
|
21
|
+
|
22
|
+
instance
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
module Persistent
|
4
|
+
module Substitute
|
5
|
+
def self.build
|
6
|
+
Persistent.build
|
7
|
+
end
|
8
|
+
|
9
|
+
class Persistent
|
10
|
+
include Store::Persistent
|
11
|
+
|
12
|
+
attr_accessor :telemetry_sink
|
13
|
+
|
14
|
+
def self.build
|
15
|
+
instance = new(subject)
|
16
|
+
instance.configure
|
17
|
+
instance
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure(session: nil)
|
21
|
+
self.telemetry_sink = self.class.register_telemetry_sink(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get(id)
|
25
|
+
record = get_records[id]
|
26
|
+
|
27
|
+
if record
|
28
|
+
return record.entity, record.version, record.time
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_records
|
33
|
+
@get_records ||= {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(id, entity, version, time)
|
37
|
+
record = Record.new(id, entity, version, time)
|
38
|
+
|
39
|
+
get_records[id] = record
|
40
|
+
|
41
|
+
record
|
42
|
+
end
|
43
|
+
|
44
|
+
def put(*)
|
45
|
+
end
|
46
|
+
|
47
|
+
def put?(&block)
|
48
|
+
block ||= proc { true }
|
49
|
+
|
50
|
+
telemetry_sink.recorded_put? do |record|
|
51
|
+
data = record.data
|
52
|
+
|
53
|
+
block.(data.id, data.entity, data.version, data.time)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.subject
|
58
|
+
:substitute
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
class Temporary
|
4
|
+
include Log::Dependency
|
5
|
+
|
6
|
+
attr_accessor :subject
|
7
|
+
|
8
|
+
def self.build(subject)
|
9
|
+
instance = new
|
10
|
+
instance.subject = subject
|
11
|
+
instance
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.configure(receiver, subject, scope: nil, attr_name: nil)
|
15
|
+
attr_name ||= :temporary_store
|
16
|
+
|
17
|
+
instance = Build.(subject, scope: scope)
|
18
|
+
receiver.public_send("#{attr_name}=", instance)
|
19
|
+
instance
|
20
|
+
end
|
21
|
+
|
22
|
+
abstract :records
|
23
|
+
|
24
|
+
def get(id)
|
25
|
+
logger.trace { "Getting Entity (ID: #{id.inspect})" }
|
26
|
+
|
27
|
+
record = records[id]
|
28
|
+
|
29
|
+
logger.debug { "Get entity done (ID: #{id.inspect}, #{Record::LogText.get(record)})" }
|
30
|
+
|
31
|
+
record
|
32
|
+
end
|
33
|
+
|
34
|
+
def put(record)
|
35
|
+
id = record.id
|
36
|
+
|
37
|
+
logger.trace { "Putting entity (ID: #{id.inspect}, #{Record::LogText.get(record)})" }
|
38
|
+
|
39
|
+
records[id] = record
|
40
|
+
|
41
|
+
logger.trace { "Put entity done (ID: #{id.inspect}, #{Record::LogText.get(record)})" }
|
42
|
+
|
43
|
+
record
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
class Temporary
|
4
|
+
module Build
|
5
|
+
def self.call(subject, scope: nil)
|
6
|
+
scope ||= Defaults.scope
|
7
|
+
|
8
|
+
cls = scope_class(scope)
|
9
|
+
|
10
|
+
cls.build(subject)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.default_scope_class
|
14
|
+
scope_class(Defaults.scope)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.scope_class(scope)
|
18
|
+
scopes.fetch(scope) do
|
19
|
+
*scopes, final_scope = self.scopes.keys
|
20
|
+
|
21
|
+
scope_list = <<~TEXT
|
22
|
+
#{scopes.map(&:inspect) * ', '} or #{final_scope.inspect}
|
23
|
+
TEXT
|
24
|
+
|
25
|
+
error_message = %{Scope #{scope.inspect} is unknown. It must be one of: #{scope_list}}
|
26
|
+
|
27
|
+
logger.error(error_message)
|
28
|
+
raise ScopeError, error_message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.scopes
|
33
|
+
@scopes ||= {
|
34
|
+
:exclusive => Scope::Exclusive,
|
35
|
+
:global => Scope::Global,
|
36
|
+
:thread => Scope::Thread
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.logger
|
41
|
+
@logger ||= Log.get(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
ScopeError = Class.new(StandardError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
class Temporary
|
4
|
+
module Build
|
5
|
+
module Defaults
|
6
|
+
def self.scope
|
7
|
+
Scope.get
|
8
|
+
end
|
9
|
+
|
10
|
+
module Scope
|
11
|
+
def self.get
|
12
|
+
value = ENV.fetch(env_var, default)
|
13
|
+
value.to_sym
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.env_var
|
17
|
+
'ENTITY_CACHE_SCOPE'
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.default
|
21
|
+
'thread'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
class Temporary
|
4
|
+
module Scope
|
5
|
+
class Global < Temporary
|
6
|
+
def records
|
7
|
+
records_by_subject[subject]
|
8
|
+
end
|
9
|
+
|
10
|
+
def records_by_subject
|
11
|
+
mutex.synchronize do
|
12
|
+
@@records_by_subject ||= {}
|
13
|
+
@@records_by_subject[subject] ||= ThreadSafeHash.new
|
14
|
+
@@records_by_subject
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
mutex = ::Thread::Mutex.new
|
19
|
+
define_method(:mutex) do
|
20
|
+
mutex
|
21
|
+
end
|
22
|
+
|
23
|
+
class ThreadSafeHash < ::Hash
|
24
|
+
def [](key)
|
25
|
+
value = super(key)
|
26
|
+
value = Transform::Copy.(value) unless value.nil?
|
27
|
+
value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class EntityCache
|
2
|
+
module Store
|
3
|
+
class Temporary
|
4
|
+
module Scope
|
5
|
+
class Thread < Temporary
|
6
|
+
def records
|
7
|
+
records_by_subject[subject]
|
8
|
+
end
|
9
|
+
|
10
|
+
def records_by_subject
|
11
|
+
current_thread = ::Thread.current
|
12
|
+
|
13
|
+
records_by_subject = current_thread.thread_variable_get(thread_variable)
|
14
|
+
|
15
|
+
if records_by_subject.nil?
|
16
|
+
records_by_subject = Hash.new do |hash, subject|
|
17
|
+
hash[subject] = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
current_thread.thread_variable_set(thread_variable, records_by_subject)
|
21
|
+
end
|
22
|
+
|
23
|
+
records_by_subject
|
24
|
+
end
|
25
|
+
|
26
|
+
thread_variable = :"entity_cache_records_by_subject_#{SecureRandom.hex(7)}"
|
27
|
+
|
28
|
+
define_method(:thread_variable) do
|
29
|
+
thread_variable
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|