Commit | Line | Data |
---|---|---|
34e49164 C |
1 | open Common |
2 | ||
3 | open Oassoc | |
4 | ||
5 | open Oassocb | |
6 | open Osetb | |
7 | ||
0708f913 | 8 | (* Take care that must often redefine all function in the original |
ae4735db | 9 | * oassoc.ml because if some methods are not redefined, for instance |
91eba41f C |
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. | |
ae4735db | 15 | * |
0708f913 | 16 | * In the same way sometimes an exn can occur at weird time. When |
91eba41f C |
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. | |
ae4735db | 20 | * Also in the case of Out_of_memory, even if the entry is not |
91eba41f C |
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. | |
ae4735db | 25 | * |
0708f913 | 26 | * Cf also oassoc_cache.ml which can be even more efficient. |
34e49164 C |
27 | *) |
28 | ||
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 *) | |
ae4735db | 31 | class ['a,'b] oassoc_buffer max cached = |
34e49164 C |
32 | object(o) |
33 | inherit ['a,'b] oassoc | |
34 | ||
35 | val counter = ref 0 | |
ae4735db | 36 | val cache = ref (new oassocb []) |
34e49164 C |
37 | val dirty = ref (new osetb Setb.empty) |
38 | val wrapped = ref cached | |
39 | ||
ae4735db | 40 | method private myflush = |
91eba41f | 41 | |
ae4735db | 42 | let has_a_raised = ref false in |
91eba41f | 43 | |
ae4735db C |
44 | !dirty#iter (fun k -> |
45 | try | |
91eba41f | 46 | wrapped := !wrapped#add (k, !cache#assoc k) |
ae4735db | 47 | with Out_of_memory -> |
91eba41f C |
48 | pr2 "PBBBBBB: Out_of_memory in oassoc_buffer, but still empty cache"; |
49 | has_a_raised := true; | |
34e49164 C |
50 | ); |
51 | dirty := (new osetb Setb.empty); | |
52 | cache := (new oassocb []); | |
53 | counter := 0; | |
91eba41f C |
54 | if !has_a_raised then raise Out_of_memory |
55 | ||
ae4735db | 56 | |
34e49164 | 57 | method misc_op_hook2 = o#myflush |
ae4735db C |
58 | |
59 | method empty = | |
34e49164 | 60 | raise Todo |
ae4735db | 61 | |
91eba41f C |
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 | |
ae4735db | 64 | * still there, but dirty is a set, and in myflush we iter based |
91eba41f C |
65 | * on dirty so we will flush only the last 'k' in the cache. |
66 | *) | |
ae4735db | 67 | method add (k,v) = |
34e49164 C |
68 | cache := !cache#add (k,v); |
69 | dirty := !dirty#add k; | |
70 | incr counter; | |
71 | if !counter > max then o#myflush; | |
72 | o | |
73 | ||
ae4735db | 74 | method iter f = |
34e49164 C |
75 | o#myflush; (* bugfix: have to flush !!! *) |
76 | !wrapped#iter f | |
77 | ||
78 | ||
ae4735db | 79 | method keys = |
91eba41f C |
80 | o#myflush; (* bugfix: have to flush !!! *) |
81 | !wrapped#keys | |
82 | ||
ae4735db | 83 | method clear = |
91eba41f C |
84 | o#myflush; (* bugfix: have to flush !!! *) |
85 | !wrapped#clear | |
86 | ||
87 | ||
ae4735db | 88 | method length = |
34e49164 C |
89 | o#myflush; |
90 | !wrapped#length | |
91 | ||
ae4735db | 92 | method view = |
34e49164 C |
93 | raise Todo |
94 | ||
ae4735db C |
95 | method del (k,v) = |
96 | cache := !cache#del (k,v); | |
34e49164 | 97 | (* TODO as for delkey, do a try over wrapped *) |
ae4735db | 98 | wrapped := !wrapped#del (k,v); |
34e49164 C |
99 | dirty := !dirty#del k; |
100 | o | |
101 | method mem e = raise Todo | |
102 | method null = raise Todo | |
103 | ||
ae4735db C |
104 | method assoc k = |
105 | try !cache#assoc k | |
106 | with Not_found -> | |
34e49164 | 107 | (* may launch Not_found, but this time, dont catch it *) |
ae4735db | 108 | let v = !wrapped#assoc k in |
34e49164 C |
109 | begin |
110 | cache := !cache#add (k,v); | |
111 | (* otherwise can use too much mem *) | |
112 | incr counter; | |
113 | if !counter > max then o#myflush; | |
114 | v | |
115 | end | |
ae4735db C |
116 | |
117 | method delkey k = | |
118 | cache := !cache#delkey k; | |
34e49164 C |
119 | (* sometimes have not yet flushed, so may not be yet in, (could |
120 | * also flush in place of doing try). | |
ae4735db | 121 | * |
34e49164 C |
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 *) | |
ae4735db C |
125 | begin |
126 | try wrapped := !wrapped#delkey k | |
34e49164 C |
127 | with Not_found -> () |
128 | end; | |
129 | dirty := !dirty#del k; | |
130 | o | |
131 | ||
ae4735db | 132 | end |
34e49164 C |
133 | |
134 |