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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/entity_cache.rb +17 -15
  3. data/lib/entity_cache/controls.rb +12 -3
  4. data/lib/entity_cache/controls/entity.rb +27 -1
  5. data/lib/entity_cache/controls/persist_interval.rb +2 -22
  6. data/lib/entity_cache/controls/record.rb +33 -12
  7. data/lib/entity_cache/controls/storage/persistent.rb +8 -26
  8. data/lib/entity_cache/controls/storage/persistent/example.rb +41 -0
  9. data/lib/entity_cache/controls/storage/persistent/not_implemented.rb +19 -0
  10. data/lib/entity_cache/controls/storage/persistent/write.rb +25 -0
  11. data/lib/entity_cache/controls/storage/temporary.rb +14 -2
  12. data/lib/entity_cache/controls/subject.rb +2 -4
  13. data/lib/entity_cache/controls/time.rb +1 -12
  14. data/lib/entity_cache/controls/version.rb +5 -11
  15. data/lib/entity_cache/defaults.rb +2 -2
  16. data/lib/entity_cache/record.rb +36 -30
  17. data/lib/entity_cache/record/destructure.rb +29 -0
  18. data/lib/entity_cache/record/log_text.rb +9 -0
  19. data/lib/entity_cache/record/transformer.rb +26 -0
  20. data/lib/entity_cache/store/persistent/null.rb +15 -0
  21. data/lib/entity_cache/store/persistent/substitute.rb +64 -0
  22. data/lib/entity_cache/store/persistent/telemetry.rb +16 -0
  23. data/lib/entity_cache/store/temporary.rb +47 -0
  24. data/lib/entity_cache/store/temporary/build.rb +48 -0
  25. data/lib/entity_cache/store/temporary/build/defaults.rb +28 -0
  26. data/lib/entity_cache/{storage → store}/temporary/scope/exclusive.rb +1 -1
  27. data/lib/entity_cache/store/temporary/scope/global.rb +34 -0
  28. data/lib/entity_cache/store/temporary/scope/thread.rb +35 -0
  29. data/lib/entity_cache/store/temporary/substitute.rb +36 -0
  30. data/lib/entity_cache/substitute.rb +33 -17
  31. metadata +20 -58
  32. data/lib/entity_cache/entity_cache.rb +0 -83
  33. data/lib/entity_cache/error.rb +0 -3
  34. data/lib/entity_cache/storage/persistent.rb +0 -81
  35. data/lib/entity_cache/storage/persistent/none.rb +0 -15
  36. data/lib/entity_cache/storage/persistent/substitute.rb +0 -51
  37. data/lib/entity_cache/storage/persistent/telemetry.rb +0 -38
  38. data/lib/entity_cache/storage/temporary.rb +0 -56
  39. data/lib/entity_cache/storage/temporary/build.rb +0 -42
  40. data/lib/entity_cache/storage/temporary/scope/defaults.rb +0 -32
  41. data/lib/entity_cache/storage/temporary/scope/error.rb +0 -9
  42. data/lib/entity_cache/storage/temporary/scope/shared.rb +0 -31
@@ -1,44 +1,50 @@
1
1
  class EntityCache
2
- class Record < Struct.new(:id, :entity, :version, :time, :persisted_version, :persisted_time)
3
- def versions_since_persisted
4
- persisted_version = self.persisted_version
5
- persisted_version ||= -1
6
-
7
- version - persisted_version.to_i
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 destructure(includes=nil)
11
- return entity if includes.nil?
12
-
13
- responses = [entity]
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
- responses
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, Clock::UTC.now)
29
+ Clock::UTC.elapsed_milliseconds(time, clock.now)
32
30
  end
33
31
 
34
- module NoStream
35
- def self.destructure(includes=nil)
36
- record = Record.new
37
- record.destructure(includes)
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
- def self.version
41
- :no_stream
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,15 @@
1
+ class EntityCache
2
+ module Store
3
+ module Persistent
4
+ class Null
5
+ include Store::Persistent
6
+
7
+ def get(id)
8
+ end
9
+
10
+ def put(id, entity, version, time)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,16 @@
1
+ class EntityCache
2
+ module Store
3
+ module Persistent
4
+ module Telemetry
5
+ Data = Struct.new(:id, :entity, :version, :time)
6
+
7
+ class Sink
8
+ include ::Telemetry::Sink
9
+
10
+ record :put
11
+ record :get
12
+ end
13
+ end
14
+ end
15
+ end
16
+ 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
@@ -1,5 +1,5 @@
1
1
  class EntityCache
2
- module Storage
2
+ module Store
3
3
  class Temporary
4
4
  module Scope
5
5
  class Exclusive < Temporary
@@ -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