Skip to content

Commit 5607dfc

Browse files
authored
Merge pull request #55 from Shpaky/v2.3.0
V2.3.0
2 parents c0009a3 + 66368af commit 5607dfc

File tree

6 files changed

+151
-49
lines changed

6 files changed

+151
-49
lines changed

README.md

+47-15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Note that the implementation of algorithm support two interaction modes:
3131

3232
But actually nothing forbidens to interact in both modes at same time.
3333

34+
Both types of interface developed to IPACR (Interaction Protocol of Algorithms Cache Replacement) conformance.
35+
3436

3537
##### note №2:
3638
Note that the implementation of algorithm stores keys in binary, that is, for set of keys from the first example bellow key will be stored as in second example:
@@ -187,14 +189,16 @@ max key size
187189
internal - erlang interface for inner interaction in Erlang node
188190
external - outside interface for interaction from the world outside
189191

192+
###### Both types of interface developed to IPACR (Interaction Protocol of Algorithms Cache Replacement) conformance.
193+
190194
#### put key
191195
###### internal:
192196

193197
lfu:point(K).
194198

195199
###### external:
196200

197-
POINT:key %% "OK"
201+
POINT:key %% "OK"
198202

199203
#### get counter on key
200204
###### internal:
@@ -203,7 +207,7 @@ max key size
203207

204208
###### external:
205209

206-
COUNT:key %% "NUMBER"
210+
COUNT:key %% "NUMBER"
207211

208212
#### get offset counter and counter all keys
209213
###### internal:
@@ -212,7 +216,7 @@ max key size
212216

213217
###### external:
214218

215-
STATE %% JSON: "{O:NUMBER,Q:NUMBER}"
219+
STATE %% JSON: "{O:NUMBER,Q:NUMBER}"
216220

217221
#### store algorithm state to disk
218222
###### Please pay attantion, 'store' call executes asynchronously!
@@ -222,7 +226,7 @@ max key size
222226

223227
###### external:
224228

225-
STORE %% "OK"
229+
STORE %% "OK"
226230

227231
#### execute scoring of offset counter
228232
###### internal:
@@ -231,53 +235,81 @@ max key size
231235

232236
###### external:
233237

234-
SCORE %% "READY"
238+
SCORE %% "READY"
235239

236240
#### execute scoring of offset counter and get keys by it into internal table
237241
###### internal:
238242
###### Please pay attantion, that exist of internal table expires after following request to fetching 'fetch/0' or to clean 'clean/0'!
239243

240-
T = lfu:fetch(). %% tid()
244+
T = lfu:fetch(). %% tid()
241245
ets:tab2list(T).
242246

243247
###### external:
244248

245-
FETCH %% JSON: "[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]"
249+
FETCH %% JSON: "[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]"
246250

247251
#### execute scoring of offset counter and get keys by it into external table
248252
###### Please pay attantion, that it`s preferably using interface with internal table 'fetch/0', because it ensures a data consistency with your system!
249253
###### internal:
250254

