5
5
// Currently there are quite many code spread across
6
6
// DbFunctions, Db, Migrations, InMemoryStore modules which use codegen code directly.
7
7
8
- // The type reflects an effect cache table in the db
8
+ // The type reflects an cache table in the db
9
9
// It might be present even if the effect is not used in the application
10
- type effectCache = {
11
- name : string ,
10
+ type effectCacheRecord = {
11
+ effectName : string ,
12
12
// Number of rows in the table
13
- mutable size : int ,
14
- // Lazily attached table definition when effect is used in the application
15
- mutable table : option <Table .table >,
13
+ mutable count : int ,
16
14
}
17
15
18
16
type operator = [# ">" | # "=" ]
@@ -28,7 +26,6 @@ type storage = {
28
26
~generalTables : array <Table .table >= ?,
29
27
~enums : array <Internal .enumConfig <Internal .enum >>= ?,
30
28
) => promise <unit >,
31
- loadEffectCaches : unit => promise <array <effectCache >>,
32
29
@raises ("StorageError" )
33
30
loadByIdsOrThrow : 'item . (
34
31
~ids : array <string >,
@@ -50,14 +47,26 @@ type storage = {
50
47
~table : Table .table ,
51
48
~itemSchema : S .t <'item >,
52
49
) => promise <unit >,
50
+ @raises ("StorageError" )
51
+ setEffectCacheOrThrow : (
52
+ ~effect : Internal .effect ,
53
+ ~items : array <Internal .effectCacheItem >,
54
+ ~initialize : bool ,
55
+ ) => promise <unit >,
56
+ // This is to download cache from the database to .envio/cache
57
+ dumpEffectCache : unit => promise <unit >,
58
+ // This is not good, but the function does two things:
59
+ // - Gets info about existing cache tables
60
+ // - if withUpload is true, it also populates the cache from .envio/cache to the database
61
+ restoreEffectCache : (~withUpload : bool ) => promise <array <effectCacheRecord >>,
53
62
}
54
63
55
64
exception StorageError ({message : string , reason : exn })
56
65
57
66
type storageStatus =
58
67
| Unknown
59
68
| Initializing (promise <unit >)
60
- | Ready ({cleanRun : bool , effectCaches : dict <effectCache >})
69
+ | Ready ({cleanRun : bool , cache : dict <effectCacheRecord >})
61
70
62
71
type t = {
63
72
userEntities : array <Internal .entityConfig >,
@@ -66,7 +75,6 @@ type t = {
66
75
allEnums : array <Internal .enumConfig <Internal .enum >>,
67
76
mutable storageStatus : storageStatus ,
68
77
storage : storage ,
69
- onStorageInitialize : option <unit => promise <unit >>,
70
78
}
71
79
72
80
let entityHistoryActionEnumConfig : Internal .enumConfig <EntityHistory .RowAction .t > = {
@@ -83,7 +91,6 @@ let make = (
83
91
~allEnums ,
84
92
~staticTables ,
85
93
~storage ,
86
- ~onStorageInitialize = ?,
87
94
) => {
88
95
let allEntities = userEntities -> Js .Array2 .concat ([dcRegistryEntityConfig ])
89
96
let allEnums =
@@ -95,62 +102,70 @@ let make = (
95
102
allEnums ,
96
103
storageStatus : Unknown ,
97
104
storage ,
98
- onStorageInitialize ,
99
105
}
100
106
}
101
107
102
- let init = async (persistence , ~reset = false ) => {
103
- try {
104
- let shouldRun = switch persistence .storageStatus {
105
- | Unknown => true
106
- | Initializing (promise ) => {
107
- await promise
108
- reset
109
- }
110
- | Ready (_ ) => reset
111
- }
112
- if shouldRun {
113
- let resolveRef = ref (%raw (` null ` ) )
114
- let promise = Promise .make ((resolve , _ ) => {
115
- resolveRef := resolve
116
- })
117
- persistence .storageStatus = Initializing (promise )
118
- if reset || ! (await persistence .storage .isInitialized ()) {
119
- let _ = await persistence .storage .initialize (
120
- ~entities = persistence .allEntities ,
121
- ~generalTables = persistence .staticTables ,
122
- ~enums = persistence .allEnums ,
123
- )
108
+ let init = {
109
+ let loadInitialCache = async (persistence , ~withUpload ) => {
110
+ let effectCacheRecords = await persistence .storage .restoreEffectCache (~withUpload )
111
+ let cache = Js .Dict .empty ()
112
+ effectCacheRecords -> Js .Array2 .forEach (record => {
113
+ Prometheus .EffectCacheCount .set (~count = record .count , ~effectName = record .effectName )
114
+ cache -> Js .Dict .set (record .effectName , record )
115
+ })
116
+ cache
117
+ }
124
118
125
- persistence . storageStatus = Ready ( {
126
- cleanRun : true ,
127
- effectCaches : Js . Dict . empty (),
128
- })
129
- switch persistence . onStorageInitialize {
130
- | Some ( onStorageInitialize ) => await onStorageInitialize ()
131
- | None => ()
119
+ async ( persistence , ~ reset = false ) => {
120
+ try {
121
+ let shouldRun = switch persistence . storageStatus {
122
+ | Unknown => true
123
+ | Initializing ( promise ) => {
124
+ await promise
125
+ reset
132
126
}
133
- } else if (
134
- // In case of a race condition,
135
- // we want to set the initial status to Ready only once.
136
- switch persistence .storageStatus {
137
- | Initializing (_ ) => true
138
- | _ => false
139
- }
140
- ) {
141
- let effectCaches = Js .Dict .empty ()
142
- (await persistence .storage .loadEffectCaches ())-> Js .Array2 .forEach (effectCache => {
143
- effectCaches -> Js .Dict .set (effectCache .name , effectCache )
144
- })
145
- persistence .storageStatus = Ready ({
146
- cleanRun : false ,
147
- effectCaches ,
127
+ | Ready (_ ) => reset
128
+ }
129
+ if shouldRun {
130
+ let resolveRef = ref (%raw (` null ` ) )
131
+ let promise = Promise .make ((resolve , _ ) => {
132
+ resolveRef := resolve
148
133
})
134
+ persistence .storageStatus = Initializing (promise )
135
+ if reset || ! (await persistence .storage .isInitialized ()) {
136
+ Logging .info (` Initializing the indexer storage...` )
137
+
138
+ await persistence .storage .initialize (
139
+ ~entities = persistence .allEntities ,
140
+ ~generalTables = persistence .staticTables ,
141
+ ~enums = persistence .allEnums ,
142
+ )
143
+
144
+ Logging .info (` The indexer storage is ready. Uploading cache...` )
145
+ persistence .storageStatus = Ready ({
146
+ cleanRun : true ,
147
+ cache : await loadInitialCache (persistence , ~withUpload = true ),
148
+ })
149
+ } else if (
150
+ // In case of a race condition,
151
+ // we want to set the initial status to Ready only once.
152
+ switch persistence .storageStatus {
153
+ | Initializing (_ ) => true
154
+ | _ => false
155
+ }
156
+ ) {
157
+ Logging .info (` The indexer storage is ready.` )
158
+ persistence .storageStatus = Ready ({
159
+ cleanRun : false ,
160
+ cache : await loadInitialCache (persistence , ~withUpload = false ),
161
+ })
162
+ }
163
+ resolveRef .contents ()
149
164
}
150
- resolveRef .contents ()
165
+ } catch {
166
+ | exn =>
167
+ exn -> ErrorHandling .mkLogAndRaise (~msg = ` EE800: Failed to initialize the indexer storage.` )
151
168
}
152
- } catch {
153
- | exn => exn -> ErrorHandling .mkLogAndRaise (~msg = ` EE800: Failed to initialize the indexer storage.` )
154
169
}
155
170
}
156
171
@@ -162,3 +177,27 @@ let getInitializedStorageOrThrow = persistence => {
162
177
| Ready (_ ) => persistence .storage
163
178
}
164
179
}
180
+
181
+ let setEffectCacheOrThrow = async (persistence , ~effect : Internal .effect , ~items ) => {
182
+ switch persistence .storageStatus {
183
+ | Unknown
184
+ | Initializing (_ ) =>
185
+ Js .Exn .raiseError (` Failed to access the indexer storage. The Persistence layer is not initialized.` )
186
+ | Ready ({cache }) => {
187
+ let storage = persistence .storage
188
+ let effectName = effect .name
189
+ let effectCacheRecord = switch cache -> Utils .Dict .dangerouslyGetNonOption (effectName ) {
190
+ | Some (c ) => c
191
+ | None => {
192
+ let c = {effectName , count : 0 }
193
+ cache -> Js .Dict .set (effectName , c )
194
+ c
195
+ }
196
+ }
197
+ let initialize = effectCacheRecord .count === 0
198
+ await storage .setEffectCacheOrThrow (~effect , ~items , ~initialize )
199
+ effectCacheRecord .count = effectCacheRecord .count + items -> Js .Array2 .length
200
+ Prometheus .EffectCacheCount .set (~count = effectCacheRecord .count , ~effectName )
201
+ }
202
+ }
203
+ }
0 commit comments