mirror of
https://github.com/joyieldInc/predixy.git
synced 2025-12-25 06:56:42 +08:00
382 lines
8.0 KiB
C++
382 lines
8.0 KiB
C++
/*
|
|
* predixy - A high performance and full features proxy for redis.
|
|
* Copyright (C) 2017 Joyield, Inc. <joyield.com@gmail.com>
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "String.h"
|
|
#include "Logger.h"
|
|
#include "Buffer.h"
|
|
#include "IOVec.h"
|
|
|
|
int Buffer::Size = 4096 - sizeof(Buffer);
|
|
|
|
Buffer::Buffer():
|
|
mLen(0)
|
|
{
|
|
}
|
|
|
|
Buffer::Buffer(const Buffer& oth):
|
|
mLen(oth.mLen)
|
|
{
|
|
memcpy(mDat, oth.mDat, mLen);
|
|
}
|
|
|
|
Buffer::~Buffer()
|
|
{
|
|
SharePtr<Buffer> p = ListNode<Buffer, SharePtr<Buffer>>::next();
|
|
ListNode<Buffer, SharePtr<Buffer>>::reset();
|
|
while (p) {
|
|
if (p->count() == 1) {
|
|
p = p->next();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Buffer& Buffer::operator=(const Buffer& oth)
|
|
{
|
|
if (this != &oth) {
|
|
mLen = oth.mLen;
|
|
memcpy(mDat, oth.mDat, mLen);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Buffer* Buffer::append(const char* str)
|
|
{
|
|
return append(str, strlen(str));
|
|
}
|
|
|
|
Buffer* Buffer::append(const char* dat, int len)
|
|
{
|
|
if (len <= 0) {
|
|
return this;
|
|
}
|
|
Buffer* buf = this;
|
|
while (len > 0) {
|
|
if (len <= buf->room()) {
|
|
memcpy(buf->tail(), dat, len);
|
|
buf->use(len);
|
|
break;
|
|
} else {
|
|
int n = buf->room();
|
|
memcpy(buf->tail(), dat, n);
|
|
buf->use(n);
|
|
dat += n;
|
|
len -= n;
|
|
Buffer* nbuf = BufferAlloc::create();
|
|
buf->concat(nbuf);
|
|
buf = nbuf;
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
Buffer* Buffer::fappend(const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
char* dat = tail();
|
|
int len = room();
|
|
int n = vsnprintf(dat, len, fmt, ap);
|
|
va_end(ap);
|
|
if (n >= len) {
|
|
if (n > MaxBufFmtAppendLen) {
|
|
return nullptr;
|
|
}
|
|
char buf[MaxBufFmtAppendLen];
|
|
va_list aq;
|
|
va_start(aq, fmt);
|
|
n = vsnprintf(buf, sizeof(buf), fmt, aq);
|
|
va_end(aq);
|
|
return append(buf, n);
|
|
}
|
|
use(n);
|
|
return this;
|
|
}
|
|
|
|
Buffer* Buffer::vfappend(const char* fmt, va_list ap)
|
|
{
|
|
char* dat = tail();
|
|
int len = room();
|
|
va_list aq;
|
|
va_copy(aq, ap);
|
|
int n = vsnprintf(dat, len, fmt, ap);
|
|
if (n >= len) {
|
|
if (n > MaxBufFmtAppendLen) {
|
|
va_end(aq);
|
|
return nullptr;
|
|
}
|
|
char buf[MaxBufFmtAppendLen];
|
|
n = vsnprintf(buf, sizeof(buf), fmt, aq);
|
|
va_end(aq);
|
|
return append(buf, n);
|
|
}
|
|
use(n);
|
|
va_end(aq);
|
|
return this;
|
|
}
|
|
|
|
Segment::Segment()
|
|
{
|
|
}
|
|
|
|
Segment::Segment(BufferPtr beginBuf, int beginPos, BufferPtr endBuf, int endPos):
|
|
mBegin(beginBuf, beginPos),
|
|
mCur(beginBuf, beginPos),
|
|
mEnd(endBuf, endPos)
|
|
{
|
|
}
|
|
|
|
Segment::Segment(const Segment& oth):
|
|
mBegin(oth.mBegin),
|
|
mCur(oth.mCur),
|
|
mEnd(oth.mEnd)
|
|
{
|
|
}
|
|
|
|
Segment::Segment(Segment&& oth):
|
|
mBegin(oth.mBegin),
|
|
mCur(oth.mCur),
|
|
mEnd(oth.mEnd)
|
|
{
|
|
}
|
|
|
|
Segment::~Segment()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
Segment& Segment::operator=(const Segment& oth)
|
|
{
|
|
if (this != &oth) {
|
|
mBegin = oth.mBegin;
|
|
mCur = oth.mCur;
|
|
mEnd = oth.mEnd;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void Segment::clear()
|
|
{
|
|
mBegin.buf = nullptr;
|
|
mBegin.pos = 0;
|
|
mCur.buf = nullptr;
|
|
mCur.pos = 0;
|
|
mEnd.buf = nullptr;
|
|
mEnd.pos = 0;
|
|
}
|
|
|
|
Buffer* Segment::set(Buffer* buf, const char* dat, int len)
|
|
{
|
|
if (!buf) {
|
|
buf = BufferAlloc::create();
|
|
}
|
|
int pos = buf->length();
|
|
Buffer* nbuf = buf->append(dat, len);
|
|
mBegin.buf = buf;
|
|
mBegin.pos = pos;
|
|
mCur.buf = buf;
|
|
mCur.pos = pos;
|
|
mEnd.buf = nbuf;
|
|
mEnd.pos = nbuf->length();
|
|
return nbuf;
|
|
}
|
|
|
|
Buffer* Segment::fset(Buffer* buf, const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
try {
|
|
return vfset(buf, fmt, ap);
|
|
} catch (...) {
|
|
va_end(ap);
|
|
throw;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Buffer* Segment::vfset(Buffer* buf, const char* fmt, va_list ap)
|
|
{
|
|
if (!buf) {
|
|
buf = BufferAlloc::create();
|
|
}
|
|
int pos = buf->length();
|
|
Buffer* nbuf = buf->vfappend(fmt, ap);
|
|
mBegin.buf = buf;
|
|
mBegin.pos = pos;
|
|
mCur = mBegin;
|
|
mEnd.buf = nbuf;
|
|
mEnd.pos = nbuf->length();
|
|
return nbuf;
|
|
}
|
|
|
|
int Segment::length() const
|
|
{
|
|
Buffer* buf = mBegin.buf;
|
|
int pos = mBegin.pos;
|
|
int len = 0;
|
|
while (buf) {
|
|
if (buf == mEnd.buf) {
|
|
len += mEnd.pos - pos;
|
|
break;
|
|
} else {
|
|
len += buf->length() - pos;
|
|
}
|
|
buf = buf->next();
|
|
pos = 0;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
bool Segment::get(const char*& dat, int& len) const
|
|
{
|
|
if (mCur.buf == mEnd.buf && mCur.pos >= mEnd.pos) {
|
|
dat = nullptr;
|
|
len = 0;
|
|
return false;
|
|
}
|
|
dat = mCur.buf->data() + mCur.pos;
|
|
len = (mCur.buf == mEnd.buf ? mEnd.pos : mCur.buf->length()) - mCur.pos;
|
|
return true;
|
|
}
|
|
|
|
int Segment::fill(IOVec* vecs, int len, bool& all) const
|
|
{
|
|
int n = 0;
|
|
BufferPos p = mCur;
|
|
all = false;
|
|
while (n < len && p != mEnd) {
|
|
vecs[n].dat = p.buf->data() + p.pos;
|
|
vecs[n].len = (p.buf == mEnd.buf ? mEnd.pos : p.buf->length()) - p.pos;
|
|
vecs[n].seg = const_cast<Segment*>(this);
|
|
vecs[n].buf = p.buf;
|
|
vecs[n].pos = p.pos;
|
|
vecs[n].req = nullptr;
|
|
++n;
|
|
if (p.buf == mEnd.buf) {
|
|
all = true;
|
|
break;
|
|
} else {
|
|
p.buf = p.buf->next();
|
|
p.pos = 0;
|
|
}
|
|
}
|
|
if (n < len && n == 0) {
|
|
all = true;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
//caller must sure cnt < segment length
|
|
void Segment::cut(int cnt)
|
|
{
|
|
if (cnt > 0) {
|
|
while (cnt > 0 && mBegin.buf) {
|
|
BufferPtr buf = mBegin.buf;
|
|
int len = (buf == mEnd.buf ? mEnd.pos : buf->length()) - mBegin.pos;
|
|
if (len <= cnt) {
|
|
if (buf == mEnd.buf) {
|
|
mBegin.buf = nullptr;
|
|
mBegin.pos = 0;
|
|
mCur = mEnd = mBegin;
|
|
break;
|
|
}
|
|
cnt -= len;
|
|
mBegin.buf = buf->next();
|
|
mBegin.pos = 0;
|
|
if (mCur.buf == buf) {
|
|
mCur = mBegin;
|
|
}
|
|
} else {
|
|
mBegin.pos += cnt;
|
|
if (mCur.buf == mBegin.buf && mCur.pos < mBegin.pos) {
|
|
mCur.pos = mBegin.pos;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//caller must sure cnt < segment length
|
|
void Segment::use(int cnt)
|
|
{
|
|
while (cnt > 0) {
|
|
if (mCur.buf == mEnd.buf) {
|
|
mCur.pos += cnt;
|
|
if (mCur.pos > mEnd.pos) {
|
|
mCur.pos = mEnd.pos;
|
|
}
|
|
break;
|
|
} else {
|
|
int n = mCur.buf->length() - mCur.pos;
|
|
if (n <= cnt) {
|
|
mCur.buf = mCur.buf->next();
|
|
mCur.pos = 0;
|
|
} else {
|
|
mCur.pos += cnt;
|
|
}
|
|
cnt -= n;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Segment::seek(Buffer* buf, int pos, int cnt)
|
|
{
|
|
mCur.buf = buf;
|
|
mCur.pos = pos;
|
|
use(cnt);
|
|
}
|
|
|
|
int Segment::dump(char* dat, int len) const
|
|
{
|
|
int cnt = 0;
|
|
BufferPtr buf = mBegin.buf;
|
|
int pos = mBegin.pos;
|
|
bool end = false;
|
|
while (buf && !end) {
|
|
int num;
|
|
if (buf == mEnd.buf) {
|
|
num = mEnd.pos - pos;
|
|
end = true;
|
|
} else {
|
|
num = buf->length() - pos;
|
|
}
|
|
if (dat && len > 0) {
|
|
memcpy(dat, buf->data() + pos, len > num ? num : len);
|
|
dat += num;
|
|
len -= num;
|
|
}
|
|
cnt += num;
|
|
buf = buf->next();
|
|
pos = 0;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
bool Segment::hasPrefix(const char* prefix) const
|
|
{
|
|
const char* p = prefix;
|
|
BufferPtr buf = mBegin.buf;
|
|
int pos = mBegin.pos;
|
|
bool end = false;
|
|
while (buf && !end) {
|
|
int last = buf->length();
|
|
if (buf == mEnd.buf) {
|
|
last = mEnd.pos;
|
|
end = true;
|
|
}
|
|
while (pos < last && *p) {
|
|
if (buf->data()[pos++] != *p++) {
|
|
return false;
|
|
}
|
|
}
|
|
buf = buf->next();
|
|
pos = 0;
|
|
}
|
|
return *p == '\0';
|
|
}
|