251-
T = ets:new(stub,[ %% tid()
255+
T = ets:new(stub,[ %% tid()
252256
bag,public,{write_concurrency,true},
253257
{decentralized_counters,true}
254258
]).
255259
lfu:fetch(T).
256260
ets:tab2list(T).
257261

258-
#### execute scoring of offset counter and get keys by it into internal table for follow delete
262+
#### execute scoring of offset counter and get keys by it into internal table for follow delete (support both interaction types)
263+
##### without confirm
264+
###### internal:
265+
###### Please pay attantion, that exist of internal table expires after following request to fetching 'fetch/0' or to clean 'clean/0'!
266+
267+
T = lfu:clean(). %% tid()
268+
or
269+
T = lfu:clean(async). %% tid()
270+
271+
###### external:
272+
273+
CLEAN %% JSON: "[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]"
274+
or
275+
CLEAN:ASYNC %% JSON: "[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]"
276+
277+
##### with confirm
259278
###### internal:
260279
###### Please pay attantion, that exist of internal table expires after following request to fetching 'fetch/0' or to clean 'clean/0'!
261280

262-
{T,R} = lfu:clean(). %% {tid(),ref()}
281+
{T,R} = lfu:clean(sync). %% {tid(),ref()}
263282
lfu:clean(R,T).
264283

265284
###### external:
266285

267-
CLEAN %% JSON: "{[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]:UNIQ_REF}"
268-
CLEAN:UNIQ_REF %% OK
286+
CLEAN:SYNC %% JSON: "{[{number1:[key1,key2,key3]},{number2:[key1,key2,key3]},{number3:[key1,key2,key3]},...]:UNIQ_REF}"
287+
CLEAN:UNIQ_REF %% OK
269288

270-
#### execute scoring of offset counter and get keys by it into external table for follow delete
289+
#### execute scoring of offset counter and get keys by it into external table for follow delete (support only internal interaction type)
271290
###### Please pay attantion, that it`s preferably using interface with internal table 'clean/0', because it ensures a data consistency with your system!
291+
##### without confirm
292+
###### internal:
293+
294+
T = ets:new(stub,[ %% tid()
295+
bag,public,{write_concurrency,true},
296+
{decentralized_counters,true}
297+
]).
298+
T = lfu:clean(T). %% ref()
299+
or
300+
T = lfu:clean(async,T). %% ref()
301+
302+
##### with confirm
272303
###### internal:
273304

274-
T = ets:new(stub,[ %% tid()
305+
T = ets:new(stub,[ %% tid()
275306
bag,public,{write_concurrency,true},
276307
{decentralized_counters,true}
277308
]).
278-
R = lfu:clean(T). %% ref()
309+
{T,R} = lfu:clean(sync,T). %% ref()
279310
lfu:clean(R,T).
280311

312+
281313
#### put list keys with conters
282314
###### initialization of state, for example, transfer of state from other implementation 'lfu'
283315
###### internal:

lfu.app

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{application,lfu,[
22
{description,"Least Frequently Used Algorithm"},
3-
{vsn,"2.2.2"},
3+
{vsn,"2.3.0"},
44
{modules,[
55
lfu_app,lfu_sup,lfu,
66
lfu_score_sups_sup,lfu_protocol,

priv/lfu.rel

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
{crypto,"4.8"},
1010
{public_key,"1.9"},
1111
{asn1,"5.0.14"},
12-
{lfu, "2.2.2"}]
12+
{lfu, "2.3.0"}]
1313
}.

priv/lfu.tar.gz

1.42 KB
Binary file not shown.

src/lfu.erl

+55-29
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,22 @@ score() ->
102102
gen_statem:call(?MODULE,score).
103103
fetch() ->
104104
gen_statem:call(?MODULE,fetch).
105-
clean() ->
106-
gen_statem:call(?MODULE,clean).
107105
fetch(T) ->
108106
gen_statem:call(?MODULE,{fetch,T}).
107+
clean() ->
108+
gen_statem:call(?MODULE,{clean,async}).
109+
clean(async) ->
110+
gen_statem:call(?MODULE,{clean,async});
111+
clean(sync) ->
112+
gen_statem:call(?MODULE,{clean,sync});
109113
clean(T) ->
110-
gen_statem:call(?MODULE,{clean,T}).
114+
gen_statem:call(?MODULE,{clean,{async,T}}).
115+
clean(async,T) ->
116+
gen_statem:call(?MODULE,{clean,{async,T}});
117+
clean(sync,T) ->
118+
gen_statem:call(?MODULE,{clean,{sync,T}});
119+
clean(R,T) ->
120+
gen_statem:cast(?MODULE,{{clean,R},T}).
111121

112122
reset(D) ->
113123
gen_statem:cast(?MODULE,{reset,D}).
@@ -116,8 +126,6 @@ score(R,C) ->
116126
gen_statem:cast(?MODULE,{{score,R},C}).
117127
fetch(R,C) ->
118128
gen_statem:cast(?MODULE,{{fetch,R},C}).
119-
clean(R,T) ->
120-
gen_statem:cast(?MODULE,{{clean,R},T}).
121129

122130

123131
common(cast,{point,K},[O,Q]) ->
@@ -323,13 +331,18 @@ common({call,From},score,[O,Q]) ->
323331
common({call,From},fetch,[O,Q]) ->
324332
T = lfu_utils:ets_create(),
325333
{next_state,offset,[O,Q,#{from => From, tid => T, ets => internal, order => fetch}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
326-
common({call,From},clean,[O,Q]) ->
327-
T = lfu_utils:ets_create(),
328-
{next_state,offset,[O,Q,#{from => From, tid => T, ets => internal, order => clean}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
329334
common({call,From},{fetch,T},[O,Q]) ->
330335
{next_state,offset,[O,Q,#{from => From, tid => T, ets => external, order => fetch}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
331-
common({call,From},{clean,T},[O,Q]) ->
332-
{next_state,offset,[O,Q,#{from => From, tid => T, ets => external, order => clean}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
336+
common({call,From},{clean,async},[O,Q]) ->
337+
T = lfu_utils:ets_create(),
338+
{next_state,offset,[O,Q,#{from => From, tid => T, ets => internal, order => clean, mode => async}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
339+
common({call,From},{clean,sync},[O,Q]) ->
340+
T = lfu_utils:ets_create(),
341+
{next_state,offset,[O,Q,#{from => From, tid => T, ets => internal, order => clean, mode => sync}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
342+
common({call,From},{clean,{async,T}},[O,Q]) ->
343+
{next_state,offset,[O,Q,#{from => From, tid => T, ets => external, order => clean, mode => async}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
344+
common({call,From},{clean,{sync,T}},[O,Q]) ->
345+
{next_state,offset,[O,Q,#{from => From, tid => T, ets => external, order => clean, mode => sync}],[{next_event,internal,{score,{previous,{?SCORE_OFFSET,O}}}}]};
333346
common(cast,{reset,D},[O,Q]) ->
334347
NQ = resetting(D,Q),
335348
{keep_state,[O,NQ]};
@@ -404,7 +417,7 @@ offset(internal,count,[O,Q,#{previous := P, current := C, following := F, from :
404417
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => fetch}],[{next_event,internal,fetch}]};
405418
Order =:= clean ->
406419
%% idle iteration but necessary
407-
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => clean}],[{next_event,internal,fetch}]}
420+
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => clean, mode => maps:get(mode,MD)}],[{next_event,internal,fetch}]}
408421
end;
409422
C / Q * 100 < ?MIN_OFFSET andalso O*10 =< ?MAX_ORDER andalso F / Q * 100 =< ?MAX_OFFSET ->
410423
{keep_state,[O*10,Q,MD#{previous => C, current => F, following => 0}],[{next_event,internal,{score,{following,{O*100,O*1000}}}}]};
@@ -417,7 +430,7 @@ offset(internal,count,[O,Q,#{previous := P, current := C, following := F, from :
417430
Order =:= fetch ->
418431
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => fetch}],[{next_event,internal,fetch}]};
419432
Order =:= clean ->
420-
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => clean}],[{next_event,internal,fetch}]}
433+
{next_state,select,[O,Q,#{from => From, tid => maps:get(tid,MD), ets => maps:get(ets,MD), order => clean, mode => maps:get(mode,MD)}],[{next_event,internal,fetch}]}
421434
end
422435
end;
423436
offset(cast,{{score,_},_S},_StateData) ->
@@ -440,11 +453,9 @@ offset({call,_From},score,_StateData) ->
440453
{keep_state_and_data,[postpone]};
441454
offset({call,_From},fetch,_StateData) ->
442455
{keep_state_and_data,[postpone]};
443-
offset({call,_From},clean,_StateData) ->
444-
{keep_state_and_data,[postpone]};
445456
offset({call,_From},{fetch,_T},_StateData) ->
446457
{keep_state_and_data,[postpone]};
447-
offset({call,_From},{clean,_T},_StateData) ->
458+
offset({call,_From},{clean,_D},_StateData) -> %% _D = {async,tid()} || {sync,tid()} || async || sync
448459
{keep_state_and_data,[postpone]};
449460
offset(cast,{reset,_T},_StateData) ->
450461
{keep_state_and_data,[postpone]};
@@ -465,24 +476,34 @@ select(internal,fetch,[O,Q,#{tid := T} = MD]) ->
465476
true ->
466477
{keep_state,[O,Q,MD#{number => N, ref => R}],[{state_timeout,0,T}]}
467478
end;
468-
select(state_timeout,T,[O,Q,#{tid := T, from := From, order := Order, ets := internal} = _MD]) ->
479+
select(state_timeout,T,[O,Q,#{tid := T, from := From, order := Order, ets := internal} = MD]) ->
469480
% io:format("TimeoutState:~p~nMD:~p~nO:~p~nQ~p~n~n",[select,MD,O,Q]),
470481
NT = lfu_utils:ets_re_create(),
471482
if
472483
Order =:= fetch ->
473484
{next_state,common,[O,Q],[{reply,From,NT}]};
474485
Order =:= clean ->
475-
R1 = make_ref(),
476-
{next_state,delete,[O,Q,#{tid => NT, ref => R1}],[{reply,From,{NT,R1}},{state_timeout,?TIMEOUT_STATE_DELETE,NT}]}
486+
case maps:get(mode,MD) of
487+
async ->
488+
{next_state,delete,[O,Q,#{tid => NT, from => From}],[{next_event,internal,clean}]};
489+
sync ->
490+
R = make_ref(),
491+
{next_state,delete,[O,Q,#{tid => NT, ref => R}],[{reply,From,{NT,R}},{state_timeout,?TIMEOUT_STATE_DELETE,NT}]}
492+
end
477493
end;
478-
select(state_timeout,T,[O,Q,#{tid := T, from := From, order := Order, ets := external} = _MD]) ->
494+
select(state_timeout,T,[O,Q,#{tid := T, from := From, order := Order, ets := external} = MD]) ->
479495
% io:format("TimeoutState:~p~nMD:~p~nO:~p~nQ~p~n~n",[select,MD,O,Q]),
480496
if
481497
Order =:= fetch ->
482498
{next_state,common,[O,Q],[{reply,From,T}]};
483499
Order =:= clean ->
484-
R1 = make_ref(),
485-
{next_state,delete,[O,Q,#{tid => T, ref => R1}],[{reply,From,{T,R1}},{state_timeout,?TIMEOUT_STATE_DELETE,T}]}
500+
case maps:get(mode,MD) of
501+
async ->
502+
{next_state,delete,[O,Q,#{tid => T, from => From}],[{next_event,internal,clean}]};
503+
sync ->
504+
R = make_ref(),
505+
{next_state,delete,[O,Q,#{tid => T, ref => R}],[{reply,From,{T,R}},{state_timeout,?TIMEOUT_STATE_DELETE,T}]}
506+
end
486507
end;
487508
select(cast,{{fetch,R},ready},[O,Q,#{number := N, tid := T, from := From, order := Order, ref := R} = MD]) ->
488509
if
@@ -493,8 +514,13 @@ select(cast,{{fetch,R},ready},[O,Q,#{number := N, tid := T, from := From, order
493514
Order =:= fetch ->
494515
{next_state,common,[O,Q],[{reply,From,T}]};
495516
Order =:= clean ->
496-
R1 = make_ref(),
497-
{next_state,delete,[O,Q,#{tid => T, ref => R1}],[{reply,From,{T,R1}},{state_timeout,?TIMEOUT_STATE_DELETE,T}]}
517+
case maps:get(mode,MD) of
518+
async ->
519+
{next_state,delete,[O,Q,#{tid => T, from => From}],[{next_event,internal,clean}]};
520+
sync ->
521+
R1 = make_ref(),
522+
{next_state,delete,[O,Q,#{tid => T, ref => R1}],[{reply,From,{T,R1}},{state_timeout,?TIMEOUT_STATE_DELETE,T}]}
523+
end
498524
end
499525
end;
500526
select(cast,{{fetch,_R},ready},_StateData) ->
@@ -517,11 +543,9 @@ select({call,_From},score,_StateData) ->
517543
{keep_state_and_data,[postpone]};
518544
select({call,_From},fetch,_StateData) ->
519545
{keep_state_and_data,[postpone]};
520-
select({call,_From},clean,_StateData) ->
521-
{keep_state_and_data,[postpone]};
522546
select({call,_From},{fetch,_T},_StateData) ->
523547
{keep_state_and_data,[postpone]};
524-
select({call,_From},{clean,_T},_StateData) ->
548+
select({call,_From},{clean,_D},_StateData) -> %% _D = {async,tid()} || {sync,tid()} || async || sync
525549
{keep_state_and_data,[postpone]};
526550
select(cast,{reset,_T},_StateData) ->
527551
{keep_state_and_data,[postpone]};
@@ -532,6 +556,10 @@ select({call,_From},_EventContent,_StateData) ->
532556
select(info,_EventContent,_StateData) ->
533557
keep_state_and_data.
534558

559+
delete(internal,clean,[O,Q,#{tid := T, from := From}]) ->
560+
NQ = resetting(T,Q),
561+
?SUPPORT andalso erlang:apply(?AUXILIARY,reset,[T]),
562+
{next_state,common,[O,NQ],[{reply,From,T}]};
535563
delete(state_timeout,T,[O,Q,#{tid := T, ref := _R}]) ->
536564
% io:format("TimeoutState:~p~nT:~p~nO:~p~nQ~p~n~n",[delete,T,O,Q]),
537565
{next_state,common,[O,Q]};
@@ -559,11 +587,9 @@ delete({call,_From},score,_StateData) ->
559587
{keep_state_and_data,[postpone]};
560588
delete({call,_From},fetch,_StateData) ->
561589
{keep_state_and_data,[postpone]};
562-
delete({call,_From},clean,_StateData) ->
563-
{keep_state_and_data,[postpone]};
564590
delete({call,_From},{fetch,_T},_StateData) ->
565591
{keep_state_and_data,[postpone]};
566-
delete({call,_From},{clean,_T},_StateData) ->
592+
delete({call,_From},{clean,_D},_StateData) -> %% _D = {async,tid()} || {sync,tid()} || async || sync
567593
{keep_state_and_data,[postpone]};
568594
delete(cast,{reset,_T},_StateData) ->
569595
{keep_state_and_data,[postpone]};

0 commit comments

Comments
 (0)