2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 * Author: Adrian Chadd <adrian@squid-cache.org>
12 * These routines are simple plugin replacements for the file_* routines
13 * in disk.c . They back-end into the POSIX AIO routines to provide
14 * a nice and simple async IO framework for COSS.
16 * AIO is suitable for COSS - the only sync operations that the standard
17 * supports are read/write, and since COSS works on a single file
18 * per storedir it should work just fine.
22 #include "DiskIO/AIO/AIODiskFile.h"
23 #include "DiskIO/AIO/AIODiskIOStrategy.h"
24 #include "DiskIO/IORequestor.h"
25 #include "DiskIO/ReadRequest.h"
26 #include "DiskIO/WriteRequest.h"
28 AIODiskIOStrategy::AIODiskIOStrategy() :
31 aq
.aq_state
= AQ_STATE_NONE
;
33 memset(&aq
.aq_queue
, 0, sizeof(aq
.aq_queue
));
36 AIODiskIOStrategy::~AIODiskIOStrategy()
38 assert(aq
.aq_state
== AQ_STATE_SETUP
||
39 aq
.aq_numpending
== 0);
42 aq
.aq_state
= AQ_STATE_NONE
;
46 AIODiskIOStrategy::shedLoad()
52 AIODiskIOStrategy::load()
54 return aq
.aq_numpending
* 1000 / MAX_ASYNCOP
;
58 AIODiskIOStrategy::newFile (char const *path
)
64 return new AIODiskFile (path
, this);
68 AIODiskIOStrategy::sync()
70 assert(aq
.aq_state
== AQ_STATE_SETUP
);
73 * Keep calling callback to complete ops until the queue is empty
74 * We can't quit when callback returns 0 - some calls may not
75 * return any completed pending events, but they're still pending!
78 while (aq
.aq_numpending
)
83 AIODiskIOStrategy::unlinkdUseful() const
89 AIODiskIOStrategy::unlinkFile (char const *)
93 * Note: we grab the state and free the state before calling the callback
94 * because this allows us to cut down the amount of time it'll take
95 * to find a free slot (since if we call the callback first, we're going
96 * to probably be allocated the slot _after_ this one..)
98 * I'll make it much more optimal later.
101 AIODiskIOStrategy::callback()
111 async_queue_entry_t
*aqe
;
112 async_queue_entry_type_t type
;
114 assert(aq
.aq_state
== AQ_STATE_SETUP
);
116 /* Loop through all slots */
118 for (i
= 0; i
< MAX_ASYNCOP
; ++i
) {
119 if (aq
.aq_queue
[i
].aq_e_state
== AQ_ENTRY_USED
) {
120 aqe
= &aq
.aq_queue
[i
];
121 /* Active, get status */
122 reterr
= aio_error(&aqe
->aq_e_aiocb
);
125 fatal("aio_error returned an error!\n");
128 if (reterr
!= EINPROGRESS
) {
129 /* Get the return code */
130 retval
= aio_return(&aqe
->aq_e_aiocb
);
132 /* Get the callback parameters */
133 freefunc
= aqe
->aq_e_free
;
135 type
= aqe
->aq_e_type
;
136 callback_valid
= cbdataReferenceValidDone(aqe
->aq_e_callback_data
, &cbdata
);
137 AIODiskFile
* theFile
= NULL
;
138 void *theFileVoid
= NULL
;
139 void *theTmpFile
= aqe
->theFile
;
140 bool fileOk
= cbdataReferenceValidDone(theTmpFile
, &theFileVoid
);
143 theFile
= static_cast<AIODiskFile
*>(theFileVoid
);
147 memset(aqe
, 0, sizeof(async_queue_entry_t
));
149 aqe
->aq_e_state
= AQ_ENTRY_FREE
;
155 if (callback_valid
) {
158 if (type
== AQ_ENTRY_READ
)
159 theFile
->ioRequestor
->readCompleted((const char *)buf
, retval
, reterr
, static_cast<ReadRequest
*>(cbdata
));
161 if (type
== AQ_ENTRY_WRITE
)
162 theFile
->ioRequestor
->writeCompleted(reterr
,retval
, static_cast<WriteRequest
*>(cbdata
));
165 if (type
== AQ_ENTRY_WRITE
&& freefunc
)
176 AIODiskIOStrategy::init()
178 /* Make sure the queue isn't setup */
179 assert(aq
.aq_state
== AQ_STATE_NONE
);
181 /* Loop through, blanking the queue entries */
184 aq
.aq_state
= AQ_STATE_SETUP
;
188 AIODiskIOStrategy::statfs(StoreEntry
&) const
192 AIODiskIOStrategy::getOptionTree() const
198 * find a free aio slot.
199 * Return the index, or -1 if we can't find one.
202 AIODiskIOStrategy::findSlot()
204 /* Later we should use something a little more .. efficient :) */
206 for (int i
= 0; i
< MAX_ASYNCOP
; ++i
) {
207 if (aq
.aq_queue
[i
].aq_e_state
== AQ_ENTRY_FREE
)