8 (* Take care that must often redefine all function in the original
9 * oassoc.ml because if some methods are not redefined, for instance
10 * #clear, then if do wrapper over a oassocdbm, then even if oassocdbm
11 * redefine #clear, it will not be called, but instead the default
12 * method will be called that internally will call another method.
13 * So better delegate all the methods and override even the method
14 * with a default definition.
16 * In the same way sometimes an exn can occur at weird time. When
17 * we add an element, sometimes this may raise an exn such as Out_of_memory,
18 * but as we dont add directly but only at flush time, the exn
19 * may happen far later the user added something in this oassoc.
20 * Also in the case of Out_of_memory, even if the entry is not
21 * added in the wrapped, it will still be present in the cache
22 * and so the next flush will still generate an exn that again
23 * may not be cached. So for the moment if Out_of_memory then
24 * do something special and erase the entry in the cache.
26 * Cf also oassoc_cache.ml which can be even more efficient.
29 (* !!take care!!: this class has side effect, not a pure oassoc *)
30 (* can not make it pure, cos the assoc have side effect on the cache *)
31 class ['a
,'b
] oassoc_buffer max cached
=
33 inherit ['a
,'b
] oassoc
36 val cache
= ref (new oassocb
[])
37 val dirty
= ref (new osetb
Setb.empty
)
38 val wrapped
= ref cached
40 method private myflush
=
42 let has_a_raised = ref false in
46 wrapped
:= !wrapped#add
(k
, !cache#assoc k
)
48 pr2
"PBBBBBB: Out_of_memory in oassoc_buffer, but still empty cache";
51 dirty
:= (new osetb
Setb.empty
);
52 cache
:= (new oassocb
[]);
54 if !has_a_raised then raise Out_of_memory
57 method misc_op_hook2
= o#myflush
62 (* what happens in k is already present ? or if add multiple times
63 * the same k ? cache is a oassocb and so the previous binding is
64 * still there, but dirty is a set, and in myflush we iter based
65 * on dirty so we will flush only the last 'k' in the cache.
68 cache
:= !cache#add
(k
,v
);
69 dirty
:= !dirty#add k
;
71 if !counter
> max
then o#myflush
;
75 o#myflush
; (* bugfix: have to flush !!! *)
80 o#myflush
; (* bugfix: have to flush !!! *)
84 o#myflush
; (* bugfix: have to flush !!! *)
96 cache
:= !cache#del
(k
,v
);
97 (* TODO as for delkey, do a try over wrapped *)
98 wrapped
:= !wrapped#del
(k
,v
);
99 dirty
:= !dirty#del k
;
101 method mem e
= raise Todo
102 method null
= raise Todo
107 (* may launch Not_found, but this time, dont catch it *)
108 let v = !wrapped#assoc k
in
110 cache
:= !cache#add
(k
,v);
111 (* otherwise can use too much mem *)
113 if !counter
> max
then o#myflush
;
118 cache
:= !cache#delkey k
;
119 (* sometimes have not yet flushed, so may not be yet in, (could
120 * also flush in place of doing try).
122 * TODO would be better to see if was in cache (in case mean that
123 * perhaps not flushed and do try and in other case just cos del
124 * (without try) cos forcement flushed ou was an error *)
126 try wrapped
:= !wrapped#delkey k
129 dirty
:= !dirty#del k
;