]>
Commit | Line | Data |
---|---|---|
9cef6668 | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
9cef6668 | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
9cef6668 | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 20 Storage Manager Swapout Functions */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
aa839030 | 12 | #include "cbdata.h" |
af69c635 | 13 | #include "globals.h" |
e6ccf245 | 14 | #include "Store.h" |
602d9612 | 15 | #include "StoreClient.h" |
528b2c61 | 16 | /* FIXME: Abstract the use of this more */ |
17 | #include "mem_node.h" | |
18 | #include "MemObject.h" | |
4d5904f7 | 19 | #include "SquidConfig.h" |
e4f1fdae | 20 | #include "StatCounters.h" |
10818c0a | 21 | #include "store_log.h" |
4b981814 | 22 | #include "swap_log_op.h" |
602d9612 | 23 | #include "SwapDir.h" |
f09f5b26 | 24 | |
d54f0ab3 | 25 | static void storeSwapOutStart(StoreEntry * e); |
4fcc8876 | 26 | static StoreIOState::STIOCB storeSwapOutFileClosed; |
27 | static StoreIOState::STFNCB storeSwapOutFileNotify; | |
f09f5b26 | 28 | |
daacd51f AJ |
29 | // wrapper to cross C/C++ ABI boundary. xfree is extern "C" for libraries. |
30 | static void xfree_cppwrapper(void *x) | |
31 | { | |
32 | xfree(x); | |
33 | } | |
34 | ||
f09f5b26 | 35 | /* start swapping object to disk */ |
d54f0ab3 | 36 | static void |
f09f5b26 | 37 | storeSwapOutStart(StoreEntry * e) |
38 | { | |
2391a162 | 39 | MemObject *mem = e->mem_obj; |
d3b3ab85 | 40 | StoreIOState::Pointer sio; |
2391a162 | 41 | assert(mem); |
cd748f27 | 42 | /* Build the swap metadata, so the filesystem will know how much |
43 | * metadata there is to store | |
44 | */ | |
26ac0430 AJ |
45 | debugs(20, 5, "storeSwapOutStart: Begin SwapOut '" << e->url() << "' to dirno " << |
46 | e->swap_dirn << ", fileno " << std::hex << std::setw(8) << std::setfill('0') << | |
bf8fe701 | 47 | std::uppercase << e->swap_filen); |
cd748f27 | 48 | e->swap_status = SWAPOUT_WRITING; |
0cdcf3d7 | 49 | e->swapOutDecision(MemObject::SwapOut::swStarted); |
528b2c61 | 50 | /* If we start swapping out objects with OutOfBand Metadata, |
51 | * then this code needs changing | |
52 | */ | |
246e6cc1 AJ |
53 | |
54 | /* TODO: make some sort of data,size refcounted immutable buffer | |
55 | * and stop fooling ourselves with "const char*" buffers. | |
56 | */ | |
57 | ||
58 | // Create metadata now, possibly in vain: storeCreate needs swap_hdr_sz. | |
59 | const char *buf = e->getSerialisedMetaData (); | |
60 | assert(buf); | |
61 | ||
cd748f27 | 62 | /* Create the swap file */ |
aa839030 | 63 | generic_cbdata *c = new generic_cbdata(e); |
fa80a8ef | 64 | sio = storeCreate(e, storeSwapOutFileNotify, storeSwapOutFileClosed, c); |
62e76326 | 65 | |
85a4b153 | 66 | if (sio == NULL) { |
62e76326 | 67 | e->swap_status = SWAPOUT_NONE; |
0cdcf3d7 | 68 | e->swapOutDecision(MemObject::SwapOut::swImpossible); |
aa839030 | 69 | delete c; |
246e6cc1 | 70 | xfree((char*)buf); |
62e76326 | 71 | storeLog(STORE_LOG_SWAPOUTFAIL, e); |
72 | return; | |
3fc29499 | 73 | } |
62e76326 | 74 | |
528b2c61 | 75 | mem->swapout.sio = sio; |
76 | /* Don't lock until after create, or the replacement | |
77 | * code might get confused */ | |
34266cde | 78 | |
1bfe9ade | 79 | e->lock("storeSwapOutStart"); |
cd748f27 | 80 | /* Pick up the file number if it was assigned immediately */ |
81 | e->swap_filen = mem->swapout.sio->swap_filen; | |
34266cde | 82 | |
cd748f27 | 83 | e->swap_dirn = mem->swapout.sio->swap_dirn; |
34266cde | 84 | |
cd748f27 | 85 | /* write out the swap metadata */ |
daacd51f | 86 | storeIOWrite(mem->swapout.sio, buf, mem->swap_hdr_sz, 0, xfree_cppwrapper); |
f09f5b26 | 87 | } |
88 | ||
cd748f27 | 89 | static void |
e5de8b13 | 90 | storeSwapOutFileNotify(void *data, int errflag, StoreIOState::Pointer self) |
cd748f27 | 91 | { |
bd6e2f16 AJ |
92 | StoreEntry *e; |
93 | static_cast<generic_cbdata *>(data)->unwrap(&e); | |
94 | ||
cd748f27 | 95 | MemObject *mem = e->mem_obj; |
96 | assert(e->swap_status == SWAPOUT_WRITING); | |
97 | assert(mem); | |
84177444 | 98 | assert(mem->swapout.sio == self); |
cd748f27 | 99 | assert(errflag == 0); |
f58bb2f4 | 100 | assert(e->swap_filen < 0); // if this fails, call SwapDir::disconnect(e) |
cd748f27 | 101 | e->swap_filen = mem->swapout.sio->swap_filen; |
102 | e->swap_dirn = mem->swapout.sio->swap_dirn; | |
103 | } | |
104 | ||
90e8b325 | 105 | static bool |
528b2c61 | 106 | doPages(StoreEntry *anEntry) |
107 | { | |
108 | MemObject *mem = anEntry->mem_obj; | |
62e76326 | 109 | |
528b2c61 | 110 | do { |
aa1a691e AR |
111 | // find the page containing the first byte we have not swapped out yet |
112 | mem_node *page = | |
113 | mem->data_hdr.getBlockContainingLocation(mem->swapout.queue_offset); | |
62e76326 | 114 | |
aa1a691e | 115 | if (!page) |
90e8b325 | 116 | break; // wait for more data to become available |
aa1a691e AR |
117 | |
118 | // memNodeWriteComplete() and absence of buffer offset math below | |
119 | // imply that we always write from the very beginning of the page | |
120 | assert(page->start() == mem->swapout.queue_offset); | |
62e76326 | 121 | |
122 | /* | |
123 | * Get the length of this buffer. We are assuming(!) that the buffer | |
124 | * length won't change on this buffer, or things are going to be very | |
125 | * strange. I think that after the copy to a buffer is done, the buffer | |
126 | * size should stay fixed regardless so that this code isn't confused, | |
127 | * but we can look at this at a later date or whenever the code results | |
128 | * in bad swapouts, whichever happens first. :-) | |
129 | */ | |
aa1a691e | 130 | ssize_t swap_buf_len = page->nodeBuffer.length; |
62e76326 | 131 | |
4a7a3d56 | 132 | debugs(20, 3, "storeSwapOut: swap_buf_len = " << swap_buf_len); |
62e76326 | 133 | |
134 | assert(swap_buf_len > 0); | |
135 | ||
4a7a3d56 | 136 | debugs(20, 3, "storeSwapOut: swapping out " << swap_buf_len << " bytes from " << mem->swapout.queue_offset); |
62e76326 | 137 | |
138 | mem->swapout.queue_offset += swap_buf_len; | |
139 | ||
90e8b325 AR |
140 | // Quit if write() fails. Sio is going to call our callback, and that |
141 | // will cleanup, but, depending on the fs, that call may be async. | |
142 | const bool ok = mem->swapout.sio->write( | |
9d4e9cfb AR |
143 | mem->data_hdr.NodeGet(page), |
144 | swap_buf_len, | |
145 | -1, | |
146 | memNodeWriteComplete); | |
62e76326 | 147 | |
90e8b325 AR |
148 | if (!ok || anEntry->swap_status != SWAPOUT_WRITING) |
149 | return false; | |
62e76326 | 150 | |
47f6e231 | 151 | int64_t swapout_size = mem->endOffset() - mem->swapout.queue_offset; |
62e76326 | 152 | |
153 | if (anEntry->store_status == STORE_PENDING) | |
154 | if (swapout_size < SM_PAGE_SIZE) | |
155 | break; | |
156 | ||
157 | if (swapout_size <= 0) | |
90e8b325 | 158 | break; |
528b2c61 | 159 | } while (true); |
90e8b325 AR |
160 | |
161 | // either wait for more data or call swapOutFileClose() | |
162 | return true; | |
528b2c61 | 163 | } |
164 | ||
528b2c61 | 165 | /* This routine is called every time data is sent to the client side. |
166 | * It's overhead is therefor, significant. | |
167 | */ | |
f09f5b26 | 168 | void |
c07cbbf4 | 169 | StoreEntry::swapOut() |
f09f5b26 | 170 | { |
c07cbbf4 | 171 | if (!mem_obj) |
62e76326 | 172 | return; |
173 | ||
5b55f1f1 CT |
174 | // this flag may change so we must check even if we are swappingOut |
175 | if (EBIT_TEST(flags, ENTRY_ABORTED)) { | |
176 | assert(EBIT_TEST(flags, RELEASE_REQUEST)); | |
177 | // StoreEntry::abort() already closed the swap out file, if any | |
178 | // no trimming: data producer must stop production if ENTRY_ABORTED | |
62e76326 | 179 | return; |
5b55f1f1 CT |
180 | } |
181 | ||
182 | const bool weAreOrMayBeSwappingOut = swappingOut() || mayStartSwapOut(); | |
55bfc9fc | 183 | |
4475555f | 184 | Store::Root().memoryOut(*this, weAreOrMayBeSwappingOut); |
5b55f1f1 | 185 | |
2d4dea47 | 186 | if (mem_obj->swapout.decision < MemObject::SwapOut::swPossible) |
5b55f1f1 | 187 | return; // nothing else to do |
528b2c61 | 188 | |
aa1a691e AR |
189 | // Aborted entries have STORE_OK, but swapoutPossible rejects them. Thus, |
190 | // store_status == STORE_OK below means we got everything we wanted. | |
191 | ||
47f6e231 | 192 | debugs(20, 7, HERE << "storeSwapOut: mem->inmem_lo = " << mem_obj->inmem_lo); |
193 | debugs(20, 7, HERE << "storeSwapOut: mem->endOffset() = " << mem_obj->endOffset()); | |
194 | debugs(20, 7, HERE << "storeSwapOut: swapout.queue_offset = " << mem_obj->swapout.queue_offset); | |
62e76326 | 195 | |
85a4b153 | 196 | if (mem_obj->swapout.sio != NULL) |
26ac0430 | 197 | debugs(20, 7, "storeSwapOut: storeOffset() = " << mem_obj->swapout.sio->offset() ); |
62e76326 | 198 | |
47f6e231 | 199 | int64_t const lowest_offset = mem_obj->lowestMemReaderOffset(); |
62e76326 | 200 | |
47f6e231 | 201 | debugs(20, 7, HERE << "storeSwapOut: lowest_offset = " << lowest_offset); |
62e76326 | 202 | |
5aecb102 | 203 | #if SIZEOF_OFF_T <= 4 |
62e76326 | 204 | |
c07cbbf4 | 205 | if (mem_obj->endOffset() > 0x7FFF0000) { |
fa84c01d | 206 | debugs(20, DBG_CRITICAL, "WARNING: preventing off_t overflow for " << url()); |
bfb55b6f | 207 | abort(); |
62e76326 | 208 | return; |
adcceb47 | 209 | } |
62e76326 | 210 | |
adcceb47 | 211 | #endif |
c07cbbf4 | 212 | if (swap_status == SWAPOUT_WRITING) |
47f6e231 | 213 | assert(mem_obj->inmem_lo <= mem_obj->objectBytesOnDisk() ); |
62e76326 | 214 | |
5b55f1f1 CT |
215 | // buffered bytes we have not swapped out yet |
216 | const int64_t swapout_maxsize = mem_obj->availableForSwapOut(); | |
217 | assert(swapout_maxsize >= 0); | |
4a7a3d56 | 218 | debugs(20, 7, "storeSwapOut: swapout_size = " << swapout_maxsize); |
62e76326 | 219 | |
aa1a691e AR |
220 | if (swapout_maxsize == 0) { // swapped everything we got |
221 | if (store_status == STORE_OK) { // got everything we wanted | |
222 | assert(mem_obj->object_sz >= 0); | |
223 | swapOutFileClose(StoreIOState::wroteAll); | |
224 | } | |
225 | // else need more data to swap out | |
226 | return; | |
1b72bda1 | 227 | } |
62e76326 | 228 | |
c07cbbf4 | 229 | if (store_status == STORE_PENDING) { |
62e76326 | 230 | /* wait for a full block to write */ |
231 | ||
232 | if (swapout_maxsize < SM_PAGE_SIZE) | |
233 | return; | |
234 | ||
235 | /* | |
236 | * Wait until we are below the disk FD limit, only if the | |
d5430dc8 | 237 | * next read won't be deferred. |
62e76326 | 238 | */ |
c07cbbf4 | 239 | if (storeTooManyDiskFilesOpen() && !checkDeferRead(-1)) |
62e76326 | 240 | return; |
c47511fd | 241 | } |
62e76326 | 242 | |
2391a162 | 243 | /* Ok, we have stuff to swap out. Is there a swapout.sio open? */ |
c07cbbf4 | 244 | if (swap_status == SWAPOUT_NONE) { |
245 | assert(mem_obj->swapout.sio == NULL); | |
246 | assert(mem_obj->inmem_lo == 0); | |
ddc9b32c | 247 | storeSwapOutStart(this); // sets SwapOut::swImpossible on failures |
f09f5b26 | 248 | } |
62e76326 | 249 | |
c07cbbf4 | 250 | if (mem_obj->swapout.sio == NULL) |
62e76326 | 251 | return; |
252 | ||
90e8b325 | 253 | if (!doPages(this)) |
62e76326 | 254 | /* oops, we're not swapping out any more */ |
255 | return; | |
256 | ||
c07cbbf4 | 257 | if (store_status == STORE_OK) { |
62e76326 | 258 | /* |
259 | * If the state is STORE_OK, then all data must have been given | |
260 | * to the filesystem at this point because storeSwapOut() is | |
261 | * not going to be called again for this entry. | |
262 | */ | |
aa1a691e | 263 | assert(mem_obj->object_sz >= 0); |
c07cbbf4 | 264 | assert(mem_obj->endOffset() == mem_obj->swapout.queue_offset); |
aa1a691e | 265 | swapOutFileClose(StoreIOState::wroteAll); |
1792fbdb | 266 | } |
f09f5b26 | 267 | } |
268 | ||
269 | void | |
aa1a691e | 270 | StoreEntry::swapOutFileClose(int how) |
f09f5b26 | 271 | { |
c07cbbf4 | 272 | assert(mem_obj != NULL); |
aa1a691e | 273 | debugs(20, 3, "storeSwapOutFileClose: " << getMD5Text() << " how=" << how); |
bf8fe701 | 274 | debugs(20, 3, "storeSwapOutFileClose: sio = " << mem_obj->swapout.sio.getRaw()); |
62e76326 | 275 | |
c07cbbf4 | 276 | if (mem_obj->swapout.sio == NULL) |
62e76326 | 277 | return; |
278 | ||
aa1a691e | 279 | storeClose(mem_obj->swapout.sio, how); |
f09f5b26 | 280 | } |
281 | ||
282 | static void | |
e5de8b13 | 283 | storeSwapOutFileClosed(void *data, int errflag, StoreIOState::Pointer self) |
f09f5b26 | 284 | { |
bd6e2f16 AJ |
285 | StoreEntry *e; |
286 | static_cast<generic_cbdata *>(data)->unwrap(&e); | |
287 | ||
25354045 | 288 | MemObject *mem = e->mem_obj; |
84177444 | 289 | assert(mem->swapout.sio == self); |
2391a162 | 290 | assert(e->swap_status == SWAPOUT_WRITING); |
62e76326 | 291 | |
aa1a691e AR |
292 | // if object_size is still unknown, the entry was probably aborted |
293 | if (errflag || e->objectLen() < 0) { | |
de4bc0ea | 294 | debugs(20, 2, "storeSwapOutFileClosed: dirno " << e->swap_dirn << ", swapfile " << |
26ac0430 | 295 | std::hex << std::setw(8) << std::setfill('0') << std::uppercase << |
bf8fe701 | 296 | e->swap_filen << ", errflag=" << errflag); |
62e76326 | 297 | |
298 | if (errflag == DISK_NO_SPACE_LEFT) { | |
c8f4eac4 | 299 | /* FIXME: this should be handle by the link from store IO to |
300 | * Store, rather than being a top level API call. | |
301 | */ | |
302 | e->store()->diskFull(); | |
62e76326 | 303 | storeConfigure(); |
304 | } | |
305 | ||
fa192c71 | 306 | if (e->swap_filen >= 0) |
c8f4eac4 | 307 | e->unlink(); |
62e76326 | 308 | |
f58bb2f4 | 309 | assert(e->swap_status == SWAPOUT_NONE); |
62e76326 | 310 | |
d88e3c49 | 311 | e->releaseRequest(); |
2391a162 | 312 | } else { |
62e76326 | 313 | /* swapping complete */ |
26ac0430 AJ |
314 | debugs(20, 3, "storeSwapOutFileClosed: SwapOut complete: '" << e->url() << "' to " << |
315 | e->swap_dirn << ", " << std::hex << std::setw(8) << std::setfill('0') << | |
bf8fe701 | 316 | std::uppercase << e->swap_filen); |
aa1a691e AR |
317 | debugs(20, 5, HERE << "swap_file_sz = " << |
318 | e->objectLen() << " + " << mem->swap_hdr_sz); | |
8061c9b2 | 319 | |
707fdc47 | 320 | e->swap_file_sz = e->objectLen() + mem->swap_hdr_sz; |
62e76326 | 321 | e->swap_status = SWAPOUT_DONE; |
da9d3191 | 322 | e->store()->swappedOut(*e); |
62e76326 | 323 | |
ddc9b32c AR |
324 | // XXX: For some Stores, it is pointless to re-check cachability here |
325 | // and it leads to double counts in store_check_cachable_hist. We need | |
326 | // another way to signal a completed but failed swapout. Or, better, | |
327 | // each Store should handle its own logging and LOG state setting. | |
3900307b | 328 | if (e->checkCachable()) { |
62e76326 | 329 | storeLog(STORE_LOG_SWAPOUT, e); |
330 | storeDirSwapLog(e, SWAP_LOG_ADD); | |
331 | } | |
332 | ||
e4f1fdae | 333 | ++statCounter.swap.outs; |
f09f5b26 | 334 | } |
62e76326 | 335 | |
bf8fe701 | 336 | debugs(20, 3, "storeSwapOutFileClosed: " << __FILE__ << ":" << __LINE__); |
d3b3ab85 | 337 | mem->swapout.sio = NULL; |
1bfe9ade | 338 | e->unlock("storeSwapOutFileClosed"); |
f09f5b26 | 339 | } |
61038223 | 340 | |
c07cbbf4 | 341 | bool |
5b55f1f1 | 342 | StoreEntry::mayStartSwapOut() |
c2725718 | 343 | { |
5b55f1f1 CT |
344 | // must be checked in the caller |
345 | assert(!EBIT_TEST(flags, ENTRY_ABORTED)); | |
4094b311 | 346 | assert(!swappingOut()); |
5b55f1f1 CT |
347 | |
348 | if (!Config.cacheSwap.n_configured) | |
349 | return false; | |
350 | ||
351 | assert(mem_obj); | |
0cdcf3d7 | 352 | const MemObject::SwapOut::Decision &decision = mem_obj->swapout.decision; |
5b55f1f1 | 353 | |
0e3b2ff0 | 354 | // if we decided that starting is not possible, do not repeat same checks |
5b55f1f1 CT |
355 | if (decision == MemObject::SwapOut::swImpossible) { |
356 | debugs(20, 3, HERE << " already rejected"); | |
357 | return false; | |
358 | } | |
359 | ||
4094b311 AR |
360 | // if we swapped out already, do not start over |
361 | if (swap_status == SWAPOUT_DONE) { | |
539283df | 362 | debugs(20, 3, "already did"); |
0cdcf3d7 | 363 | swapOutDecision(MemObject::SwapOut::swImpossible); |
4094b311 | 364 | return false; |
5b55f1f1 CT |
365 | } |
366 | ||
0e3b2ff0 AR |
367 | // if we stared swapping out already, do not start over |
368 | if (decision == MemObject::SwapOut::swStarted) { | |
369 | debugs(20, 3, "already started"); | |
0cdcf3d7 | 370 | swapOutDecision(MemObject::SwapOut::swImpossible); |
0e3b2ff0 AR |
371 | return false; |
372 | } | |
373 | ||
374 | // if we decided that swapout is possible, do not repeat same checks | |
375 | if (decision == MemObject::SwapOut::swPossible) { | |
376 | debugs(20, 3, "already allowed"); | |
377 | return true; | |
378 | } | |
379 | ||
5b55f1f1 CT |
380 | if (!checkCachable()) { |
381 | debugs(20, 3, HERE << "not cachable"); | |
0cdcf3d7 | 382 | swapOutDecision(MemObject::SwapOut::swImpossible); |
5b55f1f1 CT |
383 | return false; |
384 | } | |
385 | ||
386 | if (EBIT_TEST(flags, ENTRY_SPECIAL)) { | |
387 | debugs(20, 3, HERE << url() << " SPECIAL"); | |
0cdcf3d7 | 388 | swapOutDecision(MemObject::SwapOut::swImpossible); |
5b55f1f1 CT |
389 | return false; |
390 | } | |
391 | ||
e0397786 AR |
392 | if (mem_obj->inmem_lo > 0) { |
393 | debugs(20, 3, "storeSwapOut: (inmem_lo > 0) imem_lo:" << mem_obj->inmem_lo); | |
0cdcf3d7 | 394 | swapOutDecision(MemObject::SwapOut::swImpossible); |
e0397786 AR |
395 | return false; |
396 | } | |
397 | ||
398 | if (!mem_obj->isContiguous()) { | |
399 | debugs(20, 3, "storeSwapOut: not Contiguous"); | |
0cdcf3d7 | 400 | swapOutDecision(MemObject::SwapOut::swImpossible); |
e0397786 AR |
401 | return false; |
402 | } | |
403 | ||
3c856e95 AR |
404 | // handle store_maxobjsize limit |
405 | { | |
5b55f1f1 CT |
406 | // TODO: add estimated store metadata size to be conservative |
407 | ||
408 | // use guaranteed maximum if it is known | |
409 | const int64_t expectedEnd = mem_obj->expectedReplySize(); | |
410 | debugs(20, 7, HERE << "expectedEnd = " << expectedEnd); | |
411 | if (expectedEnd > store_maxobjsize) { | |
412 | debugs(20, 3, HERE << "will not fit: " << expectedEnd << | |
413 | " > " << store_maxobjsize); | |
0cdcf3d7 | 414 | swapOutDecision(MemObject::SwapOut::swImpossible); |
5b55f1f1 CT |
415 | return false; // known to outgrow the limit eventually |
416 | } | |
417 | ||
418 | // use current minimum (always known) | |
419 | const int64_t currentEnd = mem_obj->endOffset(); | |
420 | if (currentEnd > store_maxobjsize) { | |
421 | debugs(20, 3, HERE << "does not fit: " << currentEnd << | |
422 | " > " << store_maxobjsize); | |
0cdcf3d7 | 423 | swapOutDecision(MemObject::SwapOut::swImpossible); |
5b55f1f1 CT |
424 | return false; // already does not fit and may only get bigger |
425 | } | |
426 | ||
e0397786 AR |
427 | // prevent final default swPossible answer for yet unknown length |
428 | if (expectedEnd < 0 && store_status != STORE_OK) { | |
429 | const int64_t maxKnownSize = mem_obj->availableForSwapOut(); | |
5b55f1f1 | 430 | debugs(20, 7, HERE << "maxKnownSize= " << maxKnownSize); |
2ee34428 | 431 | /* |
b51ec8c8 AJ |
432 | * NOTE: the store_maxobjsize here is the global maximum |
433 | * size of object cacheable in any of Squid cache stores | |
434 | * both disk and memory stores. | |
435 | * | |
436 | * However, I am worried that this | |
2ee34428 A |
437 | * deferance may consume a lot of memory in some cases. |
438 | * Should we add an option to limit this memory consumption? | |
439 | */ | |
440 | debugs(20, 5, HERE << "Deferring swapout start for " << | |
441 | (store_maxobjsize - maxKnownSize) << " bytes"); | |
e0397786 | 442 | return true; // may still fit, but no final decision yet |
5b55f1f1 | 443 | } |
06d2839d | 444 | } |
62e76326 | 445 | |
0cdcf3d7 | 446 | swapOutDecision(MemObject::SwapOut::swPossible); |
c07cbbf4 | 447 | return true; |
c2725718 | 448 | } |
f53969cc | 449 |