3 * $Id: store_io_coss.cc,v 1.21 2003/01/23 00:38:13 robertc Exp $
5 * DEBUG: section 79 Storage Manager COSS Interface
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
40 #include "store_coss.h"
41 #include "MemObject.h"
45 static DWCB storeCossWriteMemBufDone
;
46 static DRCB storeCossReadDone
;
47 static void storeCossIOCallback(storeIOState
* sio
, int errflag
);
48 static char *storeCossMemPointerFromDiskOffset(CossSwapDir
* SD
, size_t offset
, CossMemBuf
** mb
);
49 static void storeCossMemBufLock(CossSwapDir
* SD
, storeIOState
* e
);
50 static void storeCossMemBufUnlock(CossSwapDir
* SD
, storeIOState
* e
);
51 static void storeCossWriteMemBuf(CossSwapDir
* SD
, CossMemBuf
* t
);
52 static void storeCossWriteMemBufDone(int, int errflag
, size_t len
, void *my_data
);
53 static CossMemBuf
*storeCossCreateMemBuf(CossSwapDir
* SD
, size_t start
,
54 sfileno curfn
, int *collision
);
56 CBDATA_TYPE(CossMemBuf
);
58 /* === PUBLIC =========================================================== */
60 MemPool
*CossState::Pool
= NULL
;
63 CossState::operator new (size_t)
66 Pool
= memPoolCreate("Squid COSS State Data", sizeof (CossState
));
67 return memPoolAlloc(Pool
);
71 CossState::operator delete (void *address
)
73 memPoolFree (Pool
, address
);
76 CossState::CossState(CossSwapDir
*aCSD
):SD (aCSD
)
82 * This routine sucks. I want to rewrite it when possible, and I also think
83 * that we should check after creatmembuf() to see if the object has a
84 * RELEASE_REQUEST set on it (thanks Eric!) rather than this way which seems
89 storeCossAllocate(CossSwapDir
* SD
, const StoreEntry
* e
, int which
)
97 /* Make sure we chcek collisions if reallocating */
98 if (which
== COSS_ALLOC_REALLOC
)
99 checkf
= e
->swap_filen
;
103 retofs
= e
->swap_filen
; /* Just for defaults, or while rebuilding */
105 if (e
->swap_file_sz
> 0)
106 allocsize
= e
->swap_file_sz
;
108 allocsize
= objectLen(e
) + e
->mem_obj
->swap_hdr_sz
;
110 /* Since we're not supporting NOTIFY anymore, lets fail */
111 assert(which
!= COSS_ALLOC_NOTIFY
);
113 /* Check if we have overflowed the disk .. */
114 if ((SD
->current_offset
+ allocsize
) > (size_t)(SD
->max_size
<< 10)) {
116 * tried to allocate past the end of the disk, so wrap
117 * back to the beginning
119 SD
->current_membuf
->flags
.full
= 1;
120 SD
->current_membuf
->diskend
= SD
->current_offset
- 1;
121 SD
->current_offset
= 0; /* wrap back to beginning */
122 debug(79, 2) ("storeCossAllocate: wrap to 0\n");
124 newmb
= storeCossCreateMemBuf(SD
, 0, checkf
, &coll
);
125 SD
->current_membuf
= newmb
;
127 /* Check if we have overflowed the MemBuf */
128 } else if ((SD
->current_offset
+ allocsize
) > SD
->current_membuf
->diskend
) {
130 * Skip the blank space at the end of the stripe. start over.
132 SD
->current_membuf
->flags
.full
= 1;
133 SD
->current_offset
= SD
->current_membuf
->diskend
+ 1;
134 debug(79, 2) ("storeCossAllocate: New offset - %ld\n",
135 (long int) SD
->current_offset
);
136 newmb
= storeCossCreateMemBuf(SD
, SD
->current_offset
, checkf
, &coll
);
137 SD
->current_membuf
= newmb
;
139 /* If we didn't get a collision, then update the current offset and return it */
141 retofs
= SD
->current_offset
;
142 SD
->current_offset
= retofs
+ allocsize
;
145 debug(79, 3) ("storeCossAllocate: Collision\n");
151 CossSwapDir::unlink(StoreEntry
& e
)
153 debug(79, 3) ("storeCossUnlink: offset %d\n", e
.swap_filen
);
154 storeCossRemove(this, &e
);
157 StoreIOState::Pointer
158 CossSwapDir::createStoreIO(StoreEntry
&e
, STFNCB
* file_callback
, STIOCB
* callback
, void *callback_data
)
161 StoreIOState::Pointer sio
= new CossState(this);
162 cstate
= dynamic_cast<CossState
*>(sio
.getRaw());
164 sio
->mode
= O_WRONLY
| O_BINARY
;
167 * If we get handed an object with a size of -1,
168 * the squid code is broken
170 assert(e
.mem_obj
->object_sz
!= -1);
173 * this one is kinda strange - Eric called storeCossAllocate(), then
174 * storeCossOpen(O_RDONLY) .. weird. Anyway, I'm allocating this now.
176 cstate
->st_size
= objectLen(&e
) + e
.mem_obj
->swap_hdr_sz
;
177 sio
->swap_dirn
= index
;
178 sio
->swap_filen
= storeCossAllocate(this, &e
, COSS_ALLOC_ALLOCATE
);
179 debug(79, 3) ("storeCossCreate: offset %d, size %ld, end %ld\n", sio
->swap_filen
, (long int) cstate
->st_size
, (long int) (sio
->swap_filen
+ cstate
->st_size
));
181 sio
->callback
= callback
;
182 sio
->file_callback
= file_callback
;
183 sio
->callback_data
= cbdataReference(callback_data
);
186 cstate
->flags
.writing
= 0;
187 cstate
->flags
.reading
= 0;
188 cstate
->readbuffer
= NULL
;
189 cstate
->reqdiskoffset
= -1;
191 /* Now add it into the index list */
192 storeCossAdd(this, &e
);
194 storeCossMemBufLock(this, sio
.getRaw());
198 StoreIOState::Pointer
199 CossSwapDir::openStoreIO(StoreEntry
& e
, STFNCB
* file_callback
,
200 STIOCB
* callback
, void *callback_data
)
204 sfileno f
= e
.swap_filen
;
206 debug(79, 3) ("storeCossOpen: offset %d\n", f
);
208 StoreIOState::Pointer sio
= new CossState (this);
209 cstate
= dynamic_cast<CossState
*>(sio
.getRaw());
212 sio
->swap_dirn
= index
;
214 sio
->mode
= O_RDONLY
| O_BINARY
;
215 sio
->callback
= callback
;
216 sio
->file_callback
= file_callback
;
217 sio
->callback_data
= cbdataReference(callback_data
);
218 cstate
->st_size
= e
.swap_file_sz
;
221 cstate
->flags
.writing
= 0;
222 cstate
->flags
.reading
= 0;
223 cstate
->readbuffer
= NULL
;
224 cstate
->reqdiskoffset
= -1;
225 p
= storeCossMemPointerFromDiskOffset(this, f
, NULL
);
226 /* make local copy so we don't have to lock membuf */
228 cstate
->readbuffer
= (char *)xmalloc(cstate
->st_size
);
229 xmemcpy(cstate
->readbuffer
, p
, cstate
->st_size
);
231 /* Do the allocation */
232 /* this is the first time we've been called on a new sio
233 * read the whole object into memory, then return the
237 * This bit of code actually does the LRU disk thing - we realloc
238 * a place for the object here, and the file_read() reads the object
239 * into the cossmembuf for later writing ..
241 cstate
->reqdiskoffset
= sio
->swap_filen
;
242 sio
->swap_filen
= -1;
243 sio
->swap_filen
= storeCossAllocate(this, &e
, COSS_ALLOC_REALLOC
);
244 if (sio
->swap_filen
== -1) {
245 /* We have to clean up neatly .. */
247 debug(79, 2) ("storeCossOpen: Reallocation of %d/%d failed\n", e
.swap_dirn
, e
.swap_filen
);
248 /* XXX XXX XXX Will squid call storeUnlink for this object? */
251 /* Notify the upper levels that we've changed file number */
252 sio
->file_callback(sio
->callback_data
, 0, sio
.getRaw());
255 * lock the buffer so it doesn't get swapped out on us
256 * this will get unlocked in storeCossReadDone
258 storeCossMemBufLock(this, sio
.getRaw());
261 * Do the index magic to keep the disk and memory LRUs identical
263 storeCossRemove(this, &e
);
264 storeCossAdd(this, &e
);
267 * Since we've reallocated a spot for this object, we need to
268 * write it to the cossmembuf *and* return it in the read ..
270 cstate
->readbuffer
= NULL
;
278 debug(79, 3) ("storeCossClose: offset %d\n", swap_filen
);
279 if (FILE_MODE(mode
) == O_WRONLY
)
280 storeCossMemBufUnlock(SD
, this);
281 storeCossIOCallback(this, 0);
285 CossState::read_(char *buf
, size_t size
, off_t offset
, STRCB
* callback
, void *callback_data
)
288 CossSwapDir
*SD
= (CossSwapDir
*)INDEXSD(swap_dirn
);
290 assert(read
.callback
== NULL
);
291 assert(read
.callback_data
== NULL
);
292 read
.callback
= callback
;
293 read
.callback_data
= cbdataReference(callback_data
);
294 debug(79, 3) ("storeCossRead: offset %ld\n", (long int) offset
);
297 if ((offset
+ size
) > st_size
)
298 size
= st_size
- offset
;
301 requestoffset
= offset
;
302 if (readbuffer
== NULL
) {
303 p
= storeCossMemPointerFromDiskOffset(SD
, swap_filen
, NULL
);
304 /* Remember we need to translate the block offset to a disk offset! */
305 a_file_read(&SD
->aq
, SD
->fd
,
311 reqdiskoffset
= 0; /* XXX */
313 storeCossReadDone(SD
->fd
,
322 CossState::write(char const *buf
, size_t size
, off_t offset
, FREE
* free_func
)
329 * If we get handed an object with a size of -1,
330 * the squid code is broken
332 assert(e
->mem_obj
->object_sz
!= -1);
334 debug(79, 3) ("storeCossWrite: offset %ld, len %lu\n", (long int) offset_
, (unsigned long int) size
);
335 diskoffset
= swap_filen
+ offset_
;
336 CossSwapDir
*SD
= (CossSwapDir
*)INDEXSD(swap_dirn
);
337 dest
= storeCossMemPointerFromDiskOffset(SD
, diskoffset
, &membuf
);
338 assert(dest
!= NULL
);
339 xmemcpy(dest
, buf
, size
);
342 (free_func
) ((char *)buf
);
346 /* === STATIC =========================================================== */
349 storeCossReadDone(int rvfd
, const char *buf
, int len
, int errflag
, void *my_data
)
351 storeIOState
*sio
= (storeIOState
*)my_data
;
353 STRCB
*callback
= sio
->read
.callback
;
355 CossSwapDir
*SD
= (CossSwapDir
*)INDEXSD(sio
->swap_dirn
);
356 CossState
*cstate
= dynamic_cast<CossState
*>(sio
);
359 debug(79, 3) ("storeCossReadDone: fileno %d, FD %d, len %d\n",
360 sio
->swap_filen
, rvfd
, len
);
361 cstate
->flags
.reading
= 0;
363 debug(79, 3) ("storeCossReadDone: got failure (%d)\n", errflag
);
366 if (cstate
->readbuffer
== NULL
) {
367 cstate
->readbuffer
= (char *)xmalloc(cstate
->st_size
);
368 p
= storeCossMemPointerFromDiskOffset(SD
, sio
->swap_filen
, NULL
);
369 xmemcpy(cstate
->readbuffer
, p
, cstate
->st_size
);
370 storeCossMemBufUnlock(SD
, sio
);
373 xmemcpy(cstate
->requestbuf
, &cstate
->readbuffer
[cstate
->requestoffset
],
375 rlen
= (size_t) cstate
->requestlen
;
378 sio
->read
.callback
= NULL
;
379 if (cbdataReferenceValidDone(sio
->read
.callback_data
, &cbdata
))
380 callback(cbdata
, cstate
->requestbuf
, rlen
);
384 storeCossIOCallback(storeIOState
* sio
, int errflag
)
386 CossState
*cstate
= dynamic_cast<CossState
*>(sio
);
387 STIOCB
*callback
= sio
->callback
;
389 debug(79, 3) ("storeCossIOCallback: errflag=%d\n", errflag
);
390 xfree(cstate
->readbuffer
);
391 sio
->callback
= NULL
;
392 if (cbdataReferenceValidDone(sio
->callback_data
, &cbdata
))
393 callback(cbdata
, errflag
, sio
);
398 storeCossMemPointerFromDiskOffset(CossSwapDir
* SD
, size_t offset
, CossMemBuf
** mb
)
403 for (m
= SD
->membufs
.head
; m
; m
= m
->next
) {
404 t
= (CossMemBuf
*)m
->data
;
405 if ((offset
>= t
->diskstart
) && (offset
<= t
->diskend
)) {
408 return &t
->buffer
[offset
- t
->diskstart
];
418 storeCossMemBufLock(CossSwapDir
* SD
, storeIOState
* e
)
423 for (m
= SD
->membufs
.head
; m
; m
= m
->next
) {
424 t
= (CossMemBuf
*)m
->data
;
425 if (((size_t)e
->swap_filen
>= t
->diskstart
) && ((size_t)e
->swap_filen
<= t
->diskend
)) {
426 debug(79, 3) ("storeCossMemBufLock: locking %p, lockcount %d\n", t
, t
->lockcount
);
431 debug(79, 3) ("storeCossMemBufLock: FAILED to lock %p\n", e
);
435 storeCossMemBufUnlock(CossSwapDir
* SD
, storeIOState
* e
)
440 for (m
= SD
->membufs
.head
; m
; m
= n
) {
442 * Note that storeCossWriteMemBuf() might call storeCossWriteMemBufDone
443 * immediately (if the write finishes immediately, of course!) which
444 * will make m = m->next kinda unworkable. So, get the next pointer.
447 t
= (CossMemBuf
*)m
->data
;
448 if (((size_t)e
->swap_filen
>= t
->diskstart
) && ((size_t)e
->swap_filen
<= t
->diskend
)) {
450 debug(79, 3) ("storeCossMemBufUnlock: unlocking %p, lockcount %d\n", t
, t
->lockcount
);
452 if (t
->flags
.full
&& !t
->flags
.writing
&& !t
->lockcount
)
453 storeCossWriteMemBuf(SD
, t
);
464 /* First, flush pending IO ops */
465 a_file_syncqueue(&aq
);
467 /* Then, flush any in-memory partial membufs */
470 for (m
= membufs
.head
; m
; m
= m
->next
) {
471 t
= (CossMemBuf
*)m
->data
;
472 if (t
->flags
.writing
)
473 sleep(5); /* XXX EEEWWW! */
474 lseek(fd
, t
->diskstart
, SEEK_SET
);
475 end
= (t
== current_membuf
) ? current_offset
: t
->diskend
;
476 FD_WRITE_METHOD(fd
, t
->buffer
, end
- t
->diskstart
);
481 storeCossWriteMemBuf(CossSwapDir
* SD
, CossMemBuf
* t
)
483 debug(79, 3) ("storeCossWriteMemBuf: offset %ld, len %ld\n",
484 (long int) t
->diskstart
, (long int) (t
->diskend
- t
->diskstart
));
485 t
->flags
.writing
= 1;
486 /* Remember that diskstart/diskend are block offsets! */
487 a_file_write(&SD
->aq
, SD
->fd
, t
->diskstart
, &t
->buffer
,
488 t
->diskend
- t
->diskstart
, storeCossWriteMemBufDone
, t
, NULL
);
493 storeCossWriteMemBufDone(int rvfd
, int errflag
, size_t len
, void *my_data
)
495 CossMemBuf
*t
= (CossMemBuf
*)my_data
;
497 debug(79, 3) ("storeCossWriteMemBufDone: buf %p, len %ld\n", t
, (long int) len
);
499 debug(79, 0) ("storeCossMemBufWriteDone: got failure (%d)\n", errflag
);
501 dlinkDelete(&t
->node
, &t
->SD
->membufs
);
506 storeCossCreateMemBuf(CossSwapDir
* SD
, size_t start
,
507 sfileno curfn
, int *collision
)
509 CossMemBuf
*newmb
, *t
;
511 dlink_node
*m
, *prev
;
514 CBDATA_INIT_TYPE_FREECB(CossMemBuf
, NULL
);
515 newmb
= cbdataAlloc(CossMemBuf
);
516 newmb
->diskstart
= start
;
517 debug(79, 3) ("storeCossCreateMemBuf: creating new membuf at %ld\n", (long int) newmb
->diskstart
);
518 debug(79, 3) ("storeCossCreateMemBuf: at %p\n", newmb
);
519 newmb
->diskend
= newmb
->diskstart
+ COSS_MEMBUF_SZ
- 1;
520 newmb
->flags
.full
= 0;
521 newmb
->flags
.writing
= 0;
522 newmb
->lockcount
= 0;
524 /* XXX This should be reversed, with the new buffer last in the chain */
525 dlinkAdd(newmb
, &newmb
->node
, &SD
->membufs
);
527 /* Print out the list of membufs */
528 for (m
= SD
->membufs
.head
; m
; m
= m
->next
) {
529 t
= (CossMemBuf
*)m
->data
;
530 debug(79, 3) ("storeCossCreateMemBuf: membuflist %ld lockcount %d\n", (long int) t
->diskstart
, t
->lockcount
);
534 * Kill objects from the tail to make space for a new chunk
536 for (m
= SD
->cossindex
.tail
; m
; m
= prev
) {
538 e
= (StoreEntry
*)m
->data
;
539 if (curfn
== e
->swap_filen
)
540 *collision
= 1; /* Mark an object alloc collision */
541 if (((size_t)e
->swap_filen
>= newmb
->diskstart
) &&
542 ((size_t)e
->swap_filen
<= newmb
->diskend
)) {
549 debug(79, 3) ("storeCossCreateMemBuf: this allocation released %d storeEntries\n", numreleased
);
554 * Creates the initial membuf after rebuild
557 storeCossStartMembuf(CossSwapDir
* sd
)
559 CossMemBuf
*newmb
= storeCossCreateMemBuf(sd
, sd
->current_offset
, -1, NULL
);
560 assert(!sd
->current_membuf
);
561 sd
->current_membuf
= newmb
;
565 * Clean up any references from the SIO before it get's released.
567 CossState::~CossState()