XRootD
Loading...
Searching...
No Matches
XrdXrootdXeqPgrw.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d X r o o t d X e q P g r w . c c */
4/* */
5/* (c) 2020 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Department of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#include <cctype>
31#include <cstdio>
32#include <sys/uio.h>
33
36
38
39#include "Xrd/XrdBuffer.hh"
40#include "Xrd/XrdLink.hh"
41#include "XrdOuc/XrdOucCRC.hh"
55
56/******************************************************************************/
57/* G l o b a l s */
58/******************************************************************************/
59
61
62namespace
63{
64static const int pgPageSize = XrdProto::kXR_pgPageSZ;
65static const int pgPageMask = XrdProto::kXR_pgPageSZ-1;
66static const int pgUnitSize = XrdProto::kXR_pgUnitSZ;
67}
68
69namespace
70{
71static const int pgAioMin = XrdXrootdPgrwAio::aioSZ
72 + XrdXrootdPgrwAio::aioSZ*8/10; // 1.8 of aiosz
73static const int pgAioHalf= XrdXrootdPgrwAio::aioSZ/2;
74}
75
76/******************************************************************************/
77/* d o _ P g C l o s e */
78/******************************************************************************/
79
80bool XrdXrootdProtocol::do_PgClose(XrdXrootdFile *fP, int &rc)
81{
82 XrdXrootdPgwFob *fobP = fP->pgwFob;
83 int numErrs, numFixes, numLeft;
84
85// Make sure we have a fob
86//
87 if (!fobP) return true;
88
89// Obtain the checksum status of this file and update statistics
90//
91 numLeft = fobP->numOffs(&numErrs, &numFixes);
92 fP->Stats.pgUpdt(numErrs, numFixes, numLeft);
93
94// If there are uncorrected checksum, indicate failure. These will be logged
95// when the fob is deleted later on.
96//
97 if (numLeft)
98 {char ebuff[128];
99 snprintf(ebuff,sizeof(ebuff),"%d uncorrected checksum errors",numLeft);
100 rc = Response.Send(kXR_ChkSumErr, ebuff);
101 return false;
102 }
103
104// All is well
105//
106 return true;
107}
108
109/******************************************************************************/
110/* d o _ P g R e a d */
111/******************************************************************************/
112
113int XrdXrootdProtocol::do_PgRead()
114{
115 int pathID;
117 numReads++;
118
119// Unmarshall the data
120//
121 IO.IOLen = ntohl(Request.pgread.rlen);
122 n2hll(Request.pgread.offset, IO.Offset);
123
124// Perform a sanity check on the length
125//
126 if (IO.IOLen <= 0)
127 return Response.Send(kXR_ArgInvalid, "Read length is invalid");
128
129// Find the file object
130//
131 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
133 "pgread does not refer to an open file");
134
135// Now handle the optional pathid and reqflags arguments.
136//
137 IO.Flags = 0;
138 if (!Request.header.dlen) pathID = 0;
140 pathID = static_cast<int>(rargs->pathid);
141 if (Request.header.dlen > 1)
142 IO.Flags = static_cast<unsigned short>(rargs->reqflags);
143 }
144
145// Trace this
146//
147 TRACEP(FSIO,pathID<<" pgread "<<IO.IOLen<<'@'<<IO.Offset
148 <<" fn=" <<IO.File->FileKey);
149
150// If we are monitoring, insert a read entry
151//
152 if (Monitor.InOut())
155
156// Do statistics. They will not always be accurate because we may not be
157// able to fully complete the I/O from the file. Note that we also count
158// the checksums which a questionable practice.
159//
161
162// Use synchronous reads unless async I/O is allowed, the read size is
163// sufficient, and there are not too many async operations in flight.
164//
165 if (IO.File->AsyncMode && IO.IOLen >= pgAioMin
166 && IO.Offset+IO.IOLen <= IO.File->Stats.fSize+pgAioHalf
170 XrdXrootdPgrwAio *aioP;
171 int rc;
172
173 if (!pathID) pP = this;
174 else {if (!(pP = VerifyStream(rc, pathID, false))) return rc;
175 if (pP->linkAioReq >= as_maxperlnk) pP = 0;
176 }
177
178 if (pP && (aioP = XrdXrootdPgrwAio::Alloc(pP, pP->Response, IO.File)))
179 {if (!IO.File->aioFob) IO.File->aioFob = new XrdXrootdAioFob;
180 aioP->Read(IO.Offset, IO.IOLen);
181 return 0;
182 }
183 SI->AsyncRej++;
184 }
185
186// See if an alternate path is required, offload the read
187//
188 if (pathID) return do_Offload(&XrdXrootdProtocol::do_PgRIO, pathID);
189
190// Now do the read on the main path
191//
192 return do_PgRIO();
193}
194
195/******************************************************************************/
196/* d o _ P g R I O */
197/******************************************************************************/
198
199// IO.File = file to be read
200// IO.Offset = Offset at which to read
201// IO.IOLen = Number of bytes to read from file and write to socket
202
203int XrdXrootdProtocol::do_PgRIO()
204{
205// We restrict the maximum transfer size to generate no more than 1023 iovec
206// elements where the first is used for the header.
207//
208 static int iovmax = -1;
209 if (iovmax == -1) {
210#ifdef _SC_IOV_MAX
211 iovmax = sysconf(_SC_IOV_MAX);
212 if (iovmax == -1)
213#endif
214#ifdef IOV_MAX
215 iovmax = IOV_MAX;
216#else
217 iovmax = 1024;
218#endif
219 }
220 static const int maxIOVZ = iovmax;
221 static const int maxCSSZ = iovmax/2 - 1;
222 static const int maxPGRD = maxCSSZ*pgPageSize; // 2,093,056 usually
223 static const int infoLen = sizeof(kXR_int64);
224
225 struct pgReadResponse
227 kXR_int64 ofs;
228 } pgrResp;
229
230 XrdSfsFile *sfsP = IO.File->XrdSfsp;
231 uint64_t pgrOpts = 0;
232 int dlen, fLen, lLen, rc, xframt, Quantum;
233 uint32_t csVec[maxCSSZ];
234 struct iovec iov[maxIOVZ];
235
236// Set flags, as needed
237//
239
240// Preinitialize the header
241//
242 pgrResp.rsp.bdy.requestid = kXR_pgread - kXR_1stRequest;
243 pgrResp.rsp.bdy.resptype = XrdProto::kXR_PartialResult;;
244 memset(pgrResp.rsp.bdy.reserved, 0, sizeof(pgrResp.rsp.bdy.reserved));
245
246// Calculate the total pages in the read request. Note that the first and
247// last pages may require short reads if they are not fully aligned.
248//
249 int pgOff, rPages, rLen = IO.IOLen;
250 rPages = XrdOucPgrwUtils::csNum(IO.Offset, IO.IOLen) * pgPageSize;
251
252// Compute the quantum.
253//
254 Quantum = (maxPGRD > maxBuffsz ? maxBuffsz : maxPGRD);
255 if (rPages < Quantum) Quantum = rPages;
256
257// Make sure we have a large enough buffer. We may need to adjust it downward
258// due to reallocation rounding.
259//
260 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
261 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
262 else if (hcNow < hcNext) hcNow++;
263 if (argp->bsize > maxPGRD) Quantum = maxPGRD;
264
265// Compute the number of iovec elements we need plus one for the header. The
266// Quantum is gauranteed to be a multiple of pagesize now. Verify that this
267// calculation was indeed correct to avoid overwriting the stack.
268//
269 int items = Quantum / pgPageSize;
270 if (items > maxCSSZ)
271 return Response.Send(kXR_Impossible, "pgread logic error 1");
272
273// Preinitialize the io vector for checksums and data (leave 1st element free).
274//
275 uint32_t *csVP = csVec;
276 char *buff = argp->buff;
277 int i = 1, n = items * 2;
278 while(i < n)
279 {iov[i ].iov_base = csVP++;
280 iov[i++].iov_len = sizeof(uint32_t);
281 iov[i ].iov_base = buff;
282 iov[i++].iov_len = pgPageSize;
283 buff += pgPageSize;
284 }
285
286// If this is an unaligned read, offset the unaligned segment in the buffer
287// so that remaining pages are page-aligned. It will be reset when needed.
288// We also calculate the actual length of the first read.
289//
290 if ((pgOff = IO.Offset & pgPageMask))
291 {rLen = pgPageSize - pgOff;
292 buff = argp->buff + pgOff;
293 iov[2].iov_base = buff;
294 iov[2].iov_len = rLen;
295 rLen += Quantum - pgPageSize;
296 } else {
297 rLen = Quantum;
298 buff = argp->buff;
299 }
300 if (IO.IOLen < rLen) rLen = IO.IOLen;
301
302// Now read all of the data. For each read we must recacalculate the number
303// of iovec elements that we will use to send the data as fewer bytes may have
304// been read. In fact, no bytes may have been read.
305//
306 long long ioOffset = IO.Offset;
307 do {if ((xframt = sfsP->pgRead(IO.Offset, buff, rLen, csVec, pgrOpts)) <= 0)
308 break;
309
310 items = XrdOucPgrwUtils::csNum(IO.Offset, xframt, fLen, lLen);
311 iov[2].iov_len = fLen;
312 if (items > 1) iov[items<<1].iov_len = lLen;
313
314 if (xframt < rLen || xframt == IO.IOLen)
315 {pgrResp.rsp.bdy.resptype = XrdProto::kXR_FinalResult;
316 IO.IOLen = 0;
317 } else {
318 IO.IOLen -= xframt; IO.Offset += xframt;
319 rLen = (IO.IOLen < Quantum ? IO.IOLen : Quantum);
320 }
321
322 for (int i = 0; i < items; i++) csVec[i] = htonl(csVec[i]);
323
324 pgrResp.ofs = htonll(ioOffset);
325// char trBuff[512];
326// snprintf(trBuff, sizeof(trBuff), "Xeq PGR: %d@%lld (%lld)\n",
327// xframt, ioOffset, ioOffset>>12);
328// std::cerr<<trBuff<<std::flush;
329 dlen = xframt + (items * sizeof(uint32_t));
330 if ((rc = Response.Send(pgrResp.rsp, infoLen, iov, items*2+1, dlen)) < 0)
331 return rc;
332
333 if (pgOff)
334 {iov[2].iov_base = argp->buff;
335 iov[2].iov_len = pgPageSize;
336 buff = argp->buff;
337 pgOff = 0;
338 }
339
340 ioOffset = IO.Offset;
341 } while(IO.IOLen > 0);
342
343// Determine why we ended here
344//
345 if (xframt < 0) return fsError(xframt, 0, sfsP->error, 0, 0);
346
347// Return no bytes if we were tricked into sending a partial result
348//
349 if (pgrResp.rsp.bdy.resptype != XrdProto::kXR_FinalResult)
350 {pgrResp.rsp.bdy.resptype = XrdProto::kXR_FinalResult;
351 pgrResp.rsp.bdy.dlen = 0;
352 pgrResp.ofs = htonll(IO.Offset);
353 return Response.Send(pgrResp.rsp, infoLen);
354 }
355 return 0;
356}
357
358/******************************************************************************/
359/* d o _ P g W r i t e */
360/******************************************************************************/
361
362int XrdXrootdProtocol::do_PgWrite()
363{
365 int pathID;
366 numWrites++;
367
368// Unmarshall the data
369//
371 n2hll(Request.pgwrite.offset, IO.Offset);
372 pathID = Request.pgwrite.pathid;
373 IO.Flags = static_cast<unsigned short>(Request.pgwrite.reqflags);
374
375// Perform a sanity check on the length.
376//
377 if (IO.IOLen <= (int)sizeof(kXR_unt32))
378 {Response.Send(kXR_ArgInvalid, "pgwrite length is invalid");
379 return Link->setEtext("pgwrite protocol violation");
380 }
381
382// Validate pathid, at least as much as we need to. If it's wrong then we
383// don't know where the data is and we just let it go.
384//
385 if (pathID && (pathID >= maxStreams || !Stream[pathID]))
386 return Response.Send(kXR_ArgInvalid, "invalid path ID");
387
388// Find the file object
389//
390 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
391 {IO.File = 0;
392 return do_WriteNone(pathID);
393 }
394
395// If the file object does not have a pgWrite object, allocate one.
396//
397 if (IO.File->pgwFob == 0) IO.File->pgwFob = new XrdXrootdPgwFob(IO.File);
398
399// Trace this
400//
401 TRACEP(FSIO, pathID<<" pgwrite "
402 <<(IO.Flags & XrdProto::kXR_pgRetry ? "retry " : "")
403 <<IO.IOLen<<'@'<<IO.Offset<<" fn=" <<IO.File->FileKey);
404
405// Do statistics. They will not always be accurate because we may not be
406// able to fully complete the I/O to the file. Note that we also count
407// the checksums which a questionable practice.
408//
410
411// If we are monitoring, insert a write entry
412//
413 if (Monitor.InOut())
416
417// See if an alternate path is required, offload the write
418//
419 if (pathID) return do_Offload(&XrdXrootdProtocol::do_PgWIO, pathID);
420
421// Now do the write on the main path
422//
423 return do_PgWIO(true);
424}
425
426/******************************************************************************/
427/* d o _ P g W A I O */
428/******************************************************************************/
429
430// IO.File = file to be written
431// IO.Offset = Offset at which to write
432// IO.IOLen = Number of bytes to read from socket
433// IO.Flags = Flags associated with request
434
435bool XrdXrootdProtocol::do_PgWAIO(int &rc)
436{
437 XrdXrootdPgrwAio *aioP;
438
439// Make sure the client is fast enough to do this
440//
441 if (myStalls >= as_maxstalls)
442 {SI->AsyncRej++;
443 myStalls--;
444 return false;
445 }
446
447// Allocate an aio request object
448//
449 if (!(aioP = XrdXrootdPgrwAio::Alloc(this, Response, IO.File, pgwCtl)))
450 {SI->AsyncRej++;
451 return false;
452 }
453
454// Issue the write request
455//
456 rc = aioP->Write(IO.Offset, IO.IOLen);
457 return true;
458}
459
460/******************************************************************************/
461/* d o _ P g W I O */
462/******************************************************************************/
463
464// IO.File = file to be written
465// IO.Offset = Offset at which to write
466// IO.IOLen = Number of bytes to read from socket
467// IO.Flags = Flags associated with request
468
469int XrdXrootdProtocol::do_PgWIO() {return do_PgWIO(true);}
470
471int XrdXrootdProtocol::do_PgWIO(bool isFresh)
472{
473 struct iovec *ioV;
474 XrdSfsFile *sfsP = IO.File->XrdSfsp;
475 const char *eMsg;
476 char *buff;
477 kXR_unt32 *csVec;
478 int n, rc, Quantum, iovLen, iovNum, csNum;
479 bool isRetry = (IO.Flags & XrdProto::kXR_pgRetry) != 0;
480
481// Verify that we still have a control area and allocate a control object
482// if we do not have one already. The object stays around until disconnect.
483//
484 if (!IO.File->pgwFob)
485 return do_WriteNone(PathID, kXR_Impossible, "pgwrite logic error 1");
486 if (!pgwCtl) pgwCtl = new XrdXrootdPgwCtl(PathID);
487
488// If this is the first entry then check if the request is eligible for async
489// I/O or if this is a retry request which, of course, is not eligible.
490//
491 if (isFresh)
492 {if (IO.File->AsyncMode && IO.IOLen >= pgAioMin
494 && !isRetry && do_PgWAIO(rc)) return rc;
495 if (isRetry && !do_PgWIORetry(rc)) return rc;
496 if (!do_PgWIOSetup(pgwCtl)) return -1;
497 }
498
499// Either complete the current frame or start a new one. When we start a new
500// one, the I/O will not return unless all of the data was successfully read.
501// Hence, we update the length outstanding.
502//
503do{if (isFresh)
504 {if (!(ioV = pgwCtl->FrameInfo(iovNum, iovLen))) break;
505 IO.IOLen -= iovLen;
506 if ((rc = getData(this, "pgwrite", ioV, iovNum))) return rc;
507 }
508
509// We now have all the data, get checksum and data information
510//
511 if (!(csVec = pgwCtl->FrameInfo(csNum, buff, Quantum, argp)))
512 return do_WriteNone(PathID, kXR_Impossible, "pgwrite logic error 2");
513
514// Convert checksums to host byte order
515//
516 for (int i = 0; i < csNum; i++) csVec[i] = ntohl(csVec[i]);
517
518// Verify the checksums
519//
520 XrdOucPgrwUtils::dataInfo dInfo(buff, csVec, IO.Offset, Quantum);
521 off_t bado;
522 int badc;
523 bool aOK = true;
524
525 while(dInfo.count > 0 && !XrdOucPgrwUtils::csVer(dInfo, bado, badc))
526 {if ((eMsg = pgwCtl->boAdd(IO.File, bado, badc)))
527 return do_WriteNone(PathID, kXR_TooManyErrs, eMsg);
528 aOK = false;
529 }
530
531// Write the data out. The callee is responsible for unaligned writes!
532//
533 if ((rc = sfsP->pgWrite(IO.Offset, buff, Quantum, csVec)) <= 0)
534 {IO.EInfo[0] = rc; IO.EInfo[1] = 0;
535 return do_WriteNone();
536 }
537
538// If this was a successful retry write, remove corrrected offset
539//
540 if (aOK && IO.Flags & XrdProto::kXR_pgRetry)
541 IO.File->pgwFob->delOffs(IO.Offset, Quantum);
542
543// Update offset and advance to next frame
544//
545 IO.Offset += Quantum;
546 isFresh = true;
547
548 } while(pgwCtl->Advance());
549
550
551// Return final result
552//
553 buff = pgwCtl->boInfo(n);
554 return Response.Send(pgwCtl->resp, sizeof(pgwCtl->info), buff, n);
555}
556
557/******************************************************************************/
558/* d o _ P g W I O R e t r y */
559/******************************************************************************/
560
561// IO.File = file to be written
562// IO.Offset = Offset at which to write
563// IO.IOLen = Number of bytes to read from socket
564// IO.Flags = Flags associated with request
565
566bool XrdXrootdProtocol::do_PgWIORetry(int &rc)
567{
568 static const int csLen = sizeof(kXR_unt32);
569 bool isBad;
570
571// Make sure the write does not cross a page bounday. For unaligned writes we
572// can compute the exact length that we need. Otherwise, it can't be bigger
573// than a unit's worth of data. Not precise but usually good enough.
574//
575 if (IO.Offset & pgPageMask)
576 {int n = pgPageSize - (IO.Offset & pgPageMask);
577 isBad = IO.IOLen > (n + csLen);
578 } else isBad = IO.IOLen > pgUnitSize;
579
580// Deep six the write if it violates retry rules.
581//
582 if (isBad)
583 {rc = do_WriteNone(PathID, kXR_ArgInvalid,
584 "pgwrite retry of more than one page not allowed");
585 return false;
586 }
587
588// Make sure that the offset is registered, if it is not, treat this as a
589// regular write as this may have been a resend during write recovery.
590//
591 if (!IO.File->pgwFob->hasOffs(IO.Offset, IO.IOLen - csLen))
592 {char buff[64];
593 snprintf(buff, sizeof(buff), "retry %d@%lld", IO.IOLen-csLen, IO.Offset);
594 eDest.Emsg("pgwRetry", buff, "not in error; fn=", IO.File->FileKey);
595 IO.Flags &= ~XrdProto::kXR_pgRetry;
596 }
597
598// We can proceed with this write now.
599//
600 return true;
601}
602
603/******************************************************************************/
604/* d o _ P g w I O S e t u p */
605/******************************************************************************/
606
607// IO.File = file to be written
608// IO.Offset = Offset at which to write
609// IO.IOLen = Number of bytes to read from socket
610// IO.Flags = Flags associated with request
611
612bool XrdXrootdProtocol::do_PgWIOSetup(XrdXrootdPgwCtl *pgwCtl)
613{
614 const char *eMsg;
615 int Quantum;
616
617// Compute the minimum (4K) or maximum buffer size we will use.
618//
620 Quantum = (IO.IOLen < pgPageSize ? pgPageSize : IO.IOLen);
621 else Quantum = XrdXrootdPgwCtl::maxBSize;
622
623// Make sure we have a large enough buffer
624//
625 if (!argp || Quantum < halfBSize || argp->bsize < Quantum
627 {if (getBuff(0, Quantum) <= 0) return -1;}
628 else if (hcNow < hcNext) hcNow++;
629
630// Do the setup. If it fails then either the client sent an incorrect stream
631// of the header was corrupted. In either case, it doesn't matter as we can't
632// depend on the information to clear the stream. So, we close the connection.
633//
634 if ((eMsg = pgwCtl->Setup(argp, IO.Offset, IO.IOLen)))
636 Link->setEtext("pgwrite protocol violation");
637 return false;
638 }
639 return true;
640}
@ kXR_ArgInvalid
Definition XProtocol.hh:988
@ kXR_Impossible
@ kXR_TooManyErrs
@ kXR_ChkSumErr
@ kXR_FileNotOpen
Definition XProtocol.hh:992
kXR_char fhandle[4]
Definition XProtocol.hh:531
struct ClientPgReadRequest pgread
Definition XProtocol.hh:859
struct ClientPgWriteRequest pgwrite
Definition XProtocol.hh:860
struct ClientRequestHdr header
Definition XProtocol.hh:844
kXR_char fhandle[4]
Definition XProtocol.hh:509
@ kXR_1stRequest
Definition XProtocol.hh:111
@ kXR_pgread
Definition XProtocol.hh:142
long long kXR_int64
Definition XPtypes.hh:98
unsigned int kXR_unt32
Definition XPtypes.hh:90
XrdOucString File
#define eMsg(x)
#define TRACEP(act, x)
XrdSysTrace XrdXrootdTrace
char * buff
Definition XrdBuffer.hh:45
static bool csVer(dataInfo &dInfo, off_t &bado, int &badc)
static int csNum(off_t offs, int count)
Compute the required size of a checksum vector based on offset & length.
static const uint64_t Verify
Options for pgRead() and pgWrite() as noted below.
XrdOucErrInfo & error
virtual XrdSfsXferSize pgRead(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize rdlen, uint32_t *csvec, uint64_t opts=0)
virtual XrdSfsXferSize pgWrite(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize wrlen, uint32_t *csvec, uint64_t opts=0)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void pgrOps(int rsz, bool isRetry=false)
void pgwOps(int wsz, bool isRetry=false)
void pgUpdt(int wErrs, int wFixd, int wUnc)
XrdXrootdFile * Get(int fnum)
XrdXrootdPgwFob * pgwFob
XrdSfsFile * XrdSfsp
XrdXrootdAioFob * aioFob
XrdXrootdFileStats Stats
XrdXrootdMonitor * Agent
void Add_rd(kXR_unt32 dictid, kXR_int32 rlen, kXR_int64 offset)
void Add_wr(kXR_unt32 dictid, kXR_int32 wlen, kXR_int64 offset)
static const int aioSZ
void Read(long long offs, int dlen) override
static XrdXrootdPgrwAio * Alloc(XrdXrootdProtocol *protP, XrdXrootdResponse &resp, XrdXrootdFile *fP, XrdXrootdPgwBadCS *bcsP=0)
int Write(long long offs, int dlen) override
const char * boAdd(XrdXrootdFile *fP, kXR_int64 foffs, int dlen=XrdProto::kXR_pgPageSZ)
char * boInfo(int &boLen)
ServerResponseStatus resp
struct iovec * FrameInfo(int &iovn, int &rdlen)
static const int maxBSize
const char * Setup(XrdBuffer *buffP, kXR_int64 fOffs, int totlen)
ServerResponseBody_pgWrite info
bool hasOffs(kXR_int64 foffs, int dlen)
bool delOffs(kXR_int64 foffs, int dlen)
int numOffs(int *errs=0, int *fixs=0)
static XrdXrootdStats * SI
XrdXrootdProtocol * VerifyStream(int &rc, int pID, bool lok=true)
XrdXrootdProtocol * Stream[maxStreams]
XrdXrootd::IOParms IO
XrdXrootdPgwCtl * pgwCtl
XrdXrootdFileTable * FTab
static XrdSysError & eDest
int getData(gdCallBack *gdcbP, const char *dtype, char *buff, int blen)
XrdXrootdMonitor::User Monitor
XrdXrootdResponse Response
static const int maxStreams
static RAtomic_int srvrAioOps
static const int kXR_pgUnitSZ
Definition XProtocol.hh:496
static const int kXR_pgPageSZ
Definition XProtocol.hh:494
@ kXR_PartialResult
@ kXR_FinalResult
static const int kXR_pgRetry
Definition XProtocol.hh:503