delegate_writer.anubis
7.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
Holder : Matthieu Herrmann
Author : The Saunders Team
Creation : 2014/05/12
Last update : 2014/05/26 11:18 by matthieu@embryo (inserted by vim).
=======================================================================================================================
Overview:
When performing multiple change on a buffer, we may want to limit the amount of write, e.g. when writing on disk.
This library allows to do so, starting a counter when the first "save" command is issued, actyally writing the data
at the end of the allocated time. Meanwhile, the data to be written can be altered.
Note: This library only works with filename.
You need an handler for your "Asynchronous Data", i.e. an opaque type making the bridge between your data and
the file to write.
public type AData($D):...
You can get a type with this function:
* prefx is a prefix prepended to the filename. Use "" if you do not need one.
* time_wait is the delay before writing the first save when the state is synchronised.
* time_poll is the polling time while waiting for the actual writing to end (when the data are really begin written).
public define AData($D) make_AData(
String prefx, // A prefix
String filename, // Your filename
($D, String) -> SaveResult writing_fun, // Your writing function: the filename is passed as a parameter.
Int time_wait, // synchronisation time, in ms
Word32 time_poll // Polling time, in ms
).
Same as above with empty prefix, 10 seconds for time_wait an 50ms for time_poll
public define AData($D) make_AData(
String filename, // Your filename
($D, String) -> SaveResult writing_fun // Your writing function: the filename is passed as a parameter.
).
Write the data on the handler.
Note: the data must be "complete", i.e. when two "save" are called, only the data from the last one will
actually be written !
public define One save($D d, AData($D) ad).
You can set a prefix. Be sure to flush your data before using this function !
public define One set_prefix(String prfx, AData($D) ad).
Force writing (do not wait, stop waiting).
public define One flush(AData($D) ad).
======================================================================================================================
= Private part =======================================================================================================
======================================================================================================================
read tools/basis.anubis // Needed for "sleep"
*** [1] Type definitions
==================================================================================================================
This type allows to control the writing of the data:
type SynchroState($D):
synchronised, // Data are written
unsynchronised($D data), // Data are waiting for a write
synchronising($D data). // Data are being written on the disk
The "Asynchronous Data" handler type
public type AData($D):
adata(
Var(String) prex, // Prefix for your file
String filename, // The filename
($D, String) -> SaveResult writing_fun, // The writing function
Var(SynchroState($D)) state_v, // The synchronisation state, holding the data.
Int time_wait, // Waiting time before write
Word32 time_poll // Polling time while writing
).
*** [2] Internal tools/functions
==================================================================================================================
define One wait_for_end_of_synchronisation(AData($D) ad) =
if ad is adata(_, _, _, state_v, _, tp) then
checking every tp millisecond,
wait for (if *state_v is synchronising(_) then false else true)
then unique.
"try_save" use "protect" and hence can not be recursive (auto-deadlock). It returns "false" on error.
define Bool try_save(AData($D) ad) =
if ad is adata(prefx, filename, wf, state_v, tw, _) then
sleep(tw);
protect(
if *state_v is
{
synchronised then should_not_happen(true)
unsynchronised(data) then
with path = if *prefx = "" then filename else *prefx + "/" + filename,
state_v <- synchronising(data);
if wf(data, path) is
{
cannot_open_file then
state_v <- unsynchronised(data);
println("Error: can not open file: " + filename + ". Trying again in "+tw+"ms.");
false
write_error then
state_v <- unsynchronised(data);
println("Error: can not write file: " + filename + ". Trying again in "+tw+"ms.");
false
ok then state_v <- synchronised; true
}
synchronising(_) then true
}
).
"delayed_save" uses "try_save" to perform the saving. If "false" is returned, it call itsel again (and again).
The waiting is done in "try_save".
define One delayed_save(AData($D) ad) =
if try_save(ad)
then unique // delegated machine will stop here
else delayed_save(ad). // Try again on error
*** [3] Interface implementation
==================================================================================================================
public define AData($D) make_AData(
String prefx,
String filename,
($D, String) -> SaveResult writing_fun,
Int time_wait,
Word32 time_poll
) = adata(var(prefx), filename, writing_fun, var(synchronised), time_wait, time_poll).
public define AData($D) make_AData(
String filename,
($D, String) -> SaveResult writing_fun
) = make_AData("", filename, writing_fun, 10000, 50).
public define One save($D d, AData($D) ad) =
if ad is adata(_, _, _, state_v, _, tp) then
if * state_v is
{
synchronised then protect(
state_v <- unsynchronised(d);
delegate delayed_save(ad),
unique
)
// Update the data to be written
unsynchronised(_) then protect state_v <- unsynchronised(d)
// Wait for end of current sync, relaunch save.
synchronising(_) then wait_for_end_of_synchronisation(ad); save(d, ad)
}
.
public define One flush(AData($D) ad) =
if ad is adata(prefx, filename, wf, state_v, _, _) then
if * state_v is
{
synchronised then unique
// Force the writing
unsynchronised(data) then protect(
with path = if *prefx = "" then filename else *prefx + "/" + filename,
state_v <- synchronising(data);
if wf(data, path) is
{
cannot_open_file then
state_v <- unsynchronised(data);
println("Error: can not open file: " + filename + ".")
write_error then
state_v <- unsynchronised(data);
println("Error: can not write file: " + filename + ".")
ok then state_v <- synchronised
}
)
// Wait for end of current sync
synchronising(_) then wait_for_end_of_synchronisation(ad)
}
.
public define One set_prefix(String prfx, AData($D) ad) = if ad is adata(prefx_v,_,_,_,_,_) then prefx_v <- prfx.