mirror of
https://github.com/stefanocasazza/ULib.git
synced 2025-09-28 19:05:55 +08:00
sync
This commit is contained in:
parent
c233caf07a
commit
8976b94e73
|
@ -261,6 +261,7 @@ U_EXPORT char* u_memoryDump( char* restrict bp, unsigned char* restrict cp, u
|
||||||
U_EXPORT uint32_t u_memory_dump(char* restrict bp, unsigned char* restrict cp, uint32_t n);
|
U_EXPORT uint32_t u_memory_dump(char* restrict bp, unsigned char* restrict cp, uint32_t n);
|
||||||
|
|
||||||
U_EXPORT uint8_t u_get_loadavg(void); /* Get the load average of the system (over last 1 minute) */
|
U_EXPORT uint8_t u_get_loadavg(void); /* Get the load average of the system (over last 1 minute) */
|
||||||
|
U_EXPORT uint16_t u_crc16(const char* a, uint32_t len); /* CRC16 implementation according to CCITT standards */
|
||||||
U_EXPORT uint32_t u_printSize(char* restrict buffer, uint64_t bytes); /* print size using u_calcRate() */
|
U_EXPORT uint32_t u_printSize(char* restrict buffer, uint64_t bytes); /* print size using u_calcRate() */
|
||||||
|
|
||||||
U_EXPORT int u_getScreenWidth(void) __pure; /* Determine the width of the terminal we're running on */
|
U_EXPORT int u_getScreenWidth(void) __pure; /* Determine the width of the terminal we're running on */
|
||||||
|
|
|
@ -316,7 +316,7 @@ protected:
|
||||||
~UClient_Base();
|
~UClient_Base();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
U_DISALLOW_COPY_AND_ASSIGN(UClient_Base)
|
// U_DISALLOW_COPY_AND_ASSIGN(UClient_Base)
|
||||||
|
|
||||||
static USocket* csocket;
|
static USocket* csocket;
|
||||||
static vPFu resize_response_buffer;
|
static vPFu resize_response_buffer;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define ULIB_REDIS_H 1
|
#define ULIB_REDIS_H 1
|
||||||
|
|
||||||
#include <ulib/notifier.h>
|
#include <ulib/notifier.h>
|
||||||
|
#include <ulib/net/tcpsocket.h>
|
||||||
#include <ulib/net/unixsocket.h>
|
#include <ulib/net/unixsocket.h>
|
||||||
#include <ulib/net/client/client.h>
|
#include <ulib/net/client/client.h>
|
||||||
|
|
||||||
|
@ -62,6 +63,8 @@
|
||||||
typedef void (*vPFcs) (const UString&);
|
typedef void (*vPFcs) (const UString&);
|
||||||
typedef void (*vPFcscs)(const UString&,const UString&);
|
typedef void (*vPFcscs)(const UString&,const UString&);
|
||||||
|
|
||||||
|
class UREDISClusterClient;
|
||||||
|
|
||||||
class U_EXPORT UREDISClient_Base : public UClient_Base, UEventFd {
|
class U_EXPORT UREDISClient_Base : public UClient_Base, UEventFd {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -189,6 +192,45 @@ public:
|
||||||
|
|
||||||
bool connect(const char* host = U_NULLPTR, unsigned int _port = 6379);
|
bool connect(const char* host = U_NULLPTR, unsigned int _port = 6379);
|
||||||
|
|
||||||
|
// by Victor Stewart
|
||||||
|
|
||||||
|
UString single(const UString& pipeline)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClient_Base::single(%V)", pipeline.rep)
|
||||||
|
|
||||||
|
(void) processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(pipeline));
|
||||||
|
|
||||||
|
return vitem[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void silencedSingle(UString& pipeline)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClient_Base::silencedSingle(%V)", pipeline.rep)
|
||||||
|
|
||||||
|
(void) pipeline.insert(0, U_CONSTANT_TO_PARAM("CLIENT REPLY SKIP \r\n"));
|
||||||
|
|
||||||
|
(void) processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
const UVector<UString>& multi(const UString& pipeline)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClient_Base::multi(%V)", pipeline.rep)
|
||||||
|
|
||||||
|
(void) processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(pipeline));
|
||||||
|
|
||||||
|
return vitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void silencedMulti(UString& pipeline)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClient_Base::silencedMulti(%V)", pipeline.rep)
|
||||||
|
|
||||||
|
(void) pipeline.insert(0, U_CONSTANT_TO_PARAM("CLIENT REPLY OFF \r\n"));
|
||||||
|
(void) pipeline.append(U_CONSTANT_TO_PARAM("CLIENT REPLY ON \r\n"));
|
||||||
|
|
||||||
|
(void) processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
// STRING (@see http://redis.io/commands#string)
|
// STRING (@see http://redis.io/commands#string)
|
||||||
|
|
||||||
bool get(const char* key, uint32_t keylen) // Get the value of a key
|
bool get(const char* key, uint32_t keylen) // Get the value of a key
|
||||||
|
@ -857,7 +899,9 @@ protected:
|
||||||
private:
|
private:
|
||||||
bool getResponseItem() U_NO_EXPORT;
|
bool getResponseItem() U_NO_EXPORT;
|
||||||
|
|
||||||
U_DISALLOW_COPY_AND_ASSIGN(UREDISClient_Base)
|
friend class UREDISClusterClient;
|
||||||
|
|
||||||
|
// U_DISALLOW_COPY_AND_ASSIGN(UREDISClient_Base)
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Socket> class U_EXPORT UREDISClient : public UREDISClient_Base {
|
template <class Socket> class U_EXPORT UREDISClient : public UREDISClient_Base {
|
||||||
|
@ -882,7 +926,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
U_DISALLOW_COPY_AND_ASSIGN(UREDISClient)
|
// U_DISALLOW_COPY_AND_ASSIGN(UREDISClient)
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> class U_EXPORT UREDISClient<UUnixSocket> : public UREDISClient_Base {
|
template <> class U_EXPORT UREDISClient<UUnixSocket> : public UREDISClient_Base {
|
||||||
|
@ -931,4 +975,109 @@ public:
|
||||||
private:
|
private:
|
||||||
U_DISALLOW_COPY_AND_ASSIGN(UREDISClient<UUnixSocket>)
|
U_DISALLOW_COPY_AND_ASSIGN(UREDISClient<UUnixSocket>)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// by Victor Stewart
|
||||||
|
|
||||||
|
#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX17)
|
||||||
|
# include <vector>
|
||||||
|
|
||||||
|
class U_EXPORT UREDISClusterClient : public UREDISClient<UTCPSocket> {
|
||||||
|
private:
|
||||||
|
struct RedisNode {
|
||||||
|
UString ipAddress;
|
||||||
|
UREDISClient<UTCPSocket> client;
|
||||||
|
uint16_t lowHashSlot, highHashSlot;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ClusterError : uint8_t {
|
||||||
|
none,
|
||||||
|
moved,
|
||||||
|
ask,
|
||||||
|
tryagain
|
||||||
|
};
|
||||||
|
|
||||||
|
ClusterError error;
|
||||||
|
UString temporaryASKip;
|
||||||
|
std::vector<RedisNode> redisNodes;
|
||||||
|
|
||||||
|
uint16_t hashslotForKey(const UString& hashableKey) { return u_crc16(U_STRING_TO_PARAM(hashableKey)); }
|
||||||
|
|
||||||
|
uint16_t hashslotFromCommand(const UString& command)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClusterClient::hashslotFromCommand(%V)", command.rep)
|
||||||
|
|
||||||
|
// expects hashable keys to be delivered as abc{hashableKey}xyz value blah \r\n
|
||||||
|
|
||||||
|
uint32_t beginning = command.find('{') + 1,
|
||||||
|
end = command.find('}', beginning) - 1;
|
||||||
|
|
||||||
|
return hashslotForKey(command.substr(beginning, end - beginning));
|
||||||
|
}
|
||||||
|
|
||||||
|
UREDISClient<UTCPSocket>& clientForHashslot(uint16_t hashslot)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClusterClient::clientForHashslot(%u)", hashslot)
|
||||||
|
|
||||||
|
for (RedisNode& workingNode : redisNodes)
|
||||||
|
{
|
||||||
|
if ((workingNode.lowHashSlot <= hashslot) || (workingNode.highHashSlot >= hashslot)) return workingNode.client;
|
||||||
|
}
|
||||||
|
|
||||||
|
return redisNodes[0].client;
|
||||||
|
}
|
||||||
|
|
||||||
|
UREDISClient<UTCPSocket>& clientForASKip()
|
||||||
|
{
|
||||||
|
for (RedisNode& workingNode : redisNodes)
|
||||||
|
{
|
||||||
|
if (temporaryASKip == workingNode.ipAddress) return workingNode.client;
|
||||||
|
}
|
||||||
|
|
||||||
|
return redisNodes[0].client;
|
||||||
|
}
|
||||||
|
|
||||||
|
UREDISClient<UTCPSocket>& clientForHashableKey(const UString& hashableKey) { return clientForHashslot(hashslotForKey(hashableKey)); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
UREDISClusterClient() : UREDISClient<UTCPSocket>()
|
||||||
|
{
|
||||||
|
U_TRACE_CTOR(0, UREDISClusterClient, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
~UREDISClusterClient()
|
||||||
|
{
|
||||||
|
U_TRACE_DTOR(0, UREDISClusterClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
void processResponse();
|
||||||
|
void calculateNodeMap();
|
||||||
|
|
||||||
|
const UVector<UString>& processPipeline(UString& pipeline, bool silence);
|
||||||
|
|
||||||
|
// all of these multis require all keys to exist within a single hash slot (on the same node isn't good enough)
|
||||||
|
|
||||||
|
UString clusterSingle(const UString& hashableKey, const UString& pipeline) { return clientForHashableKey(hashableKey).single(pipeline); }
|
||||||
|
const UVector<UString>& clusterMulti( const UString& hashableKey, const UString& pipeline) { return clientForHashableKey(hashableKey).multi(pipeline); }
|
||||||
|
|
||||||
|
void clusterSilencedMulti( const UString& hashableKey, UString& pipeline) { clientForHashableKey(hashableKey).silencedMulti(pipeline); }
|
||||||
|
void clusterSilencedSingle(const UString& hashableKey, UString& pipeline) { clientForHashableKey(hashableKey).silencedSingle(pipeline); }
|
||||||
|
|
||||||
|
// anon multis are pipelined commands of various keys that might belong to many nodes. always processed in order. commands always delimined by \r\n
|
||||||
|
|
||||||
|
const UVector<UString>& clusterAnonMulti( UString& pipeline) { return processPipeline(pipeline, false); }
|
||||||
|
void clusterSilencedAnonMulti(UString& pipeline) { (void) processPipeline(pipeline, true); }
|
||||||
|
|
||||||
|
bool clusterUnsubscribe(const UString& hashableKey, const UString& channel) { return clientForHashableKey(hashableKey).unsubscribe(channel); }
|
||||||
|
bool clusterSubscribe( const UString& hashableKey, const UString& channel, vPFcscs callback) { return clientForHashableKey(hashableKey).subscribe(channel, callback); }
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
|
||||||
|
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
|
||||||
|
const char* dump(bool _reset) const { return UREDISClient_Base::dump(_reset); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
U_DISALLOW_COPY_AND_ASSIGN(UREDISClusterClient)
|
||||||
|
};
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -566,6 +566,22 @@ public:
|
||||||
|
|
||||||
// EXTENSION
|
// EXTENSION
|
||||||
|
|
||||||
|
bool isNumber(uint32_t pos) const
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UStringRep::isNumber(%u)", pos)
|
||||||
|
|
||||||
|
U_CHECK_MEMORY
|
||||||
|
|
||||||
|
if (_length)
|
||||||
|
{
|
||||||
|
U_INTERNAL_ASSERT_MINOR(pos, _length)
|
||||||
|
|
||||||
|
if (u_isNumber(str + pos, _length - pos)) U_RETURN(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
U_RETURN(false);
|
||||||
|
}
|
||||||
|
|
||||||
bool isBinary(uint32_t pos) const
|
bool isBinary(uint32_t pos) const
|
||||||
{
|
{
|
||||||
U_TRACE(0, "UStringRep::isBinary(%u)", pos)
|
U_TRACE(0, "UStringRep::isBinary(%u)", pos)
|
||||||
|
@ -2098,6 +2114,7 @@ public:
|
||||||
bool isText(uint32_t pos = 0) const { return rep->isText(pos); }
|
bool isText(uint32_t pos = 0) const { return rep->isText(pos); }
|
||||||
bool isUTF8(uint32_t pos = 0) const { return rep->isUTF8(pos); }
|
bool isUTF8(uint32_t pos = 0) const { return rep->isUTF8(pos); }
|
||||||
bool isUTF16(uint32_t pos = 0) const { return rep->isUTF16(pos); }
|
bool isUTF16(uint32_t pos = 0) const { return rep->isUTF16(pos); }
|
||||||
|
bool isNumber(uint32_t pos = 0) const { return rep->isNumber(pos); }
|
||||||
bool isBinary(uint32_t pos = 0) const { return rep->isBinary(pos); }
|
bool isBinary(uint32_t pos = 0) const { return rep->isBinary(pos); }
|
||||||
bool isBase64(uint32_t pos = 0) const { return rep->isBase64(pos); }
|
bool isBase64(uint32_t pos = 0) const { return rep->isBase64(pos); }
|
||||||
bool isBase64Url(uint32_t pos = 0) const { return rep->isBase64Url(pos); }
|
bool isBase64Url(uint32_t pos = 0) const { return rep->isBase64Url(pos); }
|
||||||
|
|
|
@ -821,6 +821,68 @@ __pure uint32_t u_findEndHeader(const char* restrict str, uint32_t n)
|
||||||
return endHeader;
|
return endHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CRC16 implementation according to CCITT standards
|
||||||
|
*
|
||||||
|
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the following parameters:
|
||||||
|
*
|
||||||
|
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
|
||||||
|
* Width : 16 bit
|
||||||
|
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
|
||||||
|
* Initialization : 0000
|
||||||
|
* Reflect Input byte : False
|
||||||
|
* Reflect Output CRC : False
|
||||||
|
* Xor constant to output CRC : 0000
|
||||||
|
* Output for "123456789" : 31C3
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint16_t u_crc16(const char* buf, uint32_t len)
|
||||||
|
{
|
||||||
|
static uint16_t crc16tab[256]= {
|
||||||
|
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
|
||||||
|
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
|
||||||
|
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
|
||||||
|
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
|
||||||
|
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
|
||||||
|
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
|
||||||
|
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
|
||||||
|
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
|
||||||
|
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
|
||||||
|
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
|
||||||
|
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
|
||||||
|
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
|
||||||
|
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
|
||||||
|
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
|
||||||
|
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
|
||||||
|
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
|
||||||
|
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
|
||||||
|
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
|
||||||
|
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
|
||||||
|
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
|
||||||
|
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
|
||||||
|
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
|
||||||
|
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
|
||||||
|
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
|
||||||
|
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
|
||||||
|
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
|
||||||
|
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
|
||||||
|
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
|
||||||
|
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
|
||||||
|
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
|
||||||
|
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
|
||||||
|
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t crc = 0;
|
||||||
|
uint32_t counter;
|
||||||
|
|
||||||
|
U_INTERNAL_TRACE("u_crc16(%.*s,%u)", U_min(len,128), buf, len)
|
||||||
|
|
||||||
|
for (counter = 0; counter < len; ++counter) crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++) & 0x00FF];
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine the width of the terminal we're running on */
|
/* Determine the width of the terminal we're running on */
|
||||||
|
|
||||||
__pure int u_getScreenWidth(void)
|
__pure int u_getScreenWidth(void)
|
||||||
|
@ -1456,7 +1518,7 @@ __pure bool u_isNumber(const char* restrict s, uint32_t n)
|
||||||
((*(const unsigned char* restrict)s) >> 4) == 0x03 &&
|
((*(const unsigned char* restrict)s) >> 4) == 0x03 &&
|
||||||
vdigit[(*(const unsigned char* restrict)s) & 0x0f])
|
vdigit[(*(const unsigned char* restrict)s) & 0x0f])
|
||||||
{
|
{
|
||||||
U_INTERNAL_PRINT("*s = %c, *s >> 4 = %c ", *s, (*(char* restrict)s) >> 4)
|
U_INTERNAL_PRINT("*s = %c, *s >> 4 = %c", *s, (*(char* restrict)s) >> 4)
|
||||||
|
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,9 +617,201 @@ int UREDISClient_Base::handlerRead()
|
||||||
U_RETURN(U_NOTIFIER_OK);
|
U_RETURN(U_NOTIFIER_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(U_STDCPP_ENABLE)
|
||||||
|
|
||||||
|
// by Victor Stewart
|
||||||
|
|
||||||
|
# if defined(HAVE_CXX17)
|
||||||
|
void UREDISClusterClient::processResponse()
|
||||||
|
{
|
||||||
|
U_TRACE_NO_PARAM(0, "UREDISClusterClient::processResponse()")
|
||||||
|
|
||||||
|
if (UClient_Base::response.find("MOVED", 0, 5) != U_NOT_FOUND)
|
||||||
|
{
|
||||||
|
// MOVED 3999 127.0.0.1:6381 => the hashslot has been moved to another master node
|
||||||
|
|
||||||
|
error = ClusterError::moved;
|
||||||
|
|
||||||
|
calculateNodeMap();
|
||||||
|
}
|
||||||
|
else if (UClient_Base::response.find("ASK", 0, 3) != U_NOT_FOUND)
|
||||||
|
{
|
||||||
|
// ASK 3999 127.0.0.1:6381 => this means that one of the hash slots is being migrated to another server
|
||||||
|
|
||||||
|
error = ClusterError::ask;
|
||||||
|
|
||||||
|
uint32_t _start = UClient_Base::response.find(' ', 8) + 1,
|
||||||
|
end = UClient_Base::response.find(':', _start);
|
||||||
|
|
||||||
|
(void) temporaryASKip.assign(UClient_Base::response.substr(_start, end - _start));
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (UClient_Base::response.find("TRYAGAIN", 0, 8) != U_NOT_FOUND)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* during a resharding the multi-key operations targeting keys that all exist and are all still in the same node (either the source or destination node) are still available.
|
||||||
|
* Operations on keys that don't exist or are - during the resharding - split between the source and destination nodes, will generate a -TRYAGAIN error. The client can try
|
||||||
|
* the operation after some time, or report back the error. As soon as migration of the specified hash slot has terminated, all multi-key operations are available again for
|
||||||
|
* that hash slot
|
||||||
|
*/
|
||||||
|
|
||||||
|
error = ClusterError::tryagain;
|
||||||
|
|
||||||
|
UTimeVal(0L, 1000L).nanosleep(); // 0 sec, 1000 microsec = 1ms
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = ClusterError::none;
|
||||||
|
|
||||||
|
UREDISClient<UTCPSocket>::processResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const UVector<UString>& UREDISClusterClient::processPipeline(UString& pipeline, bool silence)
|
||||||
|
{
|
||||||
|
U_TRACE(0, "UREDISClusterClient::processPipeline(%V,%b)", pipeline.rep, silence)
|
||||||
|
|
||||||
|
uint16_t hashslot = 0, workingHashslot;
|
||||||
|
UString command, workingString(U_CAPACITY);
|
||||||
|
UVector<UString> commands(pipeline, "\r\n");
|
||||||
|
|
||||||
|
for (uint32_t count = 0, index = 0, n = commands.size(); index < n; ++index)
|
||||||
|
{
|
||||||
|
command = commands[index];
|
||||||
|
|
||||||
|
workingHashslot = hashslotFromCommand(command);
|
||||||
|
|
||||||
|
if (workingHashslot == hashslot)
|
||||||
|
{
|
||||||
|
(void) workingString.append(command + "\r\n");
|
||||||
|
|
||||||
|
++count;
|
||||||
|
|
||||||
|
if ((index + 1) < n) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashslot = workingHashslot;
|
||||||
|
|
||||||
|
if (silence)
|
||||||
|
{
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
(void) workingString.insert(0, U_CONSTANT_TO_PARAM("CLIENT REPLY OFF \r\n"));
|
||||||
|
(void) workingString.append(U_CONSTANT_TO_PARAM("CLIENT REPLY ON \r\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(void) pipeline.insert(0, U_CONSTANT_TO_PARAM("CLIENT REPLY SKIP \r\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UREDISClient<UTCPSocket>& client = clientForHashslot(hashslot);
|
||||||
|
|
||||||
|
replay:
|
||||||
|
(void) client.processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(workingString));
|
||||||
|
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case ClusterError::moved:
|
||||||
|
case ClusterError::tryagain:
|
||||||
|
{
|
||||||
|
goto replay;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClusterError::ask:
|
||||||
|
{
|
||||||
|
UREDISClient<UTCPSocket>& temporaryClient = clientForASKip();
|
||||||
|
|
||||||
|
(void) temporaryClient.processRequest(U_RC_MULTIBULK, U_STRING_TO_PARAM(workingString));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ClusterError::none: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (silence == false) vitem.move(client.vitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UREDISClusterClient::calculateNodeMap()
|
||||||
|
{
|
||||||
|
U_TRACE_NO_PARAM(0, "UREDISClusterClient::calculateNodeMap()")
|
||||||
|
|
||||||
|
/*
|
||||||
|
127.0.0.1:30001> cluster slots
|
||||||
|
1) 1) (integer) 0
|
||||||
|
2) (integer) 5460
|
||||||
|
3) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30001
|
||||||
|
3) "09dbe9720cda62f7865eabc5fd8857c5d2678366"
|
||||||
|
4) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30004
|
||||||
|
3) "821d8ca00d7ccf931ed3ffc7e3db0599d2271abf"
|
||||||
|
2) 1) (integer) 5461
|
||||||
|
2) (integer) 10922
|
||||||
|
3) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30002
|
||||||
|
3) "c9d93d9f2c0c524ff34cc11838c2003d8c29e013"
|
||||||
|
4) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30005
|
||||||
|
3) "faadb3eb99009de4ab72ad6b6ed87634c7ee410f"
|
||||||
|
3) 1) (integer) 10923
|
||||||
|
2) (integer) 16383
|
||||||
|
3) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30003
|
||||||
|
3) "044ec91f325b7595e76dbcb18cc688b6a5b434a1"
|
||||||
|
4) 1) "127.0.0.1"
|
||||||
|
2) (integer) 30006
|
||||||
|
3) "58e6e48d41228013e5d9c1c37c5060693925e97e"
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool findHashSlots = true;
|
||||||
|
uint16_t workingLowHashSlot;
|
||||||
|
uint16_t workingHighHashSlot;
|
||||||
|
|
||||||
|
(void) UREDISClient_Base::processRequest(U_RC_MULTIBULK, U_CONSTANT_TO_PARAM("CLUSTER SLOTS"));
|
||||||
|
|
||||||
|
const UVector<UString>& rawNodes = UREDISClient_Base::vitem;
|
||||||
|
|
||||||
|
for (uint32_t a = 0, b = rawNodes.size(); a < b; ++a)
|
||||||
|
{
|
||||||
|
if (findHashSlots)
|
||||||
|
{
|
||||||
|
if (rawNodes[a].isNumber() &&
|
||||||
|
rawNodes[a+1].isNumber())
|
||||||
|
{
|
||||||
|
workingLowHashSlot = rawNodes[a++].strtoul();
|
||||||
|
workingHighHashSlot = rawNodes[a].strtoul();
|
||||||
|
|
||||||
|
findHashSlots = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the immediate next after hash slot is the master
|
||||||
|
|
||||||
|
RedisNode workingNode;
|
||||||
|
|
||||||
|
workingNode.lowHashSlot = workingLowHashSlot;
|
||||||
|
workingNode.highHashSlot = workingHighHashSlot;
|
||||||
|
(void) workingNode.ipAddress.assign(rawNodes[a]);
|
||||||
|
|
||||||
|
workingNode.client.connect(workingNode.ipAddress.c_str(), rawNodes[++a].strtoul());
|
||||||
|
|
||||||
|
redisNodes.push_back(std::move(workingNode));
|
||||||
|
|
||||||
|
findHashSlots = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
|
# if defined(DEBUG)
|
||||||
const char* UREDISClient_Base::dump(bool _reset) const
|
const char* UREDISClient_Base::dump(bool _reset) const
|
||||||
{
|
{
|
||||||
UClient_Base::dump(false);
|
UClient_Base::dump(false);
|
||||||
|
@ -637,4 +829,5 @@ const char* UREDISClient_Base::dump(bool _reset) const
|
||||||
|
|
||||||
return U_NULLPTR;
|
return U_NULLPTR;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
1
tests/ulib/err/application.err
Normal file
1
tests/ulib/err/application.err
Normal file
|
@ -0,0 +1 @@
|
||||||
|
../.function: line 259: ../../examples/application/application: No such file or directory
|
0
tests/ulib/out/application.out
Normal file
0
tests/ulib/out/application.out
Normal file
|
@ -206,8 +206,8 @@ plugin/product1.lo: plugin/product1.cpp /usr/include/stdc-predef.h \
|
||||||
/usr/include/unicode/utf16.h /usr/include/unicode/utf_old.h \
|
/usr/include/unicode/utf16.h /usr/include/unicode/utf_old.h \
|
||||||
/usr/include/unicode/uenum.h /usr/include/unicode/localpointer.h \
|
/usr/include/unicode/uenum.h /usr/include/unicode/localpointer.h \
|
||||||
/usr/include/libxml2/libxml/xmlIO.h \
|
/usr/include/libxml2/libxml/xmlIO.h \
|
||||||
/usr/include/libxml2/libxml/globals.h /usr/include/libxml2/libxml/SAX.h \
|
/usr/include/libxml2/libxml/globals.h /usr/include/libxml2/libxml/SAX2.h \
|
||||||
/usr/include/libxml2/libxml/xlink.h /usr/include/libxml2/libxml/SAX2.h \
|
/usr/include/libxml2/libxml/xlink.h \
|
||||||
/usr/include/libxml2/libxml/xmlmemory.h \
|
/usr/include/libxml2/libxml/xmlmemory.h \
|
||||||
/usr/include/libxml2/libxml/threads.h \
|
/usr/include/libxml2/libxml/threads.h \
|
||||||
../../include/ulib/internal/macro.h \
|
../../include/ulib/internal/macro.h \
|
||||||
|
@ -809,12 +809,10 @@ plugin/product.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/globals.h:
|
/usr/include/libxml2/libxml/globals.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/SAX.h:
|
/usr/include/libxml2/libxml/SAX2.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/xlink.h:
|
/usr/include/libxml2/libxml/xlink.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/SAX2.h:
|
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/xmlmemory.h:
|
/usr/include/libxml2/libxml/xmlmemory.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/threads.h:
|
/usr/include/libxml2/libxml/threads.h:
|
||||||
|
|
|
@ -206,8 +206,8 @@ plugin/product2.lo: plugin/product2.cpp /usr/include/stdc-predef.h \
|
||||||
/usr/include/unicode/utf16.h /usr/include/unicode/utf_old.h \
|
/usr/include/unicode/utf16.h /usr/include/unicode/utf_old.h \
|
||||||
/usr/include/unicode/uenum.h /usr/include/unicode/localpointer.h \
|
/usr/include/unicode/uenum.h /usr/include/unicode/localpointer.h \
|
||||||
/usr/include/libxml2/libxml/xmlIO.h \
|
/usr/include/libxml2/libxml/xmlIO.h \
|
||||||
/usr/include/libxml2/libxml/globals.h /usr/include/libxml2/libxml/SAX.h \
|
/usr/include/libxml2/libxml/globals.h /usr/include/libxml2/libxml/SAX2.h \
|
||||||
/usr/include/libxml2/libxml/xlink.h /usr/include/libxml2/libxml/SAX2.h \
|
/usr/include/libxml2/libxml/xlink.h \
|
||||||
/usr/include/libxml2/libxml/xmlmemory.h \
|
/usr/include/libxml2/libxml/xmlmemory.h \
|
||||||
/usr/include/libxml2/libxml/threads.h \
|
/usr/include/libxml2/libxml/threads.h \
|
||||||
../../include/ulib/internal/macro.h \
|
../../include/ulib/internal/macro.h \
|
||||||
|
@ -809,12 +809,10 @@ plugin/product.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/globals.h:
|
/usr/include/libxml2/libxml/globals.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/SAX.h:
|
/usr/include/libxml2/libxml/SAX2.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/xlink.h:
|
/usr/include/libxml2/libxml/xlink.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/SAX2.h:
|
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/xmlmemory.h:
|
/usr/include/libxml2/libxml/xmlmemory.h:
|
||||||
|
|
||||||
/usr/include/libxml2/libxml/threads.h:
|
/usr/include/libxml2/libxml/threads.h:
|
||||||
|
|
5
tests/ulib/tmp/c
Normal file
5
tests/ulib/tmp/c
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
c
|
||||||
|
c
|
||||||
|
c
|
||||||
|
c
|
||||||
|
c
|
Loading…
Reference in New Issue
Block a user