]>
Commit | Line | Data |
---|---|---|
9cef6668 | 1 | |
2 | /* | |
262a0e14 | 3 | * $Id$ |
9cef6668 | 4 | * |
5 | * DEBUG: section 20 Storage Manager Swapout Functions | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
9cef6668 | 9 | * ---------------------------------------------------------- |
10 | * | |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
9cef6668 | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
26ac0430 | 24 | * |
9cef6668 | 25 | * This program is distributed in the hope that it will be useful, |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
26ac0430 | 29 | * |
9cef6668 | 30 | * You should have received a copy of the GNU General Public License |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | */ | |
35 | ||
f7f3304a | 36 | #include "squid-old.h" |
aa839030 | 37 | #include "cbdata.h" |
c8be6d7b | 38 | #include "StoreClient.h" |
e6ccf245 | 39 | #include "Store.h" |
528b2c61 | 40 | /* FIXME: Abstract the use of this more */ |
41 | #include "mem_node.h" | |
42 | #include "MemObject.h" | |
d3b3ab85 | 43 | #include "SwapDir.h" |
e4f1fdae | 44 | #include "StatCounters.h" |
4b981814 | 45 | #include "swap_log_op.h" |
f09f5b26 | 46 | |
d54f0ab3 | 47 | static void storeSwapOutStart(StoreEntry * e); |
4fcc8876 | 48 | static StoreIOState::STIOCB storeSwapOutFileClosed; |
49 | static StoreIOState::STFNCB storeSwapOutFileNotify; | |
f09f5b26 | 50 | |
daacd51f AJ |
51 | // wrapper to cross C/C++ ABI boundary. xfree is extern "C" for libraries. |
52 | static void xfree_cppwrapper(void *x) | |
53 | { | |
54 | xfree(x); | |
55 | } | |
56 | ||
f09f5b26 | 57 | /* start swapping object to disk */ |
d54f0ab3 | 58 | static void |
f09f5b26 | 59 | storeSwapOutStart(StoreEntry * e) |
60 | { | |
2391a162 | 61 | MemObject *mem = e->mem_obj; |
d3b3ab85 | 62 | StoreIOState::Pointer sio; |
2391a162 | 63 | assert(mem); |
cd748f27 | 64 | /* Build the swap metadata, so the filesystem will know how much |
65 | * metadata there is to store | |
66 | */ | |
26ac0430 AJ |
67 | debugs(20, 5, "storeSwapOutStart: Begin SwapOut '" << e->url() << "' to dirno " << |
68 | e->swap_dirn << ", fileno " << std::hex << std::setw(8) << std::setfill('0') << | |
bf8fe701 | 69 | std::uppercase << e->swap_filen); |
cd748f27 | 70 | e->swap_status = SWAPOUT_WRITING; |
528b2c61 | 71 | /* If we start swapping out objects with OutOfBand Metadata, |
72 | * then this code needs changing | |
73 | */ | |
246e6cc1 AJ |
74 | |
75 | /* TODO: make some sort of data,size refcounted immutable buffer | |
76 | * and stop fooling ourselves with "const char*" buffers. | |
77 | */ | |
78 | ||
79 | // Create metadata now, possibly in vain: storeCreate needs swap_hdr_sz. | |
80 | const char *buf = e->getSerialisedMetaData (); | |
81 | assert(buf); | |
82 | ||
cd748f27 | 83 | /* Create the swap file */ |
aa839030 | 84 | generic_cbdata *c = new generic_cbdata(e); |
fa80a8ef | 85 | sio = storeCreate(e, storeSwapOutFileNotify, storeSwapOutFileClosed, c); |
62e76326 | 86 | |
85a4b153 | 87 | if (sio == NULL) { |
62e76326 | 88 | e->swap_status = SWAPOUT_NONE; |
ddc9b32c | 89 | mem->swapout.decision = MemObject::SwapOut::swImpossible; |
aa839030 | 90 | delete c; |
246e6cc1 | 91 | xfree((char*)buf); |
62e76326 | 92 | storeLog(STORE_LOG_SWAPOUTFAIL, e); |
93 | return; | |
3fc29499 | 94 | } |
62e76326 | 95 | |
528b2c61 | 96 | mem->swapout.sio = sio; |
97 | /* Don't lock until after create, or the replacement | |
98 | * code might get confused */ | |
34266cde | 99 | |
3d0ac046 | 100 | e->lock(); |
cd748f27 | 101 | /* Pick up the file number if it was assigned immediately */ |
102 | e->swap_filen = mem->swapout.sio->swap_filen; | |
34266cde | 103 | |
cd748f27 | 104 | e->swap_dirn = mem->swapout.sio->swap_dirn; |
34266cde | 105 | |
cd748f27 | 106 | /* write out the swap metadata */ |
daacd51f | 107 | storeIOWrite(mem->swapout.sio, buf, mem->swap_hdr_sz, 0, xfree_cppwrapper); |
f09f5b26 | 108 | } |
109 | ||
cd748f27 | 110 | static void |
e5de8b13 | 111 | storeSwapOutFileNotify(void *data, int errflag, StoreIOState::Pointer self) |
cd748f27 | 112 | { |
e6ccf245 | 113 | generic_cbdata *c = (generic_cbdata *)data; |
114 | StoreEntry *e = (StoreEntry *)c->data; | |
cd748f27 | 115 | MemObject *mem = e->mem_obj; |
116 | assert(e->swap_status == SWAPOUT_WRITING); | |
117 | assert(mem); | |
84177444 | 118 | assert(mem->swapout.sio == self); |
cd748f27 | 119 | assert(errflag == 0); |
f58bb2f4 | 120 | assert(e->swap_filen < 0); // if this fails, call SwapDir::disconnect(e) |
cd748f27 | 121 | e->swap_filen = mem->swapout.sio->swap_filen; |
122 | e->swap_dirn = mem->swapout.sio->swap_dirn; | |
123 | } | |
124 | ||
528b2c61 | 125 | static void |
126 | doPages(StoreEntry *anEntry) | |
127 | { | |
128 | MemObject *mem = anEntry->mem_obj; | |
62e76326 | 129 | |
528b2c61 | 130 | do { |
aa1a691e AR |
131 | // find the page containing the first byte we have not swapped out yet |
132 | mem_node *page = | |
133 | mem->data_hdr.getBlockContainingLocation(mem->swapout.queue_offset); | |
62e76326 | 134 | |
aa1a691e AR |
135 | if (!page) |
136 | return; // wait for more data to become available | |
137 | ||
138 | // memNodeWriteComplete() and absence of buffer offset math below | |
139 | // imply that we always write from the very beginning of the page | |
140 | assert(page->start() == mem->swapout.queue_offset); | |
62e76326 | 141 | |
142 | /* | |
143 | * Get the length of this buffer. We are assuming(!) that the buffer | |
144 | * length won't change on this buffer, or things are going to be very | |
145 | * strange. I think that after the copy to a buffer is done, the buffer | |
146 | * size should stay fixed regardless so that this code isn't confused, | |
147 | * but we can look at this at a later date or whenever the code results | |
148 | * in bad swapouts, whichever happens first. :-) | |
149 | */ | |
aa1a691e | 150 | ssize_t swap_buf_len = page->nodeBuffer.length; |
62e76326 | 151 | |
4a7a3d56 | 152 | debugs(20, 3, "storeSwapOut: swap_buf_len = " << swap_buf_len); |
62e76326 | 153 | |
154 | assert(swap_buf_len > 0); | |
155 | ||
4a7a3d56 | 156 | debugs(20, 3, "storeSwapOut: swapping out " << swap_buf_len << " bytes from " << mem->swapout.queue_offset); |
62e76326 | 157 | |
158 | mem->swapout.queue_offset += swap_buf_len; | |
159 | ||
84177444 | 160 | storeIOWrite(mem->swapout.sio, |
aa1a691e | 161 | mem->data_hdr.NodeGet(page), |
84177444 | 162 | swap_buf_len, |
163 | -1, | |
164 | memNodeWriteComplete); | |
62e76326 | 165 | |
166 | /* the storeWrite() call might generate an error */ | |
167 | if (anEntry->swap_status != SWAPOUT_WRITING) | |
168 | break; | |
169 | ||
47f6e231 | 170 | int64_t swapout_size = mem->endOffset() - mem->swapout.queue_offset; |
62e76326 | 171 | |
172 | if (anEntry->store_status == STORE_PENDING) | |
173 | if (swapout_size < SM_PAGE_SIZE) | |
174 | break; | |
175 | ||
176 | if (swapout_size <= 0) | |
177 | return; | |
528b2c61 | 178 | } while (true); |
179 | } | |
180 | ||
181 | ||
182 | /* This routine is called every time data is sent to the client side. | |
183 | * It's overhead is therefor, significant. | |
184 | */ | |
f09f5b26 | 185 | void |
c07cbbf4 | 186 | StoreEntry::swapOut() |
f09f5b26 | 187 | { |
c07cbbf4 | 188 | if (!mem_obj) |
62e76326 | 189 | return; |
190 | ||
5b55f1f1 CT |
191 | // this flag may change so we must check even if we are swappingOut |
192 | if (EBIT_TEST(flags, ENTRY_ABORTED)) { | |
193 | assert(EBIT_TEST(flags, RELEASE_REQUEST)); | |
194 | // StoreEntry::abort() already closed the swap out file, if any | |
195 | // no trimming: data producer must stop production if ENTRY_ABORTED | |
62e76326 | 196 | return; |
5b55f1f1 CT |
197 | } |
198 | ||
199 | const bool weAreOrMayBeSwappingOut = swappingOut() || mayStartSwapOut(); | |
55bfc9fc | 200 | |
5b55f1f1 CT |
201 | trimMemory(weAreOrMayBeSwappingOut); |
202 | ||
203 | if (!weAreOrMayBeSwappingOut) | |
204 | return; // nothing else to do | |
528b2c61 | 205 | |
aa1a691e AR |
206 | // Aborted entries have STORE_OK, but swapoutPossible rejects them. Thus, |
207 | // store_status == STORE_OK below means we got everything we wanted. | |
208 | ||
47f6e231 | 209 | debugs(20, 7, HERE << "storeSwapOut: mem->inmem_lo = " << mem_obj->inmem_lo); |
210 | debugs(20, 7, HERE << "storeSwapOut: mem->endOffset() = " << mem_obj->endOffset()); | |
211 | debugs(20, 7, HERE << "storeSwapOut: swapout.queue_offset = " << mem_obj->swapout.queue_offset); | |
62e76326 | 212 | |
85a4b153 | 213 | if (mem_obj->swapout.sio != NULL) |
26ac0430 | 214 | debugs(20, 7, "storeSwapOut: storeOffset() = " << mem_obj->swapout.sio->offset() ); |
62e76326 | 215 | |
47f6e231 | 216 | int64_t const lowest_offset = mem_obj->lowestMemReaderOffset(); |
62e76326 | 217 | |
47f6e231 | 218 | debugs(20, 7, HERE << "storeSwapOut: lowest_offset = " << lowest_offset); |
62e76326 | 219 | |
5aecb102 | 220 | #if SIZEOF_OFF_T <= 4 |
62e76326 | 221 | |
c07cbbf4 | 222 | if (mem_obj->endOffset() > 0x7FFF0000) { |
c664b2a6 | 223 | debugs(20, 0, "WARNING: preventing off_t overflow for " << url()); |
bfb55b6f | 224 | abort(); |
62e76326 | 225 | return; |
adcceb47 | 226 | } |
62e76326 | 227 | |
adcceb47 | 228 | #endif |
c07cbbf4 | 229 | if (swap_status == SWAPOUT_WRITING) |
47f6e231 | 230 | assert(mem_obj->inmem_lo <= mem_obj->objectBytesOnDisk() ); |
62e76326 | 231 | |
5b55f1f1 CT |
232 | // buffered bytes we have not swapped out yet |
233 | const int64_t swapout_maxsize = mem_obj->availableForSwapOut(); | |
234 | assert(swapout_maxsize >= 0); | |
4a7a3d56 | 235 | debugs(20, 7, "storeSwapOut: swapout_size = " << swapout_maxsize); |
62e76326 | 236 | |
aa1a691e AR |
237 | if (swapout_maxsize == 0) { // swapped everything we got |
238 | if (store_status == STORE_OK) { // got everything we wanted | |
239 | assert(mem_obj->object_sz >= 0); | |
240 | swapOutFileClose(StoreIOState::wroteAll); | |
241 | } | |
242 | // else need more data to swap out | |
243 | return; | |
1b72bda1 | 244 | } |
62e76326 | 245 | |
c07cbbf4 | 246 | if (store_status == STORE_PENDING) { |
62e76326 | 247 | /* wait for a full block to write */ |
248 | ||
249 | if (swapout_maxsize < SM_PAGE_SIZE) | |
250 | return; | |
251 | ||
252 | /* | |
253 | * Wait until we are below the disk FD limit, only if the | |
254 | * next server-side read won't be deferred. | |
255 | */ | |
c07cbbf4 | 256 | if (storeTooManyDiskFilesOpen() && !checkDeferRead(-1)) |
62e76326 | 257 | return; |
c47511fd | 258 | } |
62e76326 | 259 | |
2391a162 | 260 | /* Ok, we have stuff to swap out. Is there a swapout.sio open? */ |
c07cbbf4 | 261 | if (swap_status == SWAPOUT_NONE) { |
262 | assert(mem_obj->swapout.sio == NULL); | |
263 | assert(mem_obj->inmem_lo == 0); | |
ddc9b32c | 264 | storeSwapOutStart(this); // sets SwapOut::swImpossible on failures |
f09f5b26 | 265 | } |
62e76326 | 266 | |
c07cbbf4 | 267 | if (mem_obj->swapout.sio == NULL) |
62e76326 | 268 | return; |
269 | ||
c07cbbf4 | 270 | doPages(this); |
62e76326 | 271 | |
85a4b153 | 272 | if (mem_obj->swapout.sio == NULL) |
62e76326 | 273 | /* oops, we're not swapping out any more */ |
274 | return; | |
275 | ||
c07cbbf4 | 276 | if (store_status == STORE_OK) { |
62e76326 | 277 | /* |
278 | * If the state is STORE_OK, then all data must have been given | |
279 | * to the filesystem at this point because storeSwapOut() is | |
280 | * not going to be called again for this entry. | |
281 | */ | |
aa1a691e | 282 | assert(mem_obj->object_sz >= 0); |
c07cbbf4 | 283 | assert(mem_obj->endOffset() == mem_obj->swapout.queue_offset); |
aa1a691e | 284 | swapOutFileClose(StoreIOState::wroteAll); |
1792fbdb | 285 | } |
f09f5b26 | 286 | } |
287 | ||
288 | void | |
aa1a691e | 289 | StoreEntry::swapOutFileClose(int how) |
f09f5b26 | 290 | { |
c07cbbf4 | 291 | assert(mem_obj != NULL); |
aa1a691e | 292 | debugs(20, 3, "storeSwapOutFileClose: " << getMD5Text() << " how=" << how); |
bf8fe701 | 293 | debugs(20, 3, "storeSwapOutFileClose: sio = " << mem_obj->swapout.sio.getRaw()); |
62e76326 | 294 | |
c07cbbf4 | 295 | if (mem_obj->swapout.sio == NULL) |
62e76326 | 296 | return; |
297 | ||
aa1a691e | 298 | storeClose(mem_obj->swapout.sio, how); |
f09f5b26 | 299 | } |
300 | ||
301 | static void | |
e5de8b13 | 302 | storeSwapOutFileClosed(void *data, int errflag, StoreIOState::Pointer self) |
f09f5b26 | 303 | { |
e6ccf245 | 304 | generic_cbdata *c = (generic_cbdata *)data; |
305 | StoreEntry *e = (StoreEntry *)c->data; | |
25354045 | 306 | MemObject *mem = e->mem_obj; |
84177444 | 307 | assert(mem->swapout.sio == self); |
2391a162 | 308 | assert(e->swap_status == SWAPOUT_WRITING); |
309 | cbdataFree(c); | |
62e76326 | 310 | |
aa1a691e AR |
311 | // if object_size is still unknown, the entry was probably aborted |
312 | if (errflag || e->objectLen() < 0) { | |
de4bc0ea | 313 | debugs(20, 2, "storeSwapOutFileClosed: dirno " << e->swap_dirn << ", swapfile " << |
26ac0430 | 314 | std::hex << std::setw(8) << std::setfill('0') << std::uppercase << |
bf8fe701 | 315 | e->swap_filen << ", errflag=" << errflag); |
62e76326 | 316 | |
317 | if (errflag == DISK_NO_SPACE_LEFT) { | |
c8f4eac4 | 318 | /* FIXME: this should be handle by the link from store IO to |
319 | * Store, rather than being a top level API call. | |
320 | */ | |
321 | e->store()->diskFull(); | |
62e76326 | 322 | storeConfigure(); |
323 | } | |
324 | ||
fa192c71 | 325 | if (e->swap_filen >= 0) |
c8f4eac4 | 326 | e->unlink(); |
62e76326 | 327 | |
f58bb2f4 | 328 | assert(e->swap_status == SWAPOUT_NONE); |
62e76326 | 329 | |
d88e3c49 | 330 | e->releaseRequest(); |
2391a162 | 331 | } else { |
62e76326 | 332 | /* swapping complete */ |
26ac0430 AJ |
333 | debugs(20, 3, "storeSwapOutFileClosed: SwapOut complete: '" << e->url() << "' to " << |
334 | e->swap_dirn << ", " << std::hex << std::setw(8) << std::setfill('0') << | |
bf8fe701 | 335 | std::uppercase << e->swap_filen); |
aa1a691e AR |
336 | debugs(20, 5, HERE << "swap_file_sz = " << |
337 | e->objectLen() << " + " << mem->swap_hdr_sz); | |
8061c9b2 | 338 | |
707fdc47 | 339 | e->swap_file_sz = e->objectLen() + mem->swap_hdr_sz; |
62e76326 | 340 | e->swap_status = SWAPOUT_DONE; |
da9d3191 | 341 | e->store()->swappedOut(*e); |
62e76326 | 342 | |
ddc9b32c AR |
343 | // XXX: For some Stores, it is pointless to re-check cachability here |
344 | // and it leads to double counts in store_check_cachable_hist. We need | |
345 | // another way to signal a completed but failed swapout. Or, better, | |
346 | // each Store should handle its own logging and LOG state setting. | |
3900307b | 347 | if (e->checkCachable()) { |
62e76326 | 348 | storeLog(STORE_LOG_SWAPOUT, e); |
349 | storeDirSwapLog(e, SWAP_LOG_ADD); | |
350 | } | |
351 | ||
e4f1fdae | 352 | ++statCounter.swap.outs; |
f09f5b26 | 353 | } |
62e76326 | 354 | |
bf8fe701 | 355 | debugs(20, 3, "storeSwapOutFileClosed: " << __FILE__ << ":" << __LINE__); |
d3b3ab85 | 356 | mem->swapout.sio = NULL; |
97b5e68f | 357 | e->unlock(); |
f09f5b26 | 358 | } |
61038223 | 359 | |
c07cbbf4 | 360 | bool |
5b55f1f1 | 361 | StoreEntry::mayStartSwapOut() |
c2725718 | 362 | { |
06d2839d | 363 | dlink_node *node; |
62e76326 | 364 | |
5b55f1f1 CT |
365 | // must be checked in the caller |
366 | assert(!EBIT_TEST(flags, ENTRY_ABORTED)); | |
367 | ||
368 | if (!Config.cacheSwap.n_configured) | |
369 | return false; | |
370 | ||
371 | assert(mem_obj); | |
372 | MemObject::SwapOut::Decision &decision = mem_obj->swapout.decision; | |
373 | ||
374 | // if we decided that swapout is not possible, do not repeat same checks | |
375 | if (decision == MemObject::SwapOut::swImpossible) { | |
376 | debugs(20, 3, HERE << " already rejected"); | |
377 | return false; | |
378 | } | |
379 | ||
380 | // if we decided that swapout is possible, do not repeat same checks | |
381 | if (decision == MemObject::SwapOut::swPossible) { | |
382 | debugs(20, 3, HERE << "already allowed"); | |
c07cbbf4 | 383 | return true; |
5b55f1f1 CT |
384 | } |
385 | ||
386 | // if we are swapping out already, do not repeat same checks | |
387 | if (swap_status != SWAPOUT_NONE) { | |
388 | debugs(20, 3, HERE << " already started"); | |
389 | decision = MemObject::SwapOut::swPossible; | |
390 | return true; | |
391 | } | |
392 | ||
393 | if (!checkCachable()) { | |
394 | debugs(20, 3, HERE << "not cachable"); | |
395 | decision = MemObject::SwapOut::swImpossible; | |
396 | return false; | |
397 | } | |
398 | ||
399 | if (EBIT_TEST(flags, ENTRY_SPECIAL)) { | |
400 | debugs(20, 3, HERE << url() << " SPECIAL"); | |
401 | decision = MemObject::SwapOut::swImpossible; | |
402 | return false; | |
403 | } | |
404 | ||
405 | // check cache_dir max-size limit if all cache_dirs have it | |
406 | if (store_maxobjsize >= 0) { | |
407 | // TODO: add estimated store metadata size to be conservative | |
408 | ||
409 | // use guaranteed maximum if it is known | |
410 | const int64_t expectedEnd = mem_obj->expectedReplySize(); | |
411 | debugs(20, 7, HERE << "expectedEnd = " << expectedEnd); | |
412 | if (expectedEnd > store_maxobjsize) { | |
413 | debugs(20, 3, HERE << "will not fit: " << expectedEnd << | |
414 | " > " << store_maxobjsize); | |
415 | decision = MemObject::SwapOut::swImpossible; | |
416 | return false; // known to outgrow the limit eventually | |
417 | } | |
418 | ||
419 | // use current minimum (always known) | |
420 | const int64_t currentEnd = mem_obj->endOffset(); | |
421 | if (currentEnd > store_maxobjsize) { | |
422 | debugs(20, 3, HERE << "does not fit: " << currentEnd << | |
423 | " > " << store_maxobjsize); | |
424 | decision = MemObject::SwapOut::swImpossible; | |
425 | return false; // already does not fit and may only get bigger | |
426 | } | |
427 | ||
428 | // prevent default swPossible answer for yet unknown length | |
429 | if (expectedEnd < 0) { | |
430 | debugs(20, 3, HERE << "wait for more info: " << | |
431 | store_maxobjsize); | |
432 | return false; // may fit later, but will be rejected now | |
433 | } | |
62e76326 | 434 | |
5b55f1f1 CT |
435 | if (store_status != STORE_OK) { |
436 | const int64_t maxKnownSize = expectedEnd < 0 ? | |
55bfc9fc | 437 | mem_obj->availableForSwapOut() : expectedEnd; |
5b55f1f1 CT |
438 | debugs(20, 7, HERE << "maxKnownSize= " << maxKnownSize); |
439 | if (maxKnownSize < store_maxobjsize) { | |
440 | /* | |
441 | * NOTE: the store_maxobjsize here is the max of optional | |
442 | * max-size values from 'cache_dir' lines. It is not the | |
443 | * same as 'maximum_object_size'. By default, store_maxobjsize | |
444 | * will be set to -1. However, I am worried that this | |
445 | * deferance may consume a lot of memory in some cases. | |
446 | * Should we add an option to limit this memory consumption? | |
447 | */ | |
448 | debugs(20, 5, HERE << "Deferring swapout start for " << | |
449 | (store_maxobjsize - maxKnownSize) << " bytes"); | |
450 | return false; | |
451 | } | |
452 | } | |
453 | } | |
454 | ||
455 | if (mem_obj->inmem_lo > 0) { | |
456 | debugs(20, 3, "storeSwapOut: (inmem_lo > 0) imem_lo:" << mem_obj->inmem_lo); | |
457 | decision = MemObject::SwapOut::swImpossible; | |
c07cbbf4 | 458 | return false; |
5b55f1f1 | 459 | } |
62e76326 | 460 | |
5f25e839 | 461 | /* |
462 | * If there are DISK clients, we must write to disk | |
463 | * even if its not cachable | |
528b2c61 | 464 | * RBC: Surely we should not create disk client on non cacheable objects? |
465 | * therefore this should be an assert? | |
4e70dae3 | 466 | * RBC 20030708: We can use disk to avoid mem races, so this shouldn't be |
467 | * an assert. | |
5b55f1f1 CT |
468 | * |
469 | * XXX: Not clear what "mem races" the above refers to, especially when | |
470 | * dealing with non-cachable objects that cannot have multiple clients. | |
471 | * | |
472 | * XXX: If STORE_DISK_CLIENT needs SwapOut::swPossible, we have to check | |
473 | * for that flag earlier, but forcing swapping may contradict max-size or | |
474 | * other swapability restrictions. Change storeClientType() and/or its | |
475 | * callers to take swap-in availability into account. | |
5f25e839 | 476 | */ |
c07cbbf4 | 477 | for (node = mem_obj->clients.head; node; node = node->next) { |
5b55f1f1 CT |
478 | if (((store_client *) node->data)->getType() == STORE_DISK_CLIENT) { |
479 | debugs(20, 3, HERE << "DISK client found"); | |
480 | decision = MemObject::SwapOut::swPossible; | |
c07cbbf4 | 481 | return true; |
5b55f1f1 | 482 | } |
06d2839d | 483 | } |
62e76326 | 484 | |
5b55f1f1 CT |
485 | if (!mem_obj->isContiguous()) { |
486 | debugs(20, 3, "storeSwapOut: not Contiguous"); | |
487 | decision = MemObject::SwapOut::swImpossible; | |
c07cbbf4 | 488 | return false; |
5b55f1f1 | 489 | } |
62e76326 | 490 | |
5b55f1f1 | 491 | decision = MemObject::SwapOut::swPossible; |
c07cbbf4 | 492 | return true; |
c2725718 | 493 | } |