UFSStoreState.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 79 Storage Manager UFS Interface */
10
11#include "squid.h"
12#include "DiskIO/DiskFile.h"
14#include "DiskIO/ReadRequest.h"
15#include "DiskIO/WriteRequest.h"
16#include "Generic.h"
17#include "SquidConfig.h"
18#include "Store.h"
19#include "store/Disk.h"
20#include "UFSStoreState.h"
21#include "UFSStrategy.h"
22
24
25void
27{
28 if (opening) {
29 opening = false;
30 debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
31 swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
32 std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
33 std::dec << theFile->error());
34
35 assert (FILE_MODE(mode) == O_RDONLY);
36 openDone();
37
38 return;
39 }
40
41 if (creating) {
42 creating = false;
43 debugs(79, 3, "UFSStoreState::ioCompletedNotification: dirno " <<
44 swap_dirn << ", fileno "<< std::setfill('0') << std::hex <<
45 std::setw(8) << swap_filen << " status "<< std::setfill(' ') <<
46 std::dec << theFile->error());
47
48 openDone();
49
50 return;
51 }
52
53 assert (!(closing ||opening));
54 debugs(79, 3, "diskd::ioCompleted: dirno " << swap_dirn << ", fileno "<<
55 std::setfill('0') << std::hex << std::setw(8) << swap_filen <<
56 " status "<< std::setfill(' ') << std::dec << theFile->error());
57
58 /* Ok, notification past open means an error has occurred */
59 assert (theFile->error());
60 tryClosing();
61}
62
63void
65{
66 if (closing)
67 debugs(0, DBG_CRITICAL, "already closing in openDone()!?");
68
69 if (theFile->error()) {
70 tryClosing();
71 return;
72 }
73
74 if (FILE_MODE(mode) == O_WRONLY) {
75 drainWriteQueue();
76
77 } else if ((FILE_MODE(mode) == O_RDONLY) && !closing) {
78 if (kickReadQueue())
79 return;
80 }
81
82 if (flags.try_closing)
83 tryClosing();
84
85 debugs(79, 3, "UFSStoreState::openDone: exiting");
86}
87
88void
90{
91 assert (closing);
92 debugs(79, 3, "UFSStoreState::closeCompleted: dirno " << swap_dirn <<
93 ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
94 swap_filen << " status "<< std::setfill(' ') << std::dec <<
95 theFile->error());
96
97 if (theFile->error()) {
98 debugs(79,3, "theFile->error() ret " << theFile->error());
99 doCloseCallback(DISK_ERROR);
100 } else {
101 doCloseCallback(DISK_OK);
102 }
103
104 closing = false;
105}
106
107/*
108 * DPW 2006-05-24
109 * This close function is called by the higher layer when it has finished
110 * reading/writing everything, or otherwise wants to close the swap
111 * file. In the case of writing and using aufs storage, close() might
112 * be called before any/all data is written, and even before the open
113 * callback occurs. Thus, we use our tryClosing() method, which knows
114 * when it is safe to actually signal the lower layer for closing.
115 */
116void
118{
119 debugs(79, 3, "UFSStoreState::close: dirno " << swap_dirn << ", fileno "<<
120 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
121 tryClosing(); // UFS does not distinguish different closure types
122}
123
124void
125Fs::Ufs::UFSStoreState::read_(char *buf, size_t size, off_t aOffset, STRCB * aCallback, void *aCallbackData)
126{
127 assert(read.callback == nullptr);
128 assert(read.callback_data == nullptr);
129 assert(!reading);
130 assert(!closing);
131 assert (aCallback);
132
133 if (!theFile->canRead()) {
134 debugs(79, 3, "queueing read because theFile can't read");
135 assert(opening);
136 pending_reads.emplace(buf, size, aOffset, aCallback, aCallbackData);
137 return;
138 }
139
140 read.callback = aCallback;
141 read.callback_data = cbdataReference(aCallbackData);
142 debugs(79, 3, "UFSStoreState::read_: dirno " << swap_dirn << ", fileno "<<
143 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
144 offset_ = aOffset;
145 read_buf = buf;
146 reading = true;
147 theFile->read(new ReadRequest(buf,aOffset,size));
148}
149
150/*
151 * DPW 2006-05-24
152 * This, the public write interface, places the write request at the end
153 * of the pending_writes queue to ensure correct ordering of writes.
154 * We could optimize things a little if there are no other pending
155 * writes and just do the write directly. But for now we'll keep the
156 * code simpler and always go through the pending_writes queue.
157 */
158bool
159Fs::Ufs::UFSStoreState::write(char const *buf, size_t size, off_t aOffset, FREE * free_func)
160{
161 debugs(79, 3, "UFSStoreState::write: dirn " << swap_dirn << ", fileno "<<
162 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen);
163
164 if (theFile->error()) {
165 debugs(79, DBG_IMPORTANT, "ERROR: avoid write on theFile with error");
166 debugs(79, DBG_IMPORTANT, "calling free_func for " << (void*) buf);
167 free_func((void*)buf);
168 return false;
169 }
170
171 const Store::Disk &dir = *INDEXSD(swap_dirn);
172 if (static_cast<uint64_t>(offset_ + size) > static_cast<uint64_t>(dir.maxObjectSize())) {
173 debugs(79, 2, "accepted unknown-size entry grew too big: " <<
174 (offset_ + size) << " > " << dir.maxObjectSize());
175 free_func((void*)buf);
176 tryClosing();
177 return false;
178 }
179
180 debugs(79, 3, (void*)this << " queueing write of size " << size);
181 pending_writes.emplace(buf, size, aOffset, free_func);
182 drainWriteQueue();
183 return true;
184}
185
186/*
187 * DPW 2006-05-24
188 * This, the private write method, calls the lower level write for the
189 * first write request in the pending_writes queue. doWrite() is only
190 * called by drainWriteQueue().
191 */
192void
194{
195 debugs(79, 3, (void*)this);
196
197 assert(theFile->canWrite());
198
199 if (pending_writes.empty()) {
200 debugs(79, 3, (void*)this << " write queue is empty");
201 return;
202 }
203
204 auto &q = pending_writes.front();
205
206 if (theFile->error()) {
207 debugs(79, DBG_IMPORTANT, "ERROR: " << MYNAME << "avoid write on theFile with error");
208 pending_writes.pop();
209 return;
210 }
211
212 /*
213 * DPW 2006-05-24
214 * UFSStoreState has a 'writing' flag that we used to set here,
215 * but it wasn't really used anywhere. In fact, some lower
216 * layers such as DISKD allow multiple outstanding writes, which
217 * makes the boolean writing flag meaningless. We would need
218 * a counter to keep track of writes going out and write callbacks
219 * coming in. For now let's just not use the writing flag at
220 * all.
221 */
222 debugs(79, 3, (void*)this << " calling theFile->write(" << q.size << ")");
223
224 theFile->write(new WriteRequest(q.buf, q.offset, q.size, q.free_func));
225 q.buf = nullptr; // prevent buf deletion on pop, its used by the above object
226 pending_writes.pop();
227}
228
229void
231{
232 assert (result.getRaw());
233 reading = false;
234 debugs(79, 3, "UFSStoreState::readCompleted: dirno " << swap_dirn <<
235 ", fileno "<< std::setfill('0') << std::hex << std::setw(8) <<
236 swap_filen << " len "<< std::setfill(' ') << std::dec << len);
237
238 if (len > 0)
239 offset_ += len;
240
241 STRCB *callback_ = read.callback;
242
243 assert(callback_);
244
245 read.callback = nullptr;
246
247 void *cbdata;
248
249 /* A note:
250 * diskd IO queues closes via the diskd queue. So close callbacks
251 * occur strictly after reads and writes.
252 * ufs doesn't queue, it simply completes, so close callbacks occur
253 * strictly after reads and writes.
254 * aufs performs closes synchronously, so close events must be managed
255 * to force strict ordering.
256 * The below does this:
257 * closing is set when theFile->close() has been called, and close only triggers
258 * when no io's are pending.
259 * writeCompleted likewise.
260 */
261 if (!closing && cbdataReferenceValidDone(read.callback_data, &cbdata)) {
262 if (len > 0 && read_buf != buf)
263 memcpy(read_buf, buf, len);
264
265 callback_(cbdata, read_buf, len, this);
266 }
267
268 if (flags.try_closing || (theFile != nullptr && theFile->error()) )
269 tryClosing();
270}
271
272void
274{
275 debugs(79, 3, "dirno " << swap_dirn << ", fileno " <<
276 std::setfill('0') << std::hex << std::uppercase << std::setw(8) << swap_filen <<
277 ", len " << len);
278 /*
279 * DPW 2006-05-24
280 * See doWrites() for why we don't update UFSStoreState::writing
281 * here anymore.
282 */
283
284 offset_ += len;
285
286 if (theFile->error()) {
287 debugs(79,2, " detected an error, will try to close");
288 tryClosing();
289 }
290
291 /*
292 * HNO 2009-07-24
293 * Kick any pending write/close operations alive
294 */
295 drainWriteQueue();
296}
297
298void
300{
301 debugs(79, 3, "storeUfsIOCallback: errflag=" << errflag);
302 /*
303 * DPW 2006-05-24
304 * When we signal the higher layer with this callback, it might unlock
305 * the StoreEntry and its associated data. We must "free" any queued
306 * I/Os (especially writes) now, otherwise the StoreEntry's mem_node's
307 * will have their write_pending flag set, and we'll get an assertion.
308 */
309 freePending();
310 STIOCB *theCallback = callback;
311 callback = nullptr;
312
313 void *cbdata;
314
315 if (cbdataReferenceValidDone(callback_data, &cbdata) && theCallback)
316 theCallback(cbdata, errflag, this);
317
318 /*
319 * We are finished with theFile since the lower layer signalled
320 * us that the file has been closed. This must be the last line,
321 * as theFile may be the only object holding us in memory.
322 */
323 theFile = nullptr; // refcounted
324}
325
326/* ============= THE REAL UFS CODE ================ */
327
328Fs::Ufs::UFSStoreState::UFSStoreState(SwapDir * SD, StoreEntry * anEntry, STIOCB * cbIo, void *data) :
329 StoreIOState(cbIo, data),
330 opening(false),
331 creating(false),
332 closing(false),
333 reading(false),
334 writing(false),
335 read_buf(nullptr)
336{
337 // StoreIOState inherited members
338 swap_filen = anEntry->swap_filen;
339 swap_dirn = SD->index;
340 e = anEntry;
341
342 // our flags
343 flags.write_draining = false;
344 flags.try_closing = false;
345}
346
348{
349 assert(pending_reads.empty());
350 assert(pending_writes.empty());
351}
352
353void
355{
356 while (!pending_reads.empty())
357 pending_reads.pop();
358 debugs(79, 3, "freed pending reads");
359
360 while (!pending_writes.empty())
361 pending_writes.pop();
362 debugs(79, 3, "freed pending writes");
363}
364
365bool
367{
368 if (pending_reads.empty())
369 return false;
370
371 auto &q = pending_reads.front();
372
373 debugs(79, 3, "reading queued request of " << q.size << " bytes");
374
375 bool result = true;
376 void *cbdata;
377 if (cbdataReferenceValidDone(q.callback_data, &cbdata)) {
378 read_(q.buf, q.size, q.offset, q.callback, cbdata);
379 } else {
380 debugs(79, 2, "this=" << (void*)this << " cbdataReferenceValidDone returned false." <<
381 " closing: " << closing << " flags.try_closing: " << flags.try_closing);
382 result = false;
383 }
384
385 pending_reads.pop(); // erase the front object
386 return result;
387}
388
389/*
390 * DPW 2006-05-24
391 * drainWriteQueue() is a loop around doWrite().
392 */
393void
395{
396 /*
397 * DPW 2007-04-12
398 * We might find that flags.write_draining is already set
399 * because schemes like diskd can process I/O acks
400 * before sending another I/O request. e.g. the following
401 * sequence of events: open request -> write request ->
402 * drainWriteQueue() -> queue full -> callbacks -> openDone() ->
403 * drainWriteQueue().
404 */
405 if (flags.write_draining)
406 return;
407
408 if (!theFile || !theFile->canWrite())
409 return;
410
411 flags.write_draining = true;
412
413 while (!pending_writes.empty())
414 doWrite();
415
416 flags.write_draining = false;
417
418 if (flags.try_closing)
419 tryClosing();
420}
421
422/*
423 * DPW 2006-05-24
424 * This blows. DiskThreadsDiskFile::close() won't actually do the close
425 * if ioInProgress() is true. So we have to check it here. Maybe someday
426 * DiskThreadsDiskFile::close() will be modified to have a return value,
427 * or will remember to do the close for us.
428 */
429void
431{
432 debugs(79,3, this << " tryClosing()" <<
433 " closing = " << closing <<
434 " flags.try_closing = " << flags.try_closing <<
435 " ioInProgress = " << theFile->ioInProgress());
436
437 if (theFile->ioInProgress()) {
438 debugs(79, 3, this <<
439 " won't close since ioInProgress is true, bailing");
440 flags.try_closing = true;
441 return;
442 }
443
444 closing = true;
445 flags.try_closing = false;
446 theFile->close();
447}
448
int size
Definition: ModDevPoll.cc:75
#define INDEXSD(i)
Definition: SquidConfig.h:74
CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs, UFSStoreState)
#define assert(EX)
Definition: assert.h:17
#define cbdataReference(var)
Definition: cbdata.h:343
#define cbdataReferenceValidDone(var, ptr)
Definition: cbdata.h:239
virtual bool error() const =0
virtual void doCloseCallback(int errflag)
void closeCompleted() override
void read_(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data) override
void writeCompleted(int errflag, size_t len, RefCount< WriteRequest >) override
bool write(char const *buf, size_t size, off_t offset, FREE *free_func) override
UFSStoreState(SwapDir *SD, StoreEntry *anEntry, STIOCB *callback_, void *callback_data_)
void close(int how) override
finish or abort swapping per CloseHow
void readCompleted(const char *buf, int len, int errflag, RefCount< ReadRequest >) override
struct Fs::Ufs::UFSStoreState::@66 flags
RefCount< DiskFile > theFile
Definition: UFSStoreState.h:36
void ioCompletedNotification() override
C * getRaw() const
Definition: RefCount.h:89
sfileno swap_filen
unique ID inside a cache_dir for swapped out entries; -1 for others
Definition: Store.h:236
sfileno swap_filen
Definition: StoreIOState.h:72
StoreEntry * e
Definition: StoreIOState.h:73
sdirno swap_dirn
Definition: StoreIOState.h:71
manages a single cache_dir
Definition: Disk.h:22
int index
Definition: Disk.h:103
int64_t maxObjectSize() const override
the maximum size of a storable object; -1 if unlimited
Definition: Disk.cc:103
Definition: cbdata.cc:38
#define MYNAME
Definition: Stream.h:236
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
#define FILE_MODE(x)
Definition: defines.h:145
#define DISK_ERROR
Definition: defines.h:28
#define DISK_OK
Definition: defines.h:27
void FREE(void *)
Definition: forward.h:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors