/******************************************************************************/ /* */ /* X r d C l i e n t S i d . c c */ /* */ /* Author: Fabrizio Furano (INFN Padova, 2005) */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ ////////////////////////////////////////////////////////////////////////// // // // Utility classes to handle the mapping between xrootd streamids. // // A single streamid can have multiple "parallel" streamids. // // Their use is typically to support the client to submit multiple // // parallel requests (belonging to the same LogConnectionID), // // which are to be processed asynchronously when the answers arrive. // // // ////////////////////////////////////////////////////////////////////////// #include "XrdClient/XrdClientSid.hh" #include "XrdClient/XrdClientEnv.hh" #include "XrdClient/XrdClientConst.hh" XrdClientSid::XrdClientSid() { freesids.Resize(65536); // We populate the free sids queue for (kXR_unt16 i = 65535; i >= 1; i--) freesids.Push_back(i); } XrdClientSid::~XrdClientSid() { freesids.Clear(); childsidnfo.Purge(); } // Gets an available sid // From now on it will be no more available. // A retval of 0 means that there are no more available sids kXR_unt16 XrdClientSid::GetNewSid() { XrdSysMutexHelper l(fMutex); if (!freesids.GetSize()) return 0; return (freesids.Pop_back()); }; // Gets an available sid for a request which is to be outstanding // This means that this sid will be inserted into the Rash // The request gets inserted the new sid in the right place // Also the one passed as parameter gets the new sid, as should be expected kXR_unt16 XrdClientSid::GetNewSid(kXR_unt16 sid, ClientRequest *req) { XrdSysMutexHelper l(fMutex); if (!freesids.GetSize()) return 0; kXR_unt16 nsid = freesids.Pop_back(); if (nsid) { struct SidInfo si; memcpy(req->header.streamid, &nsid, sizeof(req->header.streamid)); si.fathersid = sid; si.outstandingreq = *req; si.reqbyteprogress = 0; si.sendtime = time(0); si.rspstatuscode = 0; si.rsperrno = kXR_noErrorYet; si.rsperrmsg = 0; childsidnfo.Add(nsid, si); } return nsid; }; // Report the response for an outstanding request // Typically this is used to keep track of the received errors, expecially // for async writes void XrdClientSid::ReportSidResp(kXR_unt16 sid, kXR_unt16 statuscode, kXR_unt32 errcode, char *errmsg) { XrdSysMutexHelper l(fMutex); struct SidInfo *si = childsidnfo.Find(sid); if (si) { si->rspstatuscode = statuscode; si->rsperrno = errcode; if (si->rsperrmsg) free(si->rsperrmsg); if (errmsg) si->rsperrmsg = strdup(errmsg); else si->rsperrmsg = 0; } }; // Releases a sid. // It is re-inserted into the available set // Its info is rmeoved from the tree void XrdClientSid::ReleaseSid(kXR_unt16 sid) { XrdSysMutexHelper l(fMutex); childsidnfo.Del(sid); freesids.Push_back(sid); }; //_____________________________________________________________________________ struct ReleaseSidTreeItem_data { kXR_unt16 fathersid; XrdClientVector *freesids; }; int ReleaseSidTreeItem(kXR_unt16 key, struct SidInfo si, void *arg) { ReleaseSidTreeItem_data *data = (ReleaseSidTreeItem_data *)arg; // If the sid we have is a son of the given father then delete it if (si.fathersid == data->fathersid) { free(si.rsperrmsg); data->freesids->Push_back(key); return -1; } return 0; } // Releases a sid and all its childs void XrdClientSid::ReleaseSidTree(kXR_unt16 fathersid) { XrdSysMutexHelper l(fMutex); ReleaseSidTreeItem_data data; data.fathersid = fathersid; data.freesids = &freesids; childsidnfo.Apply(ReleaseSidTreeItem, static_cast(&data)); freesids.Push_back(fathersid); } static int printoutreq(kXR_unt16, struct SidInfo p, void *) { smartPrintClientHeader(&p.outstandingreq); return 0; } void XrdClientSid::PrintoutOutstandingRequests() { cerr << "-------------------------------------------------- start outstanding reqs dump. freesids: " << freesids.GetSize() << endl; XrdSysMutexHelper l(fMutex); childsidnfo.Apply(printoutreq, this); cerr << "++++++++++++++++++++++++++++++++++++++++++++++++++++ end outstanding reqs dump." << endl; } struct sniffOutstandingFailedWriteReq_data { XrdClientVector *reqs; kXR_unt16 fathersid; XrdClientVector *freesids; }; static int sniffOutstandingFailedWriteReq(kXR_unt16 sid, struct SidInfo p, void *d) { sniffOutstandingFailedWriteReq_data *data = (sniffOutstandingFailedWriteReq_data *)d; if ((p.fathersid == data->fathersid) && (p.outstandingreq.header.requestid == kXR_write)) { // If it went into timeout or got a negative response // we add this req to the vector if ( (time(0) - p.sendtime > EnvGetLong(NAME_REQUESTTIMEOUT)) || (p.rspstatuscode != kXR_ok) || (p.rsperrno != kXR_noErrorYet) ) { data->reqs->Push_back(p.outstandingreq); // And we release the failed sid free(p.rsperrmsg); data->freesids->Push_back(sid); return -1; } } // smartPrintClientHeader(&p.outstandingreq); return 0; } static int sniffOutstandingAllWriteReq(kXR_unt16 sid, struct SidInfo p, void *d) { sniffOutstandingFailedWriteReq_data *data = (sniffOutstandingFailedWriteReq_data *)d; if ((p.fathersid == data->fathersid) && (p.outstandingreq.header.requestid == kXR_write)) { // we add this req to the vector data->reqs->Push_back(p.outstandingreq); // And we release the failed sid free(p.rsperrmsg); data->freesids->Push_back(sid); return -1; } // smartPrintClientHeader(&p.outstandingreq); return 0; } struct countOutstandingWriteReq_data { int cnt; kXR_unt16 fathersid; }; static int countOutstandingWriteReq(kXR_unt16 sid, struct SidInfo p, void *c) { countOutstandingWriteReq_data *data = (countOutstandingWriteReq_data *)c; if ((p.fathersid == data->fathersid) && (p.outstandingreq.header.requestid == kXR_write)) data->cnt++; // smartPrintClientHeader(&p.outstandingreq); return 0; } int XrdClientSid::GetFailedOutstandingWriteRequests(kXR_unt16 fathersid, XrdClientVector &reqvect) { XrdSysMutexHelper l(fMutex); sniffOutstandingFailedWriteReq_data data; data.reqs = &reqvect; data.fathersid = fathersid; data.freesids = &freesids; childsidnfo.Apply(sniffOutstandingFailedWriteReq, (void *)&data); return reqvect.GetSize(); } int XrdClientSid::GetOutstandingWriteRequestCnt(kXR_unt16 fathersid) { XrdSysMutexHelper l(fMutex); countOutstandingWriteReq_data data; data.fathersid = fathersid; data.cnt = 0; childsidnfo.Apply(countOutstandingWriteReq, (void *)&data); return data.cnt; } int XrdClientSid::GetAllOutstandingWriteRequests(kXR_unt16 fathersid, XrdClientVector &reqvect) { XrdSysMutexHelper l(fMutex); sniffOutstandingFailedWriteReq_data data; data.reqs = &reqvect; data.fathersid = fathersid; data.freesids = &freesids; childsidnfo.Apply(sniffOutstandingAllWriteReq, (void *)&data); return reqvect.GetSize(); }