Throw error for conflicting bcast tracking prefixes (#8176)
Throw an error if there are conflicting bcast tracking prefixes.
This commit is contained in:
parent
47579bdf5c
commit
999494cef8
@ -2800,6 +2800,13 @@ NULL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options & CLIENT_TRACKING_BCAST) {
|
||||||
|
if (!checkPrefixCollisionsOrReply(c,prefix,numprefix)) {
|
||||||
|
zfree(prefix);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enableTracking(c,redir,options,prefix,numprefix);
|
enableTracking(c,redir,options,prefix,numprefix);
|
||||||
} else if (!strcasecmp(c->argv[2]->ptr,"off")) {
|
} else if (!strcasecmp(c->argv[2]->ptr,"off")) {
|
||||||
disableTracking(c);
|
disableTracking(c);
|
||||||
|
@ -1849,6 +1849,7 @@ uint64_t trackingGetTotalItems(void);
|
|||||||
uint64_t trackingGetTotalKeys(void);
|
uint64_t trackingGetTotalKeys(void);
|
||||||
uint64_t trackingGetTotalPrefixes(void);
|
uint64_t trackingGetTotalPrefixes(void);
|
||||||
void trackingBroadcastInvalidationMessages(void);
|
void trackingBroadcastInvalidationMessages(void);
|
||||||
|
int checkPrefixCollisionsOrReply(client *c, robj **prefix, size_t numprefix);
|
||||||
|
|
||||||
/* List data type */
|
/* List data type */
|
||||||
void listTypeTryConversion(robj *subject, robj *value);
|
void listTypeTryConversion(robj *subject, robj *value);
|
||||||
|
@ -99,6 +99,57 @@ void disableTracking(client *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int stringCheckPrefix(unsigned char *s1, size_t s1_len, unsigned char *s2, size_t s2_len) {
|
||||||
|
size_t min_length = s1_len < s2_len ? s1_len : s2_len;
|
||||||
|
return memcmp(s1,s2,min_length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if any of the provided prefixes collide with one another or
|
||||||
|
* with an existing prefix for the client. A collision is defined as two
|
||||||
|
* prefixes that will emit an invalidation for the same key. If no prefix
|
||||||
|
* collision is found, 1 is return, otherwise 0 is returned and the client
|
||||||
|
* has an error emitted describing the error. */
|
||||||
|
int checkPrefixCollisionsOrReply(client *c, robj **prefixes, size_t numprefix) {
|
||||||
|
for (size_t i = 0; i < numprefix; i++) {
|
||||||
|
/* Check input list has no overlap with existing prefixes. */
|
||||||
|
if (c->client_tracking_prefixes) {
|
||||||
|
raxIterator ri;
|
||||||
|
raxStart(&ri,c->client_tracking_prefixes);
|
||||||
|
raxSeek(&ri,"^",NULL,0);
|
||||||
|
while(raxNext(&ri)) {
|
||||||
|
if (stringCheckPrefix(ri.key,ri.key_len,
|
||||||
|
prefixes[i]->ptr,sdslen(prefixes[i]->ptr)))
|
||||||
|
{
|
||||||
|
sds collision = sdsnewlen(ri.key,ri.key_len);
|
||||||
|
addReplyErrorFormat(c,
|
||||||
|
"Prefix '%s' overlaps with an existing prefix '%s'. "
|
||||||
|
"Prefixes for a single client must not overlap.",
|
||||||
|
(unsigned char *)prefixes[i]->ptr,
|
||||||
|
(unsigned char *)collision);
|
||||||
|
sdsfree(collision);
|
||||||
|
raxStop(&ri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raxStop(&ri);
|
||||||
|
}
|
||||||
|
/* Check input has no overlap with itself. */
|
||||||
|
for (size_t j = i + 1; j < numprefix; j++) {
|
||||||
|
if (stringCheckPrefix(prefixes[i]->ptr,sdslen(prefixes[i]->ptr),
|
||||||
|
prefixes[j]->ptr,sdslen(prefixes[j]->ptr)))
|
||||||
|
{
|
||||||
|
addReplyErrorFormat(c,
|
||||||
|
"Prefix '%s' overlaps with another provided prefix '%s'. "
|
||||||
|
"Prefixes for a single client must not overlap.",
|
||||||
|
(unsigned char *)prefixes[i]->ptr,
|
||||||
|
(unsigned char *)prefixes[j]->ptr);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
|
/* Set the client 'c' to track the prefix 'prefix'. If the client 'c' is
|
||||||
* already registered for the specified prefix, no operation is performed. */
|
* already registered for the specified prefix, no operation is performed. */
|
||||||
void enableBcastTrackingForPrefix(client *c, char *prefix, size_t plen) {
|
void enableBcastTrackingForPrefix(client *c, char *prefix, size_t plen) {
|
||||||
|
@ -323,7 +323,25 @@ start_server {tags {"tracking"}} {
|
|||||||
set ping_reply [$rd read]
|
set ping_reply [$rd read]
|
||||||
assert {$inv_msg eq {invalidate key1}}
|
assert {$inv_msg eq {invalidate key1}}
|
||||||
assert {$ping_reply eq {PONG}}
|
assert {$ping_reply eq {PONG}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {BCAST with prefix collisions throw errors} {
|
||||||
|
set r [redis_client]
|
||||||
|
catch {$r CLIENT TRACKING ON BCAST PREFIX FOOBAR PREFIX FOO} output
|
||||||
|
assert_match {ERR Prefix 'FOOBAR'*'FOO'*} $output
|
||||||
|
|
||||||
|
catch {$r CLIENT TRACKING ON BCAST PREFIX FOO PREFIX FOOBAR} output
|
||||||
|
assert_match {ERR Prefix 'FOO'*'FOOBAR'*} $output
|
||||||
|
|
||||||
|
$r CLIENT TRACKING ON BCAST PREFIX FOO PREFIX BAR
|
||||||
|
catch {$r CLIENT TRACKING ON BCAST PREFIX FO} output
|
||||||
|
assert_match {ERR Prefix 'FO'*'FOO'*} $output
|
||||||
|
|
||||||
|
catch {$r CLIENT TRACKING ON BCAST PREFIX BARB} output
|
||||||
|
assert_match {ERR Prefix 'BARB'*'BAR'*} $output
|
||||||
|
|
||||||
|
$r CLIENT TRACKING OFF
|
||||||
|
}
|
||||||
|
|
||||||
test {Tracking gets notification on tracking table key eviction} {
|
test {Tracking gets notification on tracking table key eviction} {
|
||||||
$rd_redirection HELLO 2
|
$rd_redirection HELLO 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user