XRootD
Loading...
Searching...
No Matches
XrdSsiTaskReal.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d S s i T a s k R e a l . c c */
4/* */
5/* (c) 2013 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 <cstdio>
31#include <string>
32
37#include "XrdSsi/XrdSsiScale.hh"
40#include "XrdSsi/XrdSsiTrace.hh"
41#include "XrdSsi/XrdSsiUtils.hh"
42
43#include "XrdSys/XrdSysError.hh"
45#include "Xrd/XrdScheduler.hh"
46
47using namespace XrdSsi;
48
49/******************************************************************************/
50/* L o c a l M a c r o s */
51/******************************************************************************/
52
53#define DUMPIT(x,y) XrdSsiUtils::b2x(x,y,hexBuff,sizeof(hexBuff),dotBuff)<<dotBuff
54
55/******************************************************************************/
56/* L o c a l S t a t i c s */
57/******************************************************************************/
58
59namespace
60{
61const char *statName[] = {"isPend", "isWrite", "isSync",
62 "isReady", "isDone", "isDead"};
63
64XrdSsiSessReal voidSession(0, "voidSession", 0);
65
66std::string pName("ReadRecovery");
67std::string pValue("false");
68char zedData = 0;
69}
70
71/******************************************************************************/
72/* G l o b a l s */
73/******************************************************************************/
74
75namespace XrdSsi
76{
77extern XrdSysError Log;
78extern XrdScheduler *schedP;
79extern XrdSsiScale sidScale;
80}
81
82/******************************************************************************/
83/* L o c a l C l a s s e s */
84/******************************************************************************/
85
86namespace
87{
88class AlertMsg : public XrdSsiRespInfoMsg
89{
90public:
91
92void RecycleMsg(bool sent=true) {delete respObj; delete this;}
93
94 AlertMsg(XrdCl::AnyObject *resp, char *dbuff, int dlen)
95 : XrdSsiRespInfoMsg(dbuff, dlen), respObj(resp) {}
96
97 ~AlertMsg() {}
98
99private:
100XrdCl::AnyObject *respObj;
101};
102
103/******************************************************************************/
104
105class SchedEmsg : public XrdJob
106{
107public:
108
109void DoIt() {taskP->SendError();
110 delete this;
111 }
112
113 SchedEmsg(XrdSsiTaskReal *tP) : taskP(tP) {}
114 ~SchedEmsg() {}
115
116private:
117XrdSsiTaskReal *taskP;
118};
119}
120
121/******************************************************************************/
122/* Private: A s k 4 R e s p */
123/******************************************************************************/
124
125// Called with session mutex locked and returns with it unlocked!
126
127bool XrdSsiTaskReal::Ask4Resp()
128{
129 EPNAME("Ask4Resp");
130
131 XrdCl::XRootDStatus epStatus;
132 XrdSsiRRInfo rInfo;
133 XrdCl::Buffer qBuff(sizeof(unsigned long long));
134
135// Disable read recovery
136//
137 sessP->epFile.SetProperty(pName, pValue);
138
139// Compose request to wait for the response
140//
141 rInfo.Id(tskID); rInfo.Cmd(XrdSsiRRInfo::Rwt);
142 memcpy(qBuff.GetBuffer(), rInfo.Data(), sizeof(long long));
143
144// Do some debugging
145//
146 DEBUG("Calling fcntl for response.");
147
148// Issue the command to field the response
149//
150 epStatus = sessP->epFile.Fcntl(qBuff, (ResponseHandler *)this, tmOut);
151
152// Dianose any errors. If any occurred we simply return an error response but
153// otherwise let this go as it really is not a logic error.
154//
155 if (!epStatus.IsOK()) return RespErr(&epStatus);
156 mhPend = true;
157 tStat = isSync;
158 sessP->UnLock();
159 return true;
160}
161
162/******************************************************************************/
163/* D e t a c h */
164/******************************************************************************/
165
167{ tStat = isDead;
168 if (force) sessP = &voidSession;
169}
170
171/******************************************************************************/
172/* F i n i s h e d */
173/******************************************************************************/
174
175// Note that if we are called then Finished() must have been called while we
176// were still in the open phase.
177
179 const XrdSsiRespInfo &rInfo, bool cancel)
180{
181 EPNAME("TaskFinished");
182 XrdSsiMutexMon rHelp(sessP->MutexP());
183
184// Do some debugging
185//
186 DEBUG("Request="<<&rqstR<<" cancel="<<cancel);
187
188// We should do an unbind here but that is overkill. All we need to do is
189// clear the pointer to the request object.
190//
192
193// If we can kill this task right now, clean up. Otherwise, the message
194// handler will clean things up.
195//
196 if (Kill()) sessP->TaskFinished(this);
197 else {DEBUG("Task removal deferred.");}
198}
199
200/******************************************************************************/
201/* Private: G e t R e s p */
202/******************************************************************************/
203
204XrdSsiTaskReal::respType XrdSsiTaskReal::GetResp(XrdCl::AnyObject **respP,
205 char *&dbuff, int &dbL)
206{
207 EPNAME("GetResp");
208 XrdCl::AnyObject *response = *respP;
209 XrdCl::Buffer *buffP;
210 XrdSsiRRInfoAttn *mdP;
211 char *cdP;
212 unsigned int mdL, pxL, n;
213 respType xResp;
214
215// Make sure that the [meta]data is actually present
216//
217 response->Get(buffP);
218 if (!buffP || !(cdP = buffP->GetBuffer()))
219 {DEBUG("Responding with stream.");
220 return isStream;
221 }
222
223// Validate the header
224//
225 if ((n=buffP->GetSize()) < sizeof(XrdSsiRRInfoAttn)) return isBad;
226 mdP = (XrdSsiRRInfoAttn *)cdP;
227 mdL = ntohl(mdP->mdLen);
228 pxL = ntohs(mdP->pfxLen);
229 dbL = n - mdL - pxL;
230 if (pxL < sizeof(XrdSsiRRInfoAttn) || dbL < 0) return isBad;
231
232// This may be an alert message, check for that now
233//
235 {char hexBuff[16],dotBuff[4];
236 dbuff = cdP+pxL; dbL = mdL;
237 DEBUG("Posting "<<dbL<<" byte alert (0x"<<DUMPIT(dbuff,dbL)<<")");
238 return isAlert;
239 }
240
241// Extract out the metadata
242//
243 if (mdL)
244 {char hexBuff[16],dotBuff[4];
245 DEBUG(mdL <<" byte metadata set (0x" <<DUMPIT(cdP+pxL,mdL)<<")");
246 SetMetadata(cdP+pxL, mdL);
247 }
248
249// Extract out the data
250//
252 {dbuff = (dbL ? cdP+mdL+pxL : &zedData);
253 xResp = isData;
254 DEBUG("Responding with " <<dbL <<" data bytes.");
255 }
256 else {xResp = isStream;
257 DEBUG("Responding with stream.");
258 }
259
260// Save the response buffer if we will be referecing it later
261//
262 if (mdL || dbL)
263 {mdResp = response;
264 *respP = 0;
265 }
266
267// All done
268//
269 return xResp;
270}
271
272/******************************************************************************/
273/* K i l l */
274/******************************************************************************/
275
276bool XrdSsiTaskReal::Kill() // Called with session mutex locked!
277{
278 EPNAME("TaskKill");
279 XrdSsiRRInfo rInfo;
280
281// Do some debugging
282//
283 DEBUG("Status="<<statName[tStat]<<" defer=" <<defer<<" mhPend="<<mhPend);
284
285// Affect proper procedure
286//
287 switch(tStat)
288 {case isWrite: break;
289 case isSync: break;
290 case isReady: break;
291 case isDone: tStat = isDead;
292 return !(mhPend || defer);
293 break;
294 case isDead: return !(mhPend || defer);
295 break;
296 case isPend: tStat = isDead;
297 return !(mhPend || defer);
298 break;
299 default: char mBuff[32];
300 snprintf(mBuff, sizeof(mBuff), "%d", tStat);
301 Log.Emsg("TaskKill", "Invalid state", mBuff);
302 tStat = isDead;
303 return false;
304 break;
305 }
306
307// The tricky thing here is that a kill came when we are actully in the process
308// of writing the request. If so, we need to hold until that finished to keep
309// valgring happy (i.e. nt writing from unallocated memory). So, we will have to
310// wait until he write catually occurs before continuing (yech -- thread hung).
311//
312 if (tStat == isWrite && mhPend)
313 {XrdSysSemaphore wSem(0);
314 wPost = &wSem;
315 DEBUG("Waiting for write event.");
316 sessP->UnLock();
317 wSem.Wait();
318 sessP->Lock();
319 }
320
321// If we are here then the request is potentially still active at the server.
322// We will send a synchronous cancel request. It shouldn't take long. Note
323// that, for now, we ignore any errors as we don't have a recovery plan.
324//
325 rInfo.Id(tskID); rInfo.Cmd(XrdSsiRRInfo::Can);
326 DEBUG("Sending cancel request.");
327 XrdCl::XRootDStatus Status = sessP->epFile.Truncate(rInfo.Info(), tmOut);
328
329
330// If we are in the message handler or if we have a message pending, then
331// the message handler will dispose of the task.
332//
333 tStat = isDead;
334 DEBUG("Returning " <<!(mhPend || defer));
335 return !(mhPend || defer);
336}
337
338/******************************************************************************/
339/* Private: R e s p E r r */
340/******************************************************************************/
341
342// Called with session mutex locked and returns with it unlocked!
343
344bool XrdSsiTaskReal::RespErr(XrdCl::XRootDStatus *status)
345{
346 EPNAME("RespErr");
347 std::string eTxt;
348 int eNum = XrdSsiUtils::GetErr(*status, eTxt);
349
350// Indicate we are done and unlock the session. The caller should have deferred
351// the processing of Finished() if this object will continue to be referenced.
352//
353 tStat = isDone;
354 if (sessP)
355 {sessP->UnHold(false);
356 sessP->UnLock();
357 }
358
359// Reflect an error to the request object.
360//
361 DEBUG("Posting error " <<eNum <<": " <<eTxt.c_str());
362 SetErrResponse(eTxt.c_str(), eNum);
363 return false;
364}
365
366/******************************************************************************/
367/* S c h e d E r r o r */
368/******************************************************************************/
369
370// Called with sessMutex locked!
371
373{
374// Copy the error information if so supplied.
375//
376 if (eInfo) errInfo = *eInfo;
377
378// Schedule the error to avoid lock clashes. Make sure Finished calls deferred.
379// The target (SendError) will decrease the defer refcount (ugly but true).
380//
381 defer++;
382 XrdSsi::schedP->Schedule((XrdJob *)(new SchedEmsg(this)));
383}
384
385/******************************************************************************/
386/* S e n d E r r o r */
387/******************************************************************************/
388
389void XrdSsiTaskReal::SendError() // Called with defer > 0!
390{
391 EPNAME("SendError");
392
393// Lock the associated session
394//
395 sessP->Lock();
396 DEBUG("Status="<<statName[tStat]<<" defer=" <<defer<<" mhPend="<<mhPend);
397
398// If there was no call to finished then we need to send an error response
399// which may precipitate a finished call now or later. Defer should be set
400// with anticipation that we will decrease it after the callback.
401//
402 if (tStat != isDead)
403 {int eNum;
404 const char *eTxt = errInfo.Get(eNum).c_str();
405 sessP->UnLock();
406 SetErrResponse(eTxt, eNum);
407 sessP->Lock();
408 defer--;
409 if (tStat != isDead)
410 {sessP->UnLock();
411 return;
412 }
413 }
414
415// If it is safe to do so, finish up everything here
416//
417
418 if (mhPend || defer)
419 {DEBUG("Defering TaskFinished."<<" defer=" <<defer<<" mhPend="<<mhPend);
420 sessP->UnLock();
421 } else {
422 DEBUG("Calling TaskFinished");
423 sessP->UnLock();
424 sessP->TaskFinished(this);
425 }
426}
427
428/******************************************************************************/
429/* S e n d R e q u e s t */
430/******************************************************************************/
431
432// Called with sessMutex locked!
433
434bool XrdSsiTaskReal::SendRequest(const char *node)
435{
437 XrdSsiRRInfo rrInfo;
438 char *reqBuff;
439 int reqBlen;
440
441// We must be in pend state to send a request. If we are not then the request
442// must have been cancelled. It also means we have a logic error if the
443// state is not isDead as we can't finish off the task and leak memory.
444//
445 if (tStat != isPend)
446 {if (tStat == isDead) sessP->TaskFinished(this);
447 else Log.Emsg("SendRequest", "Invalid state", statName[tStat],
448 "; should be isPend!");
449 return false;
450 }
451
452// Establish the endpoint
453//
455
456// Get the request information. Make sure to defer Finish() calls.
457//
458 defer++;
459 reqBuff = XrdSsiRRAgent::Request(this)->GetRequest(reqBlen);
460 defer--;
461
462// It's possible that GetRequest() called finished so process that here.
463//
464 if (tStat == isDead)
465 {sessP->TaskFinished(this);
466 return false;
467 }
468
469
470// Construct the info for this request
471//
472 rrInfo.Id(tskID);
473 rrInfo.Size(reqBlen);
474 tStat = isWrite;
475
476// If we are writing a zero length message, we must fake a request as zero
477// zero length messages are normally deep-sixed.
478//
479 if (!reqBlen)
480 {reqBuff = &zedData;
481 reqBlen = 1;
482 }
483
484// Issue the write
485//
486 Status = sessP->epFile.Write(rrInfo.Info(), (uint32_t)reqBlen, reqBuff,
487 (XrdCl::ResponseHandler *)this, tmOut);
488
489// Determine ending status. If it's bad, schedule an error. Note that calls to
490// Finished() will be deferred until the error thread gets control.
491//
492 if (!Status.IsOK())
493 {XrdSsiUtils::SetErr(Status, errInfo);
494 SchedError();
495 return false;
496 }
497
498// Indicate a message handler call outstanding
499//
500 mhPend = true;
501 return true;
502}
503
504/******************************************************************************/
505/* S e t B u f f */
506/******************************************************************************/
507
509 char *buff, int blen, bool &last)
510{
511 EPNAME("TaskSetBuff");
512 XrdSsiMutexMon rHelp(sessP->MutexP());
513 XrdCl::XRootDStatus epStatus;
514 XrdSsiRRInfo rrInfo;
515 union {uint32_t ubRead; int ibRead;};
516
517// Check if this is a proper call or we have reached EOF
518//
519 DEBUG("ReadSync status=" <<statName[tStat]);
520 if (tStat != isReady)
521 {if (tStat == isDone) return 0;
522 eRef.Set("Stream is not active", ENODEV);
523 return -1;
524 }
525
526// Prepare to issue the read
527//
528 rrInfo.Id(tskID);
529
530// Issue a read
531//
532 epStatus = sessP->epFile.Read(rrInfo.Info(),(uint32_t)blen,buff,ubRead,tmOut);
533 if (epStatus.IsOK())
534 {if (ibRead < blen) {tStat = isDone; last = true;}
535 DEBUG("ReadSync returning " <<ibRead <<" bytes.");
536 return ibRead;
537 }
538
539// We failed, return an error
540//
541 XrdSsiUtils::SetErr(epStatus, eRef);
542 tStat = isDone;
543 DEBUG("ReadSync error; " <<epStatus.ToStr());
544 return -1;
545}
546
547/******************************************************************************/
548
549bool XrdSsiTaskReal::SetBuff(XrdSsiErrInfo &eRef, char *buff, int blen)
550{
551 EPNAME("TaskSetBuff");
552 XrdSsiMutexMon rHelp(sessP->MutexP());
553 XrdCl::XRootDStatus epStatus;
554 XrdSsiRRInfo rrInfo;
555
556// Check if this is a proper call or we have reached EOF
557//
558 DEBUG("ReadAsync Status=" <<statName[tStat]);
559 if (tStat != isReady)
560 {eRef.Set("Stream is not active", ENODEV);
561 return false;
562 }
563
564// We only support (for now) one read at a time
565//
566 if (mhPend)
567 {eRef.Set("Stream is already active", EINPROGRESS);
568 return false;
569 }
570
571// Make sure the buffer length is valid
572//
573 if (blen <= 0)
574 {eRef.Set("Buffer length invalid", EINVAL);
575 return false;
576 }
577
578// Prepare to issue the read
579//
580 rrInfo.Id(tskID);
581
582// Issue a read
583//
584 dataBuff = buff; dataRlen = blen;
585 epStatus = sessP->epFile.Read(rrInfo.Info(), (uint32_t)blen, buff,
586 (XrdCl::ResponseHandler *)this, tmOut);
587
588// If success then indicate we are pending and return
589//
590 if (epStatus.IsOK()) {mhPend = true; return true;}
591
592// We failed, return an error
593//
594 XrdSsiUtils::SetErr(epStatus, eRef);
595 tStat = isDone;
596 DEBUG("ReadAsync error; " <<epStatus.ToStr());
597 return false;
598}
599
600/******************************************************************************/
601/* X e q E v e n t */
602/******************************************************************************/
603
605 XrdCl::AnyObject **respP)
606{
607 EPNAME("TaskXeqEvent");
608
609 XrdCl::AnyObject *response = *respP;
610 XrdSsiRespInfoMsg *aMsg;
611 char *dBuff;
612 union {uint32_t ubRead; int ibRead;};
613 int dLen;
614 TaskStat Tstat;
615 bool last, aOK = status->IsOK();
616
617// Obtain a lock and indicate the any Finish() calls should be deferred until
618// we return from this method. The reason is that any callback that we do here
619// may precipitate a Finish() call not to mention some other thread doing so.
620//
621 XrdSsiMutexMon monMtx(sessP->MutexP());
622 defer++;
623 mhPend = false;
624
625// Do some debugging
626//
627 DEBUG("aOK="<<aOK<<" status="<<statName[tStat]<<" defer=" <<defer);
628
629// Affect proper response
630//
631 switch(tStat)
632 {case isWrite:
633 if (!aOK)
634 {RespErr(status); // Unlocks the mutex!
635 monMtx.Reset();
636 return 1;
637 }
638 DEBUG("Write completed.");
639 if (wPost)
640 {DEBUG("Posting killer.");
641 wPost->Post(); wPost = 0;
642 return 1;
643 }
644 DEBUG("Calling RelBuff.");
646 if (tStat == isWrite)
647 {monMtx.Reset();
648 return (Ask4Resp() ? 0 : 1); // Unlocks the mutex!
649 }
650 return 1;
651
652 case isSync:
653 monMtx.Reset();
654 if (!aOK) return (RespErr(status) ? 0 : 1); // Unlocks the mutex!
655
656 if (response) switch(GetResp(respP, dBuff, dLen))
657 {case isAlert: aMsg = new AlertMsg(*respP, dBuff, dLen);
658 *respP = 0;
659 sessP->UnLock();
660 XrdSsiRRAgent::Alert(*rqstP, *aMsg);
661 sessP->Lock();
662 if (tStat == isSync)
663 return (Ask4Resp() ? 0 : 1);
664 Tstat = tStat;
665 sessP->UnLock();
666 return (Tstat != isDead ? 0 : 1);
667 break;
668 case isData: tStat = isDone; sessP->UnLock();
669 SetResponse(dBuff, dLen);
670 break;
671 case isStream: tStat = isReady; sessP->UnLock();
672 SetResponse((XrdSsiStream *)this);
673 break;
674 default: tStat = isDone; sessP->UnLock();
675 SetErrResponse("Invalid response", EFAULT);
676 break;
677 } else {
678 tStat = isDone; sessP->UnLock();
679 SetErrResponse("Missing response", EFAULT);
680 }
681 return 0;
682
683 case isReady:
684 break;
685
686 case isDead:
687 return 1;
688
689 default: char mBuff[32];
690 snprintf(mBuff, sizeof(mBuff), "%d", tStat);
691 Log.Emsg("TaskXeqEvent", "Invalid state", mBuff);
692 return 1;
693 }
694
695// Handle incoming response data. The session mutex is still locked!
696//
697 if (!aOK || !response)
698 {ibRead = -1;
699 if (!aOK) XrdSsiUtils::SetErr(*status, XrdSsiRRAgent::ErrInfoRef(rqstP));
700 else XrdSsiRRAgent::ErrInfoRef(rqstP).Set("Missing response", EFAULT);
701 } else {
702 XrdCl::ChunkInfo *cInfo = 0;
703 response->Get(cInfo);
704 ubRead = (cInfo ? cInfo->length : 0);
705 }
706
707// Reflect the response to the request as this was an async receive. We may not
708// reference this object after the UnLock() as Finished() might be called.
709//
710 if (ibRead < dataRlen) {tStat = isDone; dataRlen = ibRead;}
711 dBuff = dataBuff;
712 last = tStat == isDone;
713 sessP->UnLock();
714 DEBUG("Calling ProcessResponseData; len="<<ibRead<<" last="<<last);
715 rqstP->ProcessResponseData(XrdSsiRRAgent::ErrInfoRef(rqstP),
716 dBuff, ibRead, last);
717
718// All done
719//
720 return 0;
721}
722
723/******************************************************************************/
724/* X e q E v F i n */
725/******************************************************************************/
726
728{
729 EPNAME("TaskXeqEvFin");
730
731// Obtain a lock and remove defer flag (protected by the lock)
732//
733 sessP->Lock();
734 defer--;
735 DEBUG("Status="<<statName[tStat]<<" defer=" <<defer<<" mhPend="<<mhPend);
736
737
738// Check if finished has been called while we were deferred or if this is an
739// orphaned task due to a session stop request.
740//
741 if (tStat == isDead)
742 {if (sessP != &voidSession)
743 {if (mhPend || defer) {DEBUG("Defering TaskFinished.");}
744 else {DEBUG("Calling TaskFinished");
745 sessP->UnLock();
746 sessP->TaskFinished(this);
747 }
748 } else {
749 DEBUG("Deleting orphaned task.");
750 sessP->UnLock();
751 delete this;
752 }
753 } else sessP->UnLock();
754}
int DoIt(int argpnt, int argc, char **argv, bool singleshot)
#define DEBUG(x)
#define EPNAME(x)
#define DUMPIT(x, y)
void Get(Type &object)
Retrieve the object being held.
Binary blob representation.
const char * GetBuffer(uint32_t offset=0) const
Get the message buffer.
uint32_t GetSize() const
Get the size of the message.
Handle an async response.
std::string ToStr() const
Convert to string.
XrdJob(const char *desc="")
Definition XrdJob.hh:51
void Set(const char *eMsg=0, int eNum=0, int eArg=0)
static XrdSsiRequest * Request(XrdSsiResponder *rP)
static void Alert(XrdSsiRequest &reqR, XrdSsiRespInfoMsg &aMsg)
static XrdSsiErrInfo & ErrInfoRef(XrdSsiRequest *rP)
static void ResetResponder(XrdSsiResponder *rP)
static void SetNode(XrdSsiRequest *rP, const char *name)
void Size(unsigned int sz)
unsigned long long Info()
const unsigned char * Data()
void Cmd(Opc cmd)
void Id(unsigned int id)
virtual char * GetRequest(int &dlen)=0
Status SetResponse(const char *buff, int blen)
Status SetErrResponse(const char *eMsg, int eNum)
Status SetMetadata(const char *buff, int blen)
friend class XrdSsiRequest
void UnHold(bool cleanup=true)
XrdSsiStream(StreamType stype)
void Finished(XrdSsiRequest &rqstR, const XrdSsiRespInfo &rInfo, bool cancel=false)
int SetBuff(XrdSsiErrInfo &eRef, char *buff, int blen, bool &last)
int XeqEvent(XrdCl::XRootDStatus *status, XrdCl::AnyObject **respP)
void SchedError(XrdSsiErrInfo *eInfo=0)
bool SendRequest(const char *node)
void Detach(bool force=false)
static int GetErr(XrdCl::XRootDStatus &Status, std::string &eText)
static void SetErr(XrdCl::XRootDStatus &Status, XrdSsiErrInfo &eInfo)
XrdScheduler * schedP
XrdSsiScale sidScale
XrdSysError Log
Describe a data chunk for vector read.
uint32_t length
offset in the file
bool IsOK() const
We're fine.
static const int fullResp
unsigned short pfxLen
unsigned int mdLen
static const int alrtResp