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 const int maxIOVZ = IOV_MAX;
209 static const int maxCSSZ = IOV_MAX/2 - 1;
210 static const int maxPGRD = maxCSSZ*pgPageSize; // 2,093,056 usually
211 static const int infoLen = sizeof(kXR_int64);
212
213 struct pgReadResponse
215 kXR_int64 ofs;
216 } pgrResp;
217
218 XrdSfsFile *sfsP = IO.File->XrdSfsp;
219 uint64_t pgrOpts = 0;
220 int dlen, fLen, lLen, rc, xframt, Quantum;
221 uint32_t csVec[maxCSSZ];
222 struct iovec iov[maxIOVZ];
223
224// Set flags, as needed
225//
227
228// Preinitialize the header
229//
230 pgrResp.rsp.bdy.requestid = kXR_pgread - kXR_1stRequest;
231 pgrResp.rsp.bdy.resptype = XrdProto::kXR_PartialResult;;
232 memset(pgrResp.rsp.bdy.reserved, 0, sizeof(pgrResp.rsp.bdy.reserved));
233
234// Calculate the total pages in the read request. Note that the first and
235// last pages may require short reads if they are not fully aligned.
236//
237 int pgOff, rPages, rLen = IO.IOLen;
238 rPages = XrdOucPgrwUtils::csNum(IO.Offset, IO.IOLen) * pgPageSize;
239
240// Compute the quantum.
241//
242 Quantum = (maxPGRD > maxBuffsz ? maxBuffsz : maxPGRD);
243 if (rPages < Quantum) Quantum = rPages;
244
245// Make sure we have a large enough buffer. We may need to adjust it downward
246// due to reallocation rounding.
247//
248 if (!argp || Quantum < halfBSize || Quantum > argp->bsize)
249 {if ((rc = getBuff(1, Quantum)) <= 0) return rc;}
250 else if (hcNow < hcNext) hcNow++;
251 if (argp->bsize > maxPGRD) Quantum = maxPGRD;
252
253// Compute the number of iovec elements we need plus one for the header. The
254// Quantum is gauranteed to be a multiple of pagesize now. Verify that this
255// calculation was indeed correct to avoid overwriting the stack.
256//
257 int items = Quantum / pgPageSize;
258 if (items > maxCSSZ)
259 return Response.Send(kXR_Impossible, "pgread logic error 1");
260
261// Preinitialize the io vector for checksums and data (leave 1st element free).
262//
263 uint32_t *csVP = csVec;
264 char *buff = argp->buff;
265 int i = 1, n = items * 2;
266 while(i < n)
267 {iov[i ].iov_base = csVP++;
268 iov[i++].iov_len = sizeof(uint32_t);
269 iov[i ].iov_base = buff;
270 iov[i++].iov_len = pgPageSize;
271 buff += pgPageSize;
272 }
273
274// If this is an unaligned read, offset the unaligned segment in the buffer
275// so that remaining pages are page-aligned. It will be reset when needed.
276// We also calculate the actual length of the first read.
277//
278 if ((pgOff = IO.Offset & pgPageMask))
279 {rLen = pgPageSize - pgOff;
280 buff = argp->buff + pgOff;
281 iov[2].iov_base = buff;
282 iov[2].iov_len = rLen;
283 rLen += Quantum - pgPageSize;
284 } else {
285 rLen = Quantum;
286 buff = argp->buff;
287 }
288 if (IO.IOLen < rLen) rLen = IO.IOLen;
289
290// Now read all of the data. For each read we must recacalculate the number
291// of iovec elements that we will use to send the data as fewer bytes may have
292// been read. In fact, no bytes may have been read.
293//
294 long long ioOffset = IO.Offset;
295 do {if ((xframt = sfsP->pgRead(IO.Offset, buff, rLen, csVec, pgrOpts)) <= 0)
296 break;
297
298 items = XrdOucPgrwUtils::csNum(IO.Offset, xframt, fLen, lLen);
299 iov[2].iov_len = fLen;
300 if (items > 1) iov[items<<1].iov_len = lLen;
301
302 if (xframt < rLen || xframt == IO.IOLen)
303 {pgrResp.rsp.bdy.resptype = XrdProto::kXR_FinalResult;
304 IO.IOLen = 0;
305 } else {
306 IO.IOLen -= xframt; IO.Offset += xframt;
307 rLen = (IO.IOLen < Quantum ? IO.IOLen : Quantum);
308 }
309
310 for (int i = 0; i < items; i++) csVec[i] = htonl(csVec[i]);
311
312 pgrResp.ofs = htonll(ioOffset);
313// char trBuff[512];
314// snprintf(trBuff, sizeof(trBuff), "Xeq PGR: %d@%lld (%lld)\n",
315// xframt, ioOffset, ioOffset>>12);
316// std::cerr<<trBuff<<std::flush;
317 dlen = xframt + (items * sizeof(uint32_t));
318 if ((rc = Response.Send(pgrResp.rsp, infoLen, iov, items*2+1, dlen)) < 0)
319 return rc;
320
321 if (pgOff)
322 {iov[2].iov_base = argp->buff;
323 iov[2].iov_len = pgPageSize;
324 buff = argp->buff;
325 pgOff = 0;
326 }
327
328 ioOffset = IO.Offset;
329 } while(IO.IOLen > 0);
330
331// Determine why we ended here
332//
333 if (xframt < 0) return fsError(xframt, 0, sfsP->error, 0, 0);
334
335// Return no bytes if we were tricked into sending a partial result
336//
337 if (pgrResp.rsp.bdy.resptype != XrdProto::kXR_FinalResult)
338 {pgrResp.rsp.bdy.resptype = XrdProto::kXR_FinalResult;
339 pgrResp.rsp.bdy.dlen = 0;
340 pgrResp.ofs = htonll(IO.Offset);
341 return Response.Send(pgrResp.rsp, infoLen);
342 }
343 return 0;
344}
345
346/******************************************************************************/
347/* d o _ P g W r i t e */
348/******************************************************************************/
349
350int XrdXrootdProtocol::do_PgWrite()
351{
353 int pathID;
354 numWrites++;
355
356// Unmarshall the data
357//
359 n2hll(Request.pgwrite.offset, IO.Offset);
360 pathID = Request.pgwrite.pathid;
361 IO.Flags = static_cast<unsigned short>(Request.pgwrite.reqflags);
362
363// Perform a sanity check on the length.
364//
365 if (IO.IOLen <= (int)sizeof(kXR_unt32))
366 {Response.Send(kXR_ArgInvalid, "pgwrite length is invalid");
367 return Link->setEtext("pgwrite protocol violation");
368 }
369
370// Validate pathid, at least as much as we need to. If it's wrong then we
371// don't know where the data is and we just let it go.
372//
373 if (pathID && (pathID >= maxStreams || !Stream[pathID]))
374 return Response.Send(kXR_ArgInvalid, "invalid path ID");
375
376// Find the file object
377//
378 if (!FTab || !(IO.File = FTab->Get(fh.handle)))
379 {IO.File = 0;
380 return do_WriteNone(pathID);
381 }
382
383// If the file object does not have a pgWrite object, allocate one.
384//
385 if (IO.File->pgwFob == 0) IO.File->pgwFob = new XrdXrootdPgwFob(IO.File);
386
387// Trace this
388//
389 TRACEP(FSIO, pathID<<" pgwrite "
390 <<(IO.Flags & XrdProto::kXR_pgRetry ? "retry " : "")
391 <<IO.IOLen<<'@'<<IO.Offset<<" fn=" <<IO.File->FileKey);
392
393// Do statistics. They will not always be accurate because we may not be
394// able to fully complete the I/O to the file. Note that we also count
395// the checksums which a questionable practice.
396//
398
399// If we are monitoring, insert a write entry
400//
401 if (Monitor.InOut())
404
405// See if an alternate path is required, offload the write
406//
407 if (pathID) return do_Offload(&XrdXrootdProtocol::do_PgWIO, pathID);
408
409// Now do the write on the main path
410//
411 return do_PgWIO(true);
412}
413
414/******************************************************************************/
415/* d o _ P g W A I O */
416/******************************************************************************/
417
418// IO.File = file to be written
419// IO.Offset = Offset at which to write
420// IO.IOLen = Number of bytes to read from socket
421// IO.Flags = Flags associated with request
422
423bool XrdXrootdProtocol::do_PgWAIO(int &rc)
424{
425 XrdXrootdPgrwAio *aioP;
426
427// Make sure the client is fast enough to do this
428//
429 if (myStalls >= as_maxstalls)
430 {SI->AsyncRej++;
431 myStalls--;
432 return false;
433 }
434
435// Allocate an aio request object
436//
437 if (!(aioP = XrdXrootdPgrwAio::Alloc(this, Response, IO.File, pgwCtl)))
438 {SI->AsyncRej++;
439 return false;
440 }
441
442// Issue the write request
443//
444 rc = aioP->Write(IO.Offset, IO.IOLen);
445 return true;
446}
447
448/******************************************************************************/
449/* d o _ P g W I O */
450/******************************************************************************/
451
452// IO.File = file to be written
453// IO.Offset = Offset at which to write
454// IO.IOLen = Number of bytes to read from socket
455// IO.Flags = Flags associated with request
456
457int XrdXrootdProtocol::do_PgWIO() {return do_PgWIO(true);}
458
459int XrdXrootdProtocol::do_PgWIO(bool isFresh)
460{
461 struct iovec *ioV;
462 XrdSfsFile *sfsP = IO.File->XrdSfsp;
463 const char *eMsg;
464 char *buff;
465 kXR_unt32 *csVec;
466 int n, rc, Quantum, iovLen, iovNum, csNum;
467 bool isRetry = (IO.Flags & XrdProto::kXR_pgRetry) != 0;
468
469// Verify that we still have a control area and allocate a control object
470// if we do not have one already. The object stays around until disconnect.
471//
472 if (!IO.File->pgwFob)
473 return do_WriteNone(PathID, kXR_Impossible, "pgwrite logic error 1");
474 if (!pgwCtl) pgwCtl = new XrdXrootdPgwCtl(PathID);
475
476// If this is the first entry then check if the request is eligible for async
477// I/O or if this is a retry request which, of course, is not eligible.
478//
479 if (isFresh)
480 {if (IO.File->AsyncMode && IO.IOLen >= pgAioMin
482 && !isRetry && do_PgWAIO(rc)) return rc;
483 if (isRetry && !do_PgWIORetry(rc)) return rc;
484 if (!do_PgWIOSetup(pgwCtl)) return -1;
485 }
486
487// Either complete the current frame or start a new one. When we start a new
488// one, the I/O will not return unless all of the data was successfully read.
489// Hence, we update the length outstanding.
490//
491do{if (isFresh)
492 {if (!(ioV = pgwCtl->FrameInfo(iovNum, iovLen))) break;
493 IO.IOLen -= iovLen;
494 if ((rc = getData(this, "pgwrite", ioV, iovNum))) return rc;
495 }
496
497// We now have all the data, get checksum and data information
498//
499 if (!(csVec = pgwCtl->FrameInfo(csNum, buff, Quantum, argp)))
500 return do_WriteNone(PathID, kXR_Impossible, "pgwrite logic error 2");
501
502// Convert checksums to host byte order
503//
504 for (int i = 0; i < csNum; i++) csVec[i] = ntohl(csVec[i]);
505
506// Verify the checksums
507//
508 XrdOucPgrwUtils::dataInfo dInfo(buff, csVec, IO.Offset, Quantum);
509 off_t bado;
510 int badc;
511 bool aOK = true;
512
513 while(dInfo.count > 0 && !XrdOucPgrwUtils::csVer(dInfo, bado, badc))
514 {if ((eMsg = pgwCtl->boAdd(IO.File, bado, badc)))
515 return do_WriteNone(PathID, kXR_TooManyErrs, eMsg);
516 aOK = false;
517 }
518
519// Write the data out. The callee is responsible for unaligned writes!
520//
521 if ((rc = sfsP->pgWrite(IO.Offset, buff, Quantum, csVec)) <= 0)
522 {IO.EInfo[0] = rc; IO.EInfo[1] = 0;
523 return do_WriteNone();
524 }
525
526// If this was a successful retry write, remove corrrected offset
527//
528 if (aOK && IO.Flags & XrdProto::kXR_pgRetry)
529 IO.File->pgwFob->delOffs(IO.Offset, Quantum);
530
531// Update offset and advance to next frame
532//
533 IO.Offset += Quantum;
534 isFresh = true;
535
536 } while(pgwCtl->Advance());
537
538
539// Return final result
540//
541 buff = pgwCtl->boInfo(n);
542 return Response.Send(pgwCtl->resp, sizeof(pgwCtl->info), buff, n);
543}
544
545/******************************************************************************/
546/* d o _ P g W I O R e t r y */
547/******************************************************************************/
548
549// IO.File = file to be written
550// IO.Offset = Offset at which to write
551// IO.IOLen = Number of bytes to read from socket
552// IO.Flags = Flags associated with request
553
554bool XrdXrootdProtocol::do_PgWIORetry(int &rc)
555{
556 static const int csLen = sizeof(kXR_unt32);
557 bool isBad;
558
559// Make sure the write does not cross a page bounday. For unaligned writes we
560// can compute the exact length that we need. Otherwise, it can't be bigger
561// than a unit's worth of data. Not precise but usually good enough.
562//
563 if (IO.Offset & pgPageMask)
564 {int n = pgPageSize - (IO.Offset & pgPageMask);
565 isBad = IO.IOLen > (n + csLen);
566 } else isBad = IO.IOLen > pgUnitSize;
567
568// Deep six the write if it violates retry rules.
569//
570 if (isBad)
571 {rc = do_WriteNone(PathID, kXR_ArgInvalid,
572 "pgwrite retry of more than one page not allowed");
573 return false;
574 }
575
576// Make sure that the offset is registered, if it is not, treat this as a
577// regular write as this may have been a resend during write recovery.
578//
579 if (!IO.File->pgwFob->hasOffs(IO.Offset, IO.IOLen - csLen))
580 {char buff[64];
581 snprintf(buff, sizeof(buff), "retry %d@%lld", IO.IOLen-csLen, IO.Offset);
582 eDest.Emsg("pgwRetry", buff, "not in error; fn=", IO.File->FileKey);
583 IO.Flags &= ~XrdProto::kXR_pgRetry;
584 }
585
586// We can proceed with this write now.
587//
588 return true;
589}
590
591/******************************************************************************/
592/* d o _ P g w I O S e t u p */
593/******************************************************************************/
594
595// IO.File = file to be written
596// IO.Offset = Offset at which to write
597// IO.IOLen = Number of bytes to read from socket
598// IO.Flags = Flags associated with request
599
600bool XrdXrootdProtocol::do_PgWIOSetup(XrdXrootdPgwCtl *pgwCtl)
601{
602 const char *eMsg;
603 int Quantum;
604
605// Compute the minimum (4K) or maximum buffer size we will use.
606//
608 Quantum = (IO.IOLen < pgPageSize ? pgPageSize : IO.IOLen);
609 else Quantum = XrdXrootdPgwCtl::maxBSize;
610
611// Make sure we have a large enough buffer
612//
613 if (!argp || Quantum < halfBSize || argp->bsize < Quantum
615 {if (getBuff(0, Quantum) <= 0) return -1;}
616 else if (hcNow < hcNext) hcNow++;
617
618// Do the setup. If it fails then either the client sent an incorrect stream
619// of the header was corrupted. In either case, it doesn't matter as we can't
620// depend on the information to clear the stream. So, we close the connection.
621//
622 if ((eMsg = pgwCtl->Setup(argp, IO.Offset, IO.IOLen)))
624 Link->setEtext("pgwrite protocol violation");
625 return false;
626 }
627 return true;
628}
@ 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
#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