UFSStoreState.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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"
13 #include "DiskIO/DiskIOStrategy.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 
23 CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs,UFSStoreState);
24 
25 void
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 occured */
59  assert (theFile->error());
60  tryClosing();
61 }
62 
63 void
65 {
66  if (closing)
67  debugs(0, DBG_CRITICAL, HERE << "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 
88 void
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,HERE<< "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  */
116 void
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 
124 void
125 Fs::Ufs::UFSStoreState::read_(char *buf, size_t size, off_t aOffset, STRCB * aCallback, void *aCallbackData)
126 {
127  assert(read.callback == NULL);
128  assert(read.callback_data == NULL);
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  */
158 bool
159 Fs::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,HERE << "avoid write on theFile with error");
166  debugs(79, DBG_IMPORTANT,HERE << "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  */
192 void
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, 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 
229 void
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 = NULL;
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 syncronously, 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 != NULL && theFile->error()) )
269  tryClosing();
270 }
271 
272 void
274 {
275  debugs(79, 3, HERE << "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,HERE << " 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 
298 void
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 = NULL;
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 = NULL; // refcounted
324 }
325 
326 /* ============= THE REAL UFS CODE ================ */
327 
328 Fs::Ufs::UFSStoreState::UFSStoreState(SwapDir * SD, StoreEntry * anEntry, STIOCB * cbIo, void *data) :
329  StoreIOState(NULL, cbIo, data),
330  opening(false),
331  creating(false),
332  closing(false),
333  reading(false),
334  writing(false),
335  read_buf(NULL)
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 
353 void
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 
365 bool
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  */
393 void
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  */
429 void
431 {
432  debugs(79,3,HERE << 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, HERE << 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 
#define cbdataReferenceValidDone(var, ptr)
Definition: cbdata.h:256
virtual int64_t maxObjectSize() const override
the maximum size of a storable object; -1 if unlimited
Definition: Disk.cc:103
#define assert(EX)
Definition: assert.h:17
virtual void readCompleted(const char *buf, int len, int errflag, RefCount< ReadRequest >)
virtual void ioCompletedNotification()
void const char HLPCB * callback
Definition: stub_helper.cc:16
Definition: cbdata.cc:60
virtual void closeCompleted()
UFSStoreState(SwapDir *SD, StoreEntry *anEntry, STIOCB *callback_, void *callback_data_)
sfileno swap_filen
unique ID inside a cache_dir for swapped out entries; -1 for others
Definition: Store.h:177
#define DBG_CRITICAL
Definition: Debug.h:44
void FREE(void *)
Definition: forward.h:36
#define DISK_ERROR
Definition: defines.h:40
void read_(char *buf, size_t size, off_t offset, STRCB *callback, void *callback_data)
#define FILE_MODE(x)
Definition: defines.h:213
virtual void close(int how)
finish or abort swapping per CloseHow
void const char HLPCB void * data
Definition: stub_helper.cc:16
struct Fs::Ufs::UFSStoreState::@71 flags
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define cbdataReference(var)
Definition: cbdata.h:341
virtual bool error() const =0
#define DBG_IMPORTANT
Definition: Debug.h:45
virtual void writeCompleted(int errflag, size_t len, RefCount< WriteRequest >)
#define INDEXSD(i)
Definition: SquidConfig.h:64
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
CBDATA_NAMESPACED_CLASS_INIT(Fs::Ufs, UFSStoreState)
int index
Definition: Disk.h:97
#define MYNAME
Definition: Debug.h:160
virtual bool write(char const *buf, size_t size, off_t offset, FREE *free_func)
StoreEntry * e
Definition: StoreIOState.h:85
sdirno swap_dirn
Definition: StoreIOState.h:83
virtual void doCloseCallback(int errflag)
RefCount< DiskFile > theFile
Definition: UFSStoreState.h:35
#define DISK_OK
Definition: defines.h:39
C * getRaw() const
Definition: RefCount.h:74
#define NULL
Definition: types.h:166
int size
Definition: ModDevPoll.cc:77
#define false
Definition: GnuRegex.c:233
sfileno swap_filen
Definition: StoreIOState.h:84
manages a single cache_dir
Definition: Disk.h:21

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors