int MemCacheClient::Combine( const char * aType, MemRequest * aItem, int aCount ) { if (aCount < 1) { mTrace.Trace(CLDEBUG, "%s: ignoring request for %d items", aType, aCount); return 0; } CR_ASSERT(*aType == 'g' || *aType == 'd'); // get, gets, del MemRequest * rgpItem[MAX_REQUESTS] = { NULL }; if (aCount > MAX_REQUESTS) { mTrace.Trace(CLDEBUG, "%s: ignoring request for all %d items (too many)", aType, aCount); return -1; // invalid args } // initialize and find all of the servers for these items int nItemCount = 0; for (int n = 0; n < aCount; ++n) { // ensure that the key doesn't have a space in it CR_ASSERT(NULL == strchr(aItem[n].mKey.data(), ' ')); aItem[n].mServer = FindServer(aItem[n].mKey, aItem[n].mService); aItem[n].mData.SetEmpty(); if (aItem[n].mServer) { rgpItem[nItemCount++] = &aItem[n]; } else { aItem[n].mResult = MCERR_NOSERVER; } } if (nItemCount == 0) { mTrace.Trace(CLDEBUG, "%s: ignoring request for all %d items (no servers available)", aType, aCount); return 0; } // sort all requests into server order const static MemRequest::Sort sortOnServer = MemRequest::Sort(); std::sort(&rgpItem[0], &rgpItem[nItemCount], sortOnServer); // send all requests char szBuf[50]; int nItem = 0, nNext; string_t sRequest, sTemp; while (nItem < nItemCount) { for (nNext = nItem; nNext < nItemCount; ++nNext) { if (rgpItem[nItem]->mServer != rgpItem[nNext]->mServer) break; CR_ASSERT(*aType == 'g' || *aType == 'd'); rgpItem[nNext]->mData.SetEmpty(); // create get request for all keys on this server if (*aType == 'g') { if (nNext == nItem) sRequest = "get"; else sRequest.resize(sRequest.length() - 2); sRequest += ' '; sRequest += rgpItem[nNext]->mKey; sRequest += "\r\n"; rgpItem[nNext]->mResult = MCERR_NOTFOUND; } // create del request for all keys on this server else if (*aType == 'd') { // delete <key> [<time>] [noreply]\r\n sRequest += "delete "; sRequest += rgpItem[nNext]->mKey; sRequest += ' '; snprintf(szBuf, sizeof(szBuf), "%ld", (long) rgpItem[nNext]->mExpiry); sRequest += szBuf; if (rgpItem[nNext]->mResult == MCERR_NOREPLY) { sRequest += " noreply"; } sRequest += "\r\n"; if (rgpItem[nNext]->mResult != MCERR_NOREPLY) { rgpItem[nNext]->mResult = MCERR_NOTFOUND; } } } // send the request. any socket error causes the server connection // to be dropped, so we return errors for all requests using that server. try { rgpItem[nItem]->mServer->SendBytes( sRequest.data(), sRequest.length()); } catch (const Socket::Exception & e) { mTrace.Trace(CLINFO, "%s: request error '%s' at %s, marking requests as NOSERVER", aType, e.mDetail, rgpItem[nItem]->mServer->GetAddress()); for (int n = nItem; n < nNext; ++n) { rgpItem[n]->mServer = NULL; rgpItem[n]->mResult = MCERR_NOSERVER; } } nItem = nNext; } // receive responses from all servers int nResponses = 0; for (nItem = 0; nItem < nItemCount; nItem = nNext) { // find the end of this server if (!rgpItem[nItem]->mServer) { nNext = nItem + 1; continue; } for (nNext = nItem + 1; nNext < nItemCount; ++nNext) { if (rgpItem[nItem]->mServer != rgpItem[nNext]->mServer) break; } // receive the responses. any socket error causes the server connection // to be dropped, so we return errors for all requests using that server. try { if (*aType == 'g') { nResponses += HandleGetResponse( rgpItem[nItem]->mServer, &rgpItem[nItem], &rgpItem[nNext]); } else if (*aType == 'd') { nResponses += HandleDelResponse( rgpItem[nItem]->mServer, &rgpItem[nItem], &rgpItem[nNext]); } } catch (const Socket::Exception & e) { mTrace.Trace(CLINFO, "%s: response error '%s' at %s, marking requests as NOSERVER", aType, e.mDetail, rgpItem[nItem]->mServer->GetAddress()); rgpItem[nItem]->mServer->Disconnect(); for (int n = nNext - 1; n >= nItem; --n) { if (rgpItem[nItem]->mServer != rgpItem[n]->mServer) continue; rgpItem[n]->mServer = NULL; rgpItem[n]->mResult = MCERR_NOSERVER; } } } mTrace.Trace(CLDEBUG, "%s: received %d responses to %d requests", aType, nResponses, aCount); return nResponses; }
int MemCacheClient::Combine( const char * a_pszType, MemRequest * a_rgItem, int a_nCount ) { if (a_nCount < 1) return 0; MemRequest * rgpItem[MAX_REQUESTS] = { NULL }; if (a_nCount > MAX_REQUESTS) return -1; // invalid args // initialize and find all of the servers for these items int nItemCount = 0; for (int n = 0; n < a_nCount; ++n) { // ensure that the key doesn't have a space in it assert(NULL == strchr(a_rgItem[n].mKey.data(), ' ')); a_rgItem[n].mServer = FindServer(a_rgItem[n].mKey); if (a_rgItem[n].mServer) { rgpItem[nItemCount++] = &a_rgItem[n]; } else { a_rgItem[n].mResult = MCERR_NOSERVER; } } if (nItemCount == 0) return 0; // sort all requests into server order const static MemRequest::Sort sortOnServer = MemRequest::Sort(); std::sort(&rgpItem[0], &rgpItem[nItemCount], sortOnServer); // send all requests char szBuf[50]; int nItem = 0, nNext; string_t sRequest, sTemp; while (nItem < nItemCount) { for (nNext = nItem; nNext < nItemCount; ++nNext) { if (rgpItem[nItem]->mServer != rgpItem[nNext]->mServer) break; // create get request for all keys on this server if (*a_pszType == 'g') { if (nNext == nItem) sRequest = "get"; else sRequest.resize(sRequest.length() - 2); sRequest += ' '; sRequest += rgpItem[nNext]->mKey; sRequest += "\r\n"; rgpItem[nNext]->mResult = MCERR_NOTFOUND; } // create del request for all keys on this server else if (*a_pszType == 'd') { // delete <key> [<time>] [noreply]\r\n sRequest += "delete "; sRequest += rgpItem[nNext]->mKey; sRequest += ' '; snprintf(szBuf, sizeof(szBuf), "%ld", (long) rgpItem[nNext]->mExpiry); sRequest += szBuf; if (rgpItem[nNext]->mResult == MCERR_NOREPLY) { sRequest += " noreply"; } sRequest += "\r\n"; if (rgpItem[nNext]->mResult != MCERR_NOREPLY) { rgpItem[nNext]->mResult = MCERR_NOTFOUND; } } } // send the request. any socket error causes the server connection // to be dropped, so we return errors for all requests using that server. try { rgpItem[nItem]->mServer->SendBytes( sRequest.data(), sRequest.length()); } catch (const ServerSocket::Exception &) { for (int n = nItem; n < nNext; ++n) { rgpItem[n]->mServer = NULL; rgpItem[n]->mResult = MCERR_NOSERVER; } } nItem = nNext; } // receive responses from all servers int nResponses = 0; for (nItem = 0; nItem < nItemCount; nItem = nNext) { // find the end of this server if (!rgpItem[nItem]->mServer) { nNext = nItem + 1; continue; } for (nNext = nItem + 1; nNext < nItemCount; ++nNext) { if (rgpItem[nItem]->mServer != rgpItem[nNext]->mServer) break; } // receive the responses. any socket error causes the server connection // to be dropped, so we return errors for all requests using that server. try { if (*a_pszType == 'g') { nResponses += HandleGetResponse( rgpItem[nItem]->mServer, &rgpItem[nItem], &rgpItem[nNext]); } else if (*a_pszType == 'd') { nResponses += HandleDelResponse( rgpItem[nItem]->mServer, &rgpItem[nItem], &rgpItem[nNext]); } } catch (const ServerSocket::Exception &) { rgpItem[nItem]->mServer->Disconnect(); for (int n = nNext - 1; n >= nItem; --n) { if (rgpItem[nItem]->mServer != rgpItem[n]->mServer) continue; rgpItem[n]->mServer = NULL; rgpItem[n]->mResult = MCERR_NOSERVER; } } } return nResponses; }