evt-entity_cache 0.13.0.0 → 0.14.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|