447 lines
8.4 KiB
C++
447 lines
8.4 KiB
C++
/************************************************************************
|
|
*
|
|
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
|
|
* $Id: text_request.cc,v 1.0 08/31/2016 04:53:21 PM hangfeng.fj(hangfeng.fj(@alibaba-inc.com) $
|
|
*
|
|
************************************************************************/
|
|
|
|
/**
|
|
* @file text_request.cc
|
|
* @author hangfeng.fj(hangfeng.fj(@alibaba-inc.com)
|
|
* @date 08/31/2016 04:53:21 PM
|
|
* @version 1.0
|
|
* @brief
|
|
*
|
|
**/
|
|
|
|
#include "text_request.h"
|
|
#include <stdlib.h>
|
|
#include <algorithm>
|
|
#include "memcached_utils.h"
|
|
|
|
namespace alisql {
|
|
|
|
TextRequest::TextRequest() :
|
|
requestLen_(0),
|
|
valid_(false),
|
|
command_(TextCommand::UNKNOWN),
|
|
flags_(0),
|
|
exptime_(0),
|
|
noReply_(false),
|
|
casUnique_(0),
|
|
stats_(stats_t::GENERAL),
|
|
namespace_(0),
|
|
version_(0)
|
|
{
|
|
}
|
|
|
|
void TextRequest::init(const char *p, uint32_t len)
|
|
{
|
|
msgPos_= p;
|
|
msgLen_= len;
|
|
}
|
|
|
|
void TextRequest::parse()
|
|
{
|
|
const char *endOfLine= cFind(msgPos_, LF, msgLen_);
|
|
// incomplete message
|
|
if (endOfLine == NULL)
|
|
{
|
|
LOG_INFO("incomplete msg: %s length: %ld\n", msgPos_, msgLen_);
|
|
return;
|
|
}
|
|
|
|
requestLen_= endOfLine - msgPos_ + 1;
|
|
|
|
// invalid message
|
|
if (requestLen_ == 1 || *(--endOfLine) != CR)
|
|
{
|
|
LOG_INFO("invalid msg: %s length: %ld\n", msgPos_, msgLen_);
|
|
return;
|
|
}
|
|
|
|
const char *cmdStart= msgPos_;
|
|
while (*cmdStart == SP)
|
|
{
|
|
++cmdStart;
|
|
}
|
|
|
|
const char *cmdEnd= cFind(cmdStart, SP, endOfLine - cmdStart);
|
|
|
|
if (cmdEnd == NULL)
|
|
{
|
|
cmdEnd= endOfLine;
|
|
}
|
|
|
|
uint32_t cmdLen= cmdEnd - cmdStart;
|
|
|
|
switch (cmdLen)
|
|
{
|
|
case 3:
|
|
if (memcmp(cmdStart, "set", 3) == 0)
|
|
{
|
|
command_= TextCommand::SET;
|
|
parseStorage(cmdEnd, endOfLine, false, false);
|
|
return;
|
|
}
|
|
if (memcmp(cmdStart, "get", 3) == 0)
|
|
{
|
|
command_= TextCommand::GET;
|
|
parseGet(cmdEnd, endOfLine);
|
|
return;
|
|
}
|
|
if (memcmp(cmdStart, "cas", 3) == 0)
|
|
{
|
|
command_= TextCommand::CAS;
|
|
parseStorage(cmdEnd, endOfLine, true, false);
|
|
return;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (memcmp(cmdStart, "gets", 4) == 0)
|
|
{
|
|
command_= TextCommand::GETS;
|
|
parseGet(cmdEnd, endOfLine);
|
|
return;
|
|
}
|
|
break;
|
|
case 5:
|
|
if (memcmp(cmdStart, "stats", 5) == 0)
|
|
{
|
|
command_= TextCommand::STATS;
|
|
parseStats(cmdEnd, endOfLine);
|
|
return;
|
|
}
|
|
break;
|
|
case 6:
|
|
if (memcmp(cmdStart, "delete", 6) == 0)
|
|
{
|
|
command_= TextCommand::DELETE;
|
|
parseDelete(cmdEnd, endOfLine);
|
|
return;
|
|
}
|
|
break;
|
|
case 7:
|
|
if (memcmp(cmdStart, "version", 7) == 0 )
|
|
{
|
|
command_= TextCommand::VERSION;
|
|
valid_= true;
|
|
return;
|
|
}
|
|
break;
|
|
case 8:
|
|
if (memcmp(cmdStart, "tair_set", 8) == 0)
|
|
{
|
|
command_= TextCommand::TAIR_SET;
|
|
parseStorage(cmdEnd, endOfLine, false, true);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_INFO("Unknown cmd: %s\n", cmdStart);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Storage commands
|
|
// The client sends a command line which looks like this:
|
|
// <command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
|
|
// cas <key> <flags> <exptime> <bytes> <cas unique> [noreply]\r\n
|
|
void TextRequest::parseStorage(const char *beg, const char *end,
|
|
bool isCas, bool isTair)
|
|
{
|
|
// parse `key`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
const char *keyEnd= cFind(beg, SP, end - beg);
|
|
if (keyEnd == NULL)
|
|
{
|
|
LOG_INFO("No key found: %s\n", beg);
|
|
return;
|
|
}
|
|
key_= item(beg, keyEnd - beg);
|
|
beg= keyEnd;
|
|
|
|
// parse `flags`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
const char *flagsEnd= cFind(beg, SP, end - beg);
|
|
if (flagsEnd == NULL)
|
|
{
|
|
LOG_INFO("No flags found: %s\n", beg);
|
|
return;
|
|
}
|
|
bool result;
|
|
flags_= toUint<uint32_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse flags failed: %s\n", beg);
|
|
return;
|
|
}
|
|
beg= flagsEnd;
|
|
|
|
// parse `exptime`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
const char *exptimeEnd= cFind(beg, SP, end - beg);
|
|
if (exptimeEnd == NULL)
|
|
{
|
|
LOG_INFO("No exptime found: %s\n", beg);
|
|
return;
|
|
}
|
|
exptime_= toUint<std::uint64_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse exptime failed: %s\n", beg);
|
|
return;
|
|
}
|
|
beg= exptimeEnd;
|
|
|
|
// parse `bytes`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
uint32_t nbytes= toUint<std::uint32_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse bytes failed: %s\n", beg);
|
|
return;
|
|
}
|
|
const char* bytesEnd= cFind(beg, SP, end - beg);
|
|
beg= (bytesEnd == NULL) ? end : bytesEnd;
|
|
|
|
if (isCas)
|
|
{
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
casUnique_= toUint<std::uint64_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse cas unique failed: %s\n", beg);
|
|
return;
|
|
}
|
|
const char* casEnd= cFind(beg, SP, end - beg);
|
|
beg= (casEnd == NULL) ? end : casEnd;
|
|
}
|
|
|
|
if (isTair)
|
|
{
|
|
// parse `namespace`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
namespace_= toUint<std::uint64_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse namespace failed: %s\n", beg);
|
|
return;
|
|
}
|
|
const char* nameSpaceEnd= cFind(beg, SP, end - beg);
|
|
beg= (nameSpaceEnd == NULL) ? end : nameSpaceEnd;
|
|
|
|
// parse `version`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
version_= toUint<std::uint64_t>(beg, result);
|
|
if (!result)
|
|
{
|
|
LOG_INFO("Parse version failed: %s\n", beg);
|
|
return;
|
|
}
|
|
const char* versionEnd= cFind(beg, SP, end - beg);
|
|
beg= (versionEnd == NULL) ? end : versionEnd;
|
|
}
|
|
|
|
// parse `noreply`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg != end)
|
|
{
|
|
const char* noreplyEnd= cFind(beg, SP, end - beg);
|
|
uint32_t noreplyLen= (noreplyEnd != NULL) ? (noreplyEnd - beg) :
|
|
(end - beg);
|
|
if (noreplyLen != 7)
|
|
{
|
|
return;
|
|
}
|
|
if (memcmp(beg, "noreply", 7) != 0)
|
|
{
|
|
return;
|
|
}
|
|
noReply_= true;
|
|
beg= (noreplyEnd != NULL) ? noreplyEnd : end;
|
|
}
|
|
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg != end)
|
|
{
|
|
return;
|
|
}
|
|
|
|
beg += 2; //CRLF
|
|
requestLen_= (beg - msgPos_) + nbytes + 2;
|
|
if (msgLen_ < requestLen_)
|
|
{
|
|
requestLen_= 0;
|
|
return;
|
|
}
|
|
|
|
// check CRLF after data
|
|
if (*(beg + nbytes) != CR || *(beg + nbytes + 1) != LF)
|
|
{
|
|
return;
|
|
}
|
|
|
|
data_= item(beg, nbytes);
|
|
valid_= true;
|
|
}
|
|
|
|
void TextRequest::parseGet(const char *beg, const char *end)
|
|
{
|
|
// parse `key`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
const char *keyEnd= cFind(beg, SP, end - beg);
|
|
if (keyEnd == NULL)
|
|
{
|
|
keyEnd= end;
|
|
}
|
|
key_= item(beg, keyEnd - beg);
|
|
valid_= true;
|
|
}
|
|
|
|
void TextRequest::parseDelete(const char *beg, const char *end)
|
|
{
|
|
// parse `key`
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
if (beg == end)
|
|
{
|
|
return;
|
|
}
|
|
const char *keyEnd= cFind(beg, SP, end - beg);
|
|
if (keyEnd == NULL)
|
|
{
|
|
keyEnd= end;
|
|
}
|
|
key_= item(beg, keyEnd - beg);
|
|
beg= keyEnd;
|
|
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
|
|
// TODO, remove duplicated code
|
|
if (beg != end)
|
|
{
|
|
const char* noreplyEnd= cFind(beg, SP, end - beg);
|
|
uint32_t noreplyLen= (noreplyEnd != NULL) ? (noreplyEnd - beg) :
|
|
(end - beg);
|
|
if (noreplyLen != 7)
|
|
{
|
|
return;
|
|
}
|
|
if (memcmp(beg, "noreply", 7) != 0)
|
|
{
|
|
return;
|
|
}
|
|
noReply_= true;
|
|
beg= (noreplyEnd != NULL) ? noreplyEnd : end;
|
|
}
|
|
|
|
while (*beg == SP) ++beg;
|
|
if (beg != end) return;
|
|
valid_= true;
|
|
}
|
|
|
|
void TextRequest::parseStats(const char *beg, const char *end)
|
|
{
|
|
while (*beg == SP)
|
|
{
|
|
++beg;
|
|
}
|
|
|
|
if (beg == end)
|
|
{
|
|
valid_= true;
|
|
return;
|
|
}
|
|
|
|
const char *keyEnd= cFind(beg, SP, end - beg);
|
|
if (keyEnd == NULL)
|
|
{
|
|
keyEnd= end;
|
|
}
|
|
|
|
std::size_t valueLen= keyEnd - beg;
|
|
|
|
if (valueLen == 5 && std::memcmp(beg, "local", 5) == 0)
|
|
{
|
|
stats_= stats_t::LOCAL;
|
|
valid_= true;
|
|
return;
|
|
}
|
|
else if (valueLen == 7 && std::memcmp(beg, "cluster", 7) == 0)
|
|
{
|
|
stats_= stats_t::CLUSTER;
|
|
valid_= true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
} //namespace alisql
|