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
|
/*
This test exercises the CacheFileContextEvictor::WasEvicted API and code using it.
- We store 10+10 (pinned and non-pinned) entries to the cache, wait for them being written.
- Then we purge the memory pools.
- Now the IO thread is suspended on the EVICT (7) level to prevent actual deletion of the files.
- Index is disabled.
- We do clear() of the cache, this creates the "ce_*" file and posts to the EVICT level
the eviction loop mechanics.
- We open again those 10+10 entries previously stored.
- IO is resumed
- We expect to get all the pinned and
loose all the non-pinned (common) entries.
*/
"use strict";
const kENTRYCOUNT = 10;
function log_(msg) {
if (true) {
dump(">>>>>>>>>>>>> " + msg + "\n");
}
}
function run_test() {
do_get_profile();
var lci = Services.loadContextInfo.default;
var testingInterface = Services.cache2.QueryInterface(Ci.nsICacheTesting);
Assert.ok(testingInterface);
var mc = new MultipleCallbacks(
1,
function () {
// (2)
mc = new MultipleCallbacks(1, finish_cache2_test);
// Release all references to cache entries so that they can be purged
// Calling gc() four times is needed to force it to actually release
// entries that are obviously unreferenced. Yeah, I know, this is wacky...
gc();
gc();
executeSoon(() => {
gc();
gc();
log_("purging");
// Invokes cacheservice:purge-memory-pools when done.
Services.cache2.purgeFromMemory(
Ci.nsICacheStorageService.PURGE_EVERYTHING
); // goes to (3)
});
},
true
);
// (1), here we start
log_("first set of opens");
var i;
for (i = 0; i < kENTRYCOUNT; ++i) {
// Callbacks 1-20
mc.add();
asyncOpenCacheEntry(
"http://pinned" + i + "/",
"pin",
Ci.nsICacheStorage.OPEN_TRUNCATE,
lci,
new OpenCallback(NEW | WAITFORWRITE, "m" + i, "p" + i, function (entry) {
mc.fired();
})
);
mc.add();
asyncOpenCacheEntry(
"http://common" + i + "/",
"disk",
Ci.nsICacheStorage.OPEN_TRUNCATE,
lci,
new OpenCallback(NEW | WAITFORWRITE, "m" + i, "d" + i, function (entry) {
mc.fired();
})
);
}
mc.fired(); // Goes to (2)
Services.obs.addObserver(
{
observe(subject, topic, data) {
// (3)
log_("after purge");
// Prevent the I/O thread from evicting physically the data. We first want to re-open the entries.
// This deterministically emulates a slow hard drive.
testingInterface.suspendCacheIOThread(7);
log_("clearing");
// Now clear everything except pinned. Stores the "ce_*" file and schedules background eviction.
Services.cache2.clear();
log_("cleared");
log_("second set of opens");
// Now open again. Pinned entries should be there, disk entries should be the renewed entries.
// Callbacks 21-40
for (i = 0; i < kENTRYCOUNT; ++i) {
mc.add();
asyncOpenCacheEntry(
"http://pinned" + i + "/",
"disk",
Ci.nsICacheStorage.OPEN_NORMALLY,
lci,
new OpenCallback(NORMAL, "m" + i, "p" + i, function (entry) {
mc.fired();
})
);
mc.add();
asyncOpenCacheEntry(
"http://common" + i + "/",
"disk",
Ci.nsICacheStorage.OPEN_NORMALLY,
lci,
new OpenCallback(NEW, "m2" + i, "d2" + i, function (entry) {
mc.fired();
})
);
}
// Resume IO, this will just pop-off the CacheFileContextEvictor::EvictEntries() because of
// an early check on CacheIOThread::YieldAndRerun() in that method.
// CacheFileIOManager::OpenFileInternal should now run and CacheFileContextEvictor::WasEvicted
// should be checked on.
log_("resuming");
testingInterface.resumeCacheIOThread();
log_("resumed");
mc.fired(); // Finishes this test
},
},
"cacheservice:purge-memory-pools"
);
do_test_pending();
}
|