Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
a83e3663
Commit
a83e3663
authored
Feb 28, 2022
by
Oran Agra
Browse files
Merge remote-tracking branch 'origin/unstable' into 7.0
parents
d5915a16
5860fa3d
Changes
142
Expand all
Show whitespace changes
Inline
Side-by-side
src/commands/xsetid.json
View file @
a83e3663
...
@@ -4,8 +4,14 @@
...
@@ -4,8 +4,14 @@
"complexity"
:
"O(1)"
,
"complexity"
:
"O(1)"
,
"group"
:
"stream"
,
"group"
:
"stream"
,
"since"
:
"5.0.0"
,
"since"
:
"5.0.0"
,
"arity"
:
3
,
"arity"
:
-
3
,
"function"
:
"xsetidCommand"
,
"function"
:
"xsetidCommand"
,
"history"
:
[
[
"7.0.0"
,
"Added the `entries_added` and `max_deleted_entry_id` arguments."
]
],
"command_flags"
:
[
"command_flags"
:
[
"WRITE"
,
"WRITE"
,
"DENYOOM"
,
"DENYOOM"
,
...
@@ -43,6 +49,18 @@
...
@@ -43,6 +49,18 @@
{
{
"name"
:
"last-id"
,
"name"
:
"last-id"
,
"type"
:
"string"
"type"
:
"string"
},
{
"name"
:
"entries_added"
,
"token"
:
"ENTRIESADDED"
,
"type"
:
"integer"
,
"optional"
:
true
},
{
"name"
:
"max_deleted_entry_id"
,
"token"
:
"MAXDELETEDID"
,
"type"
:
"string"
,
"optional"
:
true
}
}
]
]
}
}
...
...
src/connection.c
View file @
a83e3663
...
@@ -178,6 +178,21 @@ static int connSocketWrite(connection *conn, const void *data, size_t data_len)
...
@@ -178,6 +178,21 @@ static int connSocketWrite(connection *conn, const void *data, size_t data_len)
return
ret
;
return
ret
;
}
}
static
int
connSocketWritev
(
connection
*
conn
,
const
struct
iovec
*
iov
,
int
iovcnt
)
{
int
ret
=
writev
(
conn
->
fd
,
iov
,
iovcnt
);
if
(
ret
<
0
&&
errno
!=
EAGAIN
)
{
conn
->
last_errno
=
errno
;
/* Don't overwrite the state of a connection that is not already
* connected, not to mess with handler callbacks.
*/
if
(
errno
!=
EINTR
&&
conn
->
state
==
CONN_STATE_CONNECTED
)
conn
->
state
=
CONN_STATE_ERROR
;
}
return
ret
;
}
static
int
connSocketRead
(
connection
*
conn
,
void
*
buf
,
size_t
buf_len
)
{
static
int
connSocketRead
(
connection
*
conn
,
void
*
buf
,
size_t
buf_len
)
{
int
ret
=
read
(
conn
->
fd
,
buf
,
buf_len
);
int
ret
=
read
(
conn
->
fd
,
buf
,
buf_len
);
if
(
!
ret
)
{
if
(
!
ret
)
{
...
@@ -349,6 +364,7 @@ ConnectionType CT_Socket = {
...
@@ -349,6 +364,7 @@ ConnectionType CT_Socket = {
.
ae_handler
=
connSocketEventHandler
,
.
ae_handler
=
connSocketEventHandler
,
.
close
=
connSocketClose
,
.
close
=
connSocketClose
,
.
write
=
connSocketWrite
,
.
write
=
connSocketWrite
,
.
writev
=
connSocketWritev
,
.
read
=
connSocketRead
,
.
read
=
connSocketRead
,
.
accept
=
connSocketAccept
,
.
accept
=
connSocketAccept
,
.
connect
=
connSocketConnect
,
.
connect
=
connSocketConnect
,
...
...
src/connection.h
View file @
a83e3663
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#define __REDIS_CONNECTION_H
#define __REDIS_CONNECTION_H
#include <errno.h>
#include <errno.h>
#include <sys/uio.h>
#define CONN_INFO_LEN 32
#define CONN_INFO_LEN 32
...
@@ -59,6 +60,7 @@ typedef struct ConnectionType {
...
@@ -59,6 +60,7 @@ typedef struct ConnectionType {
void
(
*
ae_handler
)(
struct
aeEventLoop
*
el
,
int
fd
,
void
*
clientData
,
int
mask
);
void
(
*
ae_handler
)(
struct
aeEventLoop
*
el
,
int
fd
,
void
*
clientData
,
int
mask
);
int
(
*
connect
)(
struct
connection
*
conn
,
const
char
*
addr
,
int
port
,
const
char
*
source_addr
,
ConnectionCallbackFunc
connect_handler
);
int
(
*
connect
)(
struct
connection
*
conn
,
const
char
*
addr
,
int
port
,
const
char
*
source_addr
,
ConnectionCallbackFunc
connect_handler
);
int
(
*
write
)(
struct
connection
*
conn
,
const
void
*
data
,
size_t
data_len
);
int
(
*
write
)(
struct
connection
*
conn
,
const
void
*
data
,
size_t
data_len
);
int
(
*
writev
)(
struct
connection
*
conn
,
const
struct
iovec
*
iov
,
int
iovcnt
);
int
(
*
read
)(
struct
connection
*
conn
,
void
*
buf
,
size_t
buf_len
);
int
(
*
read
)(
struct
connection
*
conn
,
void
*
buf
,
size_t
buf_len
);
void
(
*
close
)(
struct
connection
*
conn
);
void
(
*
close
)(
struct
connection
*
conn
);
int
(
*
accept
)(
struct
connection
*
conn
,
ConnectionCallbackFunc
accept_handler
);
int
(
*
accept
)(
struct
connection
*
conn
,
ConnectionCallbackFunc
accept_handler
);
...
@@ -142,6 +144,18 @@ static inline int connWrite(connection *conn, const void *data, size_t data_len)
...
@@ -142,6 +144,18 @@ static inline int connWrite(connection *conn, const void *data, size_t data_len)
return
conn
->
type
->
write
(
conn
,
data
,
data_len
);
return
conn
->
type
->
write
(
conn
,
data
,
data_len
);
}
}
/* Gather output data from the iovcnt buffers specified by the members of the iov
* array: iov[0], iov[1], ..., iov[iovcnt-1] and write to connection, behaves the same as writev(3).
*
* Like writev(3), a short write is possible. A -1 return indicates an error.
*
* The caller should NOT rely on errno. Testing for an EAGAIN-like condition, use
* connGetState() to see if the connection state is still CONN_STATE_CONNECTED.
*/
static
inline
int
connWritev
(
connection
*
conn
,
const
struct
iovec
*
iov
,
int
iovcnt
)
{
return
conn
->
type
->
writev
(
conn
,
iov
,
iovcnt
);
}
/* Read from the connection, behaves the same as read(2).
/* Read from the connection, behaves the same as read(2).
*
*
* Like read(2), a short read is possible. A return value of 0 will indicate the
* Like read(2), a short read is possible. A return value of 0 will indicate the
...
...
src/db.c
View file @
a83e3663
...
@@ -83,16 +83,16 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
...
@@ -83,16 +83,16 @@ robj *lookupKey(redisDb *db, robj *key, int flags) {
robj
*
val
=
NULL
;
robj
*
val
=
NULL
;
if
(
de
)
{
if
(
de
)
{
val
=
dictGetVal
(
de
);
val
=
dictGetVal
(
de
);
int
force_delete_expired
=
flags
&
LOOKUP_WRITE
;
if
(
force_delete_expired
)
{
/* Forcing deletion of expired keys on a replica makes the replica
/* Forcing deletion of expired keys on a replica makes the replica
* inconsistent with the master. The reason it's allowed for write
* inconsistent with the master. We forbid it on readonly replicas, but
* commands is to make writable replicas behave consistently. It
* we have to allow it on writable replicas to make write commands
* shall not be used in readonly commands. Modules are accepted so
* behave consistently.
* that we don't break old modules. */
*
client
*
c
=
server
.
in_script
?
scriptGetClient
()
:
server
.
current_client
;
* It's possible that the WRITE flag is set even during a readonly
serverAssert
(
!
c
||
!
c
->
cmd
||
(
c
->
cmd
->
flags
&
(
CMD_WRITE
|
CMD_MODULE
)));
* command, since the command may trigger events that cause modules to
}
* perform additional writes. */
int
is_ro_replica
=
server
.
masterhost
&&
server
.
repl_slave_ro
;
int
force_delete_expired
=
flags
&
LOOKUP_WRITE
&&
!
is_ro_replica
;
if
(
expireIfNeeded
(
db
,
key
,
force_delete_expired
))
{
if
(
expireIfNeeded
(
db
,
key
,
force_delete_expired
))
{
/* The key is no longer valid. */
/* The key is no longer valid. */
val
=
NULL
;
val
=
NULL
;
...
@@ -1340,6 +1340,11 @@ int dbSwapDatabases(int id1, int id2) {
...
@@ -1340,6 +1340,11 @@ int dbSwapDatabases(int id1, int id2) {
redisDb
aux
=
server
.
db
[
id1
];
redisDb
aux
=
server
.
db
[
id1
];
redisDb
*
db1
=
&
server
.
db
[
id1
],
*
db2
=
&
server
.
db
[
id2
];
redisDb
*
db1
=
&
server
.
db
[
id1
],
*
db2
=
&
server
.
db
[
id2
];
/* Swapdb should make transaction fail if there is any
* client watching keys */
touchAllWatchedKeysInDb
(
db1
,
db2
);
touchAllWatchedKeysInDb
(
db2
,
db1
);
/* Swap hash tables. Note that we don't swap blocking_keys,
/* Swap hash tables. Note that we don't swap blocking_keys,
* ready_keys and watched_keys, since we want clients to
* ready_keys and watched_keys, since we want clients to
* remain in the same DB they were. */
* remain in the same DB they were. */
...
@@ -1361,14 +1366,9 @@ int dbSwapDatabases(int id1, int id2) {
...
@@ -1361,14 +1366,9 @@ int dbSwapDatabases(int id1, int id2) {
* However normally we only do this check for efficiency reasons
* However normally we only do this check for efficiency reasons
* in dbAdd() when a list is created. So here we need to rescan
* in dbAdd() when a list is created. So here we need to rescan
* the list of clients blocked on lists and signal lists as ready
* the list of clients blocked on lists and signal lists as ready
* if needed.
* if needed. */
*
* Also the swapdb should make transaction fail if there is any
* client watching keys */
scanDatabaseForReadyLists
(
db1
);
scanDatabaseForReadyLists
(
db1
);
touchAllWatchedKeysInDb
(
db1
,
db2
);
scanDatabaseForReadyLists
(
db2
);
scanDatabaseForReadyLists
(
db2
);
touchAllWatchedKeysInDb
(
db2
,
db1
);
return
C_OK
;
return
C_OK
;
}
}
...
@@ -1387,6 +1387,10 @@ void swapMainDbWithTempDb(redisDb *tempDb) {
...
@@ -1387,6 +1387,10 @@ void swapMainDbWithTempDb(redisDb *tempDb) {
redisDb
aux
=
server
.
db
[
i
];
redisDb
aux
=
server
.
db
[
i
];
redisDb
*
activedb
=
&
server
.
db
[
i
],
*
newdb
=
&
tempDb
[
i
];
redisDb
*
activedb
=
&
server
.
db
[
i
],
*
newdb
=
&
tempDb
[
i
];
/* Swapping databases should make transaction fail if there is any
* client watching keys. */
touchAllWatchedKeysInDb
(
activedb
,
newdb
);
/* Swap hash tables. Note that we don't swap blocking_keys,
/* Swap hash tables. Note that we don't swap blocking_keys,
* ready_keys and watched_keys, since clients
* ready_keys and watched_keys, since clients
* remain in the same DB they were. */
* remain in the same DB they were. */
...
@@ -1408,12 +1412,8 @@ void swapMainDbWithTempDb(redisDb *tempDb) {
...
@@ -1408,12 +1412,8 @@ void swapMainDbWithTempDb(redisDb *tempDb) {
* However normally we only do this check for efficiency reasons
* However normally we only do this check for efficiency reasons
* in dbAdd() when a list is created. So here we need to rescan
* in dbAdd() when a list is created. So here we need to rescan
* the list of clients blocked on lists and signal lists as ready
* the list of clients blocked on lists and signal lists as ready
* if needed.
* if needed. */
*
* Also the swapdb should make transaction fail if there is any
* client watching keys. */
scanDatabaseForReadyLists
(
activedb
);
scanDatabaseForReadyLists
(
activedb
);
touchAllWatchedKeysInDb
(
activedb
,
newdb
);
}
}
trackingInvalidateKeysOnFlush
(
1
);
trackingInvalidateKeysOnFlush
(
1
);
...
@@ -1692,7 +1692,7 @@ int64_t getAllKeySpecsFlags(struct redisCommand *cmd, int inv) {
...
@@ -1692,7 +1692,7 @@ int64_t getAllKeySpecsFlags(struct redisCommand *cmd, int inv) {
/* Fetch the keys based of the provided key specs. Returns the number of keys found, or -1 on error.
/* Fetch the keys based of the provided key specs. Returns the number of keys found, or -1 on error.
* There are several flags that can be used to modify how this function finds keys in a command.
* There are several flags that can be used to modify how this function finds keys in a command.
*
*
* GET_KEYSPEC_INCLUDE_
CHANNEL
S: Return
channel
s as if they were keys.
* GET_KEYSPEC_INCLUDE_
NOT_KEY
S: Return
'fake' key
s as if they were keys.
* GET_KEYSPEC_RETURN_PARTIAL: Skips invalid and incomplete keyspecs but returns the keys
* GET_KEYSPEC_RETURN_PARTIAL: Skips invalid and incomplete keyspecs but returns the keys
* found in other valid keyspecs.
* found in other valid keyspecs.
*/
*/
...
@@ -1703,8 +1703,8 @@ int getKeysUsingKeySpecs(struct redisCommand *cmd, robj **argv, int argc, int se
...
@@ -1703,8 +1703,8 @@ int getKeysUsingKeySpecs(struct redisCommand *cmd, robj **argv, int argc, int se
for
(
j
=
0
;
j
<
cmd
->
key_specs_num
;
j
++
)
{
for
(
j
=
0
;
j
<
cmd
->
key_specs_num
;
j
++
)
{
keySpec
*
spec
=
cmd
->
key_specs
+
j
;
keySpec
*
spec
=
cmd
->
key_specs
+
j
;
serverAssert
(
spec
->
begin_search_type
!=
KSPEC_BS_INVALID
);
serverAssert
(
spec
->
begin_search_type
!=
KSPEC_BS_INVALID
);
/* Skip specs that represent
channels instead of
keys */
/* Skip specs that represent
'fake'
keys */
if
((
spec
->
flags
&
CMD_KEY_
CHANNEL
)
&&
!
(
search_flags
&
GET_KEYSPEC_INCLUDE_
CHANNEL
S
))
{
if
((
spec
->
flags
&
CMD_KEY_
NOT_KEY
)
&&
!
(
search_flags
&
GET_KEYSPEC_INCLUDE_
NOT_KEY
S
))
{
continue
;
continue
;
}
}
...
@@ -1821,31 +1821,123 @@ invalid_spec:
...
@@ -1821,31 +1821,123 @@ invalid_spec:
* associated with how Redis will access the key.
* associated with how Redis will access the key.
*
*
* 'cmd' must be point to the corresponding entry into the redisCommand
* 'cmd' must be point to the corresponding entry into the redisCommand
* table, according to the command name in argv[0].
* table, according to the command name in argv[0]. */
*
* This function uses the command's key specs, which contain the key-spec flags,
* (e.g. RO / RW) and only resorts to the command-specific helper function if
* any of the keys-specs are marked as INCOMPLETE. */
int
getKeysFromCommandWithSpecs
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
search_flags
,
getKeysResult
*
result
)
{
int
getKeysFromCommandWithSpecs
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
search_flags
,
getKeysResult
*
result
)
{
if
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
)
{
/* The command has at least one key-spec not marked as NOT_KEY */
return
moduleGetCommandKeysViaAPI
(
cmd
,
argv
,
argc
,
result
);
int
has_keyspec
=
(
getAllKeySpecsFlags
(
cmd
,
1
)
&
CMD_KEY_NOT_KEY
);
}
else
{
/* The command has at least one key-spec marked as VARIABLE_FLAGS */
if
(
!
(
getAllKeySpecsFlags
(
cmd
,
0
)
&
CMD_KEY_VARIABLE_FLAGS
))
{
int
has_varflags
=
(
getAllKeySpecsFlags
(
cmd
,
0
)
&
CMD_KEY_VARIABLE_FLAGS
);
/* Flags indicating that we have a getkeys callback */
int
has_module_getkeys
=
cmd
->
flags
&
CMD_MODULE_GETKEYS
;
int
has_native_getkeys
=
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
;
/* The key-spec that's auto generated by RM_CreateCommand sets VARIABLE_FLAGS since no flags are given.
* If the module provides getkeys callback, we'll prefer it, but if it didn't, we'll use key-spec anyway. */
if
((
cmd
->
flags
&
CMD_MODULE
)
&&
has_varflags
&&
!
has_module_getkeys
)
has_varflags
=
0
;
/* We prefer key-specs if there are any, and their flags are reliable. */
if
(
has_keyspec
&&
!
has_varflags
)
{
int
ret
=
getKeysUsingKeySpecs
(
cmd
,
argv
,
argc
,
search_flags
,
result
);
int
ret
=
getKeysUsingKeySpecs
(
cmd
,
argv
,
argc
,
search_flags
,
result
);
if
(
ret
>=
0
)
if
(
ret
>=
0
)
return
ret
;
return
ret
;
/* If the specs returned with an error (probably an INVALID or INCOMPLETE spec),
* fallback to the callback method. */
}
}
if
(
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
)
/* Resort to getkeys callback methods. */
if
(
has_module_getkeys
)
return
moduleGetCommandKeysViaAPI
(
cmd
,
argv
,
argc
,
result
);
/* We use native getkeys as a last resort, since not all these native getkeys provide
* flags properly (only the ones that correspond to INVALID, INCOMPLETE or VARIABLE_FLAGS do.*/
if
(
has_native_getkeys
)
return
cmd
->
getkeys_proc
(
cmd
,
argv
,
argc
,
result
);
return
cmd
->
getkeys_proc
(
cmd
,
argv
,
argc
,
result
);
return
0
;
return
0
;
}
}
}
/* This function returns a sanity check if the command may have keys. */
/* This function returns a sanity check if the command may have keys. */
int
doesCommandHaveKeys
(
struct
redisCommand
*
cmd
)
{
int
doesCommandHaveKeys
(
struct
redisCommand
*
cmd
)
{
return
(
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
)
||
/* has getkeys_proc (non modules) */
return
(
!
(
cmd
->
flags
&
CMD_MODULE
)
&&
cmd
->
getkeys_proc
)
||
/* has getkeys_proc (non modules) */
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
)
||
/* module with GETKEYS */
(
cmd
->
flags
&
CMD_MODULE_GETKEYS
)
||
/* module with GETKEYS */
(
getAllKeySpecsFlags
(
cmd
,
1
)
&
CMD_KEY_CHANNEL
);
/* has at least one key-spec not marked as CHANNEL */
(
getAllKeySpecsFlags
(
cmd
,
1
)
&
CMD_KEY_NOT_KEY
);
/* has at least one key-spec not marked as NOT_KEY */
}
/* A simplified channel spec table that contains all of the redis commands
* and which channels they have and how they are accessed. */
typedef
struct
ChannelSpecs
{
redisCommandProc
*
proc
;
/* Command procedure to match against */
uint64_t
flags
;
/* CMD_CHANNEL_* flags for this command */
int
start
;
/* The initial position of the first channel */
int
count
;
/* The number of channels, or -1 if all remaining
* arguments are channels. */
}
ChannelSpecs
;
ChannelSpecs
commands_with_channels
[]
=
{
{
subscribeCommand
,
CMD_CHANNEL_SUBSCRIBE
,
1
,
-
1
},
{
ssubscribeCommand
,
CMD_CHANNEL_SUBSCRIBE
,
1
,
-
1
},
{
unsubscribeCommand
,
CMD_CHANNEL_UNSUBSCRIBE
,
1
,
-
1
},
{
sunsubscribeCommand
,
CMD_CHANNEL_UNSUBSCRIBE
,
1
,
-
1
},
{
psubscribeCommand
,
CMD_CHANNEL_PATTERN
|
CMD_CHANNEL_SUBSCRIBE
,
1
,
-
1
},
{
punsubscribeCommand
,
CMD_CHANNEL_PATTERN
|
CMD_CHANNEL_UNSUBSCRIBE
,
1
,
-
1
},
{
publishCommand
,
CMD_CHANNEL_PUBLISH
,
1
,
1
},
{
spublishCommand
,
CMD_CHANNEL_PUBLISH
,
1
,
1
},
{
NULL
,
0
}
/* Terminator. */
};
/* Returns 1 if the command may access any channels matched by the flags
* argument. */
int
doesCommandHaveChannelsWithFlags
(
struct
redisCommand
*
cmd
,
int
flags
)
{
/* If a module declares get channels, we are just going to assume
* has channels. This API is allowed to return false positives. */
if
(
cmd
->
flags
&
CMD_MODULE_GETCHANNELS
)
{
return
1
;
}
for
(
ChannelSpecs
*
spec
=
commands_with_channels
;
spec
->
proc
!=
NULL
;
spec
+=
1
)
{
if
(
cmd
->
proc
==
spec
->
proc
)
{
return
!!
(
spec
->
flags
&
flags
);
}
}
return
0
;
}
/* Return all the arguments that are channels in the command passed via argc / argv.
* This function behaves similar to getKeysFromCommandWithSpecs, but with channels
* instead of keys.
*
* The command returns the positions of all the channel arguments inside the array,
* so the actual return value is a heap allocated array of integers. The
* length of the array is returned by reference into *numkeys.
*
* Along with the position, this command also returns the flags that are
* associated with how Redis will access the channel.
*
* 'cmd' must be point to the corresponding entry into the redisCommand
* table, according to the command name in argv[0]. */
int
getChannelsFromCommand
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
getKeysResult
*
result
)
{
keyReference
*
keys
;
/* If a module declares get channels, use that. */
if
(
cmd
->
flags
&
CMD_MODULE_GETCHANNELS
)
{
return
moduleGetCommandChannelsViaAPI
(
cmd
,
argv
,
argc
,
result
);
}
/* Otherwise check the channel spec table */
for
(
ChannelSpecs
*
spec
=
commands_with_channels
;
spec
!=
NULL
;
spec
+=
1
)
{
if
(
cmd
->
proc
==
spec
->
proc
)
{
int
start
=
spec
->
start
;
int
stop
=
(
spec
->
count
==
-
1
)
?
argc
:
start
+
spec
->
count
;
if
(
stop
>
argc
)
stop
=
argc
;
int
count
=
0
;
keys
=
getKeysPrepareResult
(
result
,
stop
-
start
);
for
(
int
i
=
start
;
i
<
stop
;
i
++
)
{
keys
[
count
].
pos
=
i
;
keys
[
count
++
].
flags
=
spec
->
flags
;
}
result
->
numkeys
=
count
;
return
count
;
}
}
return
0
;
}
}
/* The base case is to use the keys position as given in the command table
/* The base case is to use the keys position as given in the command table
...
...
src/debug.c
View file @
a83e3663
...
@@ -482,6 +482,10 @@ void debugCommand(client *c) {
...
@@ -482,6 +482,10 @@ void debugCommand(client *c) {
" Show low level client eviction pools info (maxmemory-clients)."
,
" Show low level client eviction pools info (maxmemory-clients)."
,
"PAUSE-CRON <0|1>"
,
"PAUSE-CRON <0|1>"
,
" Stop periodic cron job processing."
,
" Stop periodic cron job processing."
,
"REPLYBUFFER-PEAK-RESET-TIME <NEVER||RESET|time>"
,
" Sets the time (in milliseconds) to wait between client reply buffer peak resets."
,
" In case NEVER is provided the last observed peak will never be reset"
,
" In case RESET is provided the peak reset time will be restored to the default value"
,
NULL
NULL
};
};
addReplyHelp
(
c
,
help
);
addReplyHelp
(
c
,
help
);
...
@@ -825,7 +829,7 @@ NULL
...
@@ -825,7 +829,7 @@ NULL
int
memerr
;
int
memerr
;
unsigned
long
long
sz
=
memtoull
((
const
char
*
)
c
->
argv
[
2
]
->
ptr
,
&
memerr
);
unsigned
long
long
sz
=
memtoull
((
const
char
*
)
c
->
argv
[
2
]
->
ptr
,
&
memerr
);
if
(
memerr
||
!
quicklistisSetPackedThreshold
(
sz
))
{
if
(
memerr
||
!
quicklistisSetPackedThreshold
(
sz
))
{
addReplyError
(
c
,
"argument must be a memory value bigger th
e
n 1 and smaller than 4gb"
);
addReplyError
(
c
,
"argument must be a memory value bigger th
a
n 1 and smaller than 4gb"
);
}
else
{
}
else
{
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
}
}
...
@@ -921,12 +925,12 @@ NULL
...
@@ -921,12 +925,12 @@ NULL
addReplyStatus
(
c
,
"Apparently Redis did not crash: test passed"
);
addReplyStatus
(
c
,
"Apparently Redis did not crash: test passed"
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"set-disable-deny-scripts"
)
&&
c
->
argc
==
3
)
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"set-disable-deny-scripts"
)
&&
c
->
argc
==
3
)
{
{
server
.
script_disable_deny_script
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
;
server
.
script_disable_deny_script
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"config-rewrite-force-all"
)
&&
c
->
argc
==
2
)
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"config-rewrite-force-all"
)
&&
c
->
argc
==
2
)
{
{
if
(
rewriteConfig
(
server
.
configfile
,
1
)
==
-
1
)
if
(
rewriteConfig
(
server
.
configfile
,
1
)
==
-
1
)
addReplyError
(
c
,
"CONFIG-REWRITE-FORCE-ALL failed
"
);
addReplyError
Format
(
c
,
"CONFIG-REWRITE-FORCE-ALL failed
: %s"
,
strerror
(
errno
)
);
else
else
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"client-eviction"
)
&&
c
->
argc
==
2
)
{
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"client-eviction"
)
&&
c
->
argc
==
2
)
{
...
@@ -958,6 +962,16 @@ NULL
...
@@ -958,6 +962,16 @@ NULL
{
{
server
.
pause_cron
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
server
.
pause_cron
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"replybuffer-peak-reset-time"
)
&&
c
->
argc
==
3
)
{
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"never"
))
{
server
.
reply_buffer_peak_reset_time
=
-
1
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"reset"
))
{
server
.
reply_buffer_peak_reset_time
=
REPLY_BUFFER_DEFAULT_PEAK_RESET_TIME
;
}
else
{
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
server
.
reply_buffer_peak_reset_time
,
NULL
)
!=
C_OK
)
return
;
}
addReply
(
c
,
shared
.
ok
);
}
else
{
}
else
{
addReplySubcommandSyntaxError
(
c
);
addReplySubcommandSyntaxError
(
c
);
return
;
return
;
...
@@ -1681,13 +1695,19 @@ void logStackTrace(void *eip, int uplevel) {
...
@@ -1681,13 +1695,19 @@ void logStackTrace(void *eip, int uplevel) {
void
logServerInfo
(
void
)
{
void
logServerInfo
(
void
)
{
sds
infostring
,
clients
;
sds
infostring
,
clients
;
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
"
\n
------ INFO OUTPUT ------
\n
"
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
"
\n
------ INFO OUTPUT ------
\n
"
);
infostring
=
genRedisInfoString
(
"all"
);
int
all
=
0
,
everything
=
0
;
robj
*
argv
[
1
];
argv
[
0
]
=
createStringObject
(
"all"
,
strlen
(
"all"
));
dict
*
section_dict
=
genInfoSectionDict
(
argv
,
1
,
NULL
,
&
all
,
&
everything
);
infostring
=
genRedisInfoString
(
section_dict
,
all
,
everything
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
infostring
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
infostring
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
"
\n
------ CLIENT LIST OUTPUT ------
\n
"
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
"
\n
------ CLIENT LIST OUTPUT ------
\n
"
);
clients
=
getAllClientsInfoString
(
-
1
);
clients
=
getAllClientsInfoString
(
-
1
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
clients
);
serverLogRaw
(
LL_WARNING
|
LL_RAW
,
clients
);
sdsfree
(
infostring
);
sdsfree
(
infostring
);
sdsfree
(
clients
);
sdsfree
(
clients
);
releaseInfoSectionDict
(
section_dict
);
decrRefCount
(
argv
[
0
]);
}
}
/* Log certain config values, which can be used for debuggin */
/* Log certain config values, which can be used for debuggin */
...
@@ -1723,10 +1743,10 @@ void logCurrentClient(void) {
...
@@ -1723,10 +1743,10 @@ void logCurrentClient(void) {
sdsfree
(
client
);
sdsfree
(
client
);
for
(
j
=
0
;
j
<
cc
->
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
cc
->
argc
;
j
++
)
{
robj
*
decoded
;
robj
*
decoded
;
decoded
=
getDecodedObject
(
cc
->
argv
[
j
]);
decoded
=
getDecodedObject
(
cc
->
argv
[
j
]);
serverLog
(
LL_WARNING
|
LL_RAW
,
"argv[%d]: '%s'
\n
"
,
j
,
sds
repr
=
sdscatrepr
(
sdsempty
(),
decoded
->
ptr
,
min
(
sdslen
(
decoded
->
ptr
),
128
));
(
char
*
)
decoded
->
ptr
);
serverLog
(
LL_WARNING
|
LL_RAW
,
"argv[%d]: '%s'
\n
"
,
j
,
(
char
*
)
repr
);
sdsfree
(
repr
);
decrRefCount
(
decoded
);
decrRefCount
(
decoded
);
}
}
/* Check if the first argument, usually a key, is found inside the
/* Check if the first argument, usually a key, is found inside the
...
@@ -1764,7 +1784,10 @@ int memtest_test_linux_anonymous_maps(void) {
...
@@ -1764,7 +1784,10 @@ int memtest_test_linux_anonymous_maps(void) {
if
(
!
fd
)
return
0
;
if
(
!
fd
)
return
0
;
fp
=
fopen
(
"/proc/self/maps"
,
"r"
);
fp
=
fopen
(
"/proc/self/maps"
,
"r"
);
if
(
!
fp
)
return
0
;
if
(
!
fp
)
{
closeDirectLogFiledes
(
fd
);
return
0
;
}
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
while
(
fgets
(
line
,
sizeof
(
line
),
fp
)
!=
NULL
)
{
char
*
start
,
*
end
,
*
p
=
line
;
char
*
start
,
*
end
,
*
p
=
line
;
...
...
src/debugmacro.h
View file @
a83e3663
...
@@ -30,6 +30,9 @@
...
@@ -30,6 +30,9 @@
* POSSIBILITY OF SUCH DAMAGE.
* POSSIBILITY OF SUCH DAMAGE.
*/
*/
#ifndef _REDIS_DEBUGMACRO_H_
#define _REDIS_DEBUGMACRO_H_
#include <stdio.h>
#include <stdio.h>
#define D(...) \
#define D(...) \
do { \
do { \
...
@@ -39,3 +42,5 @@
...
@@ -39,3 +42,5 @@
fprintf(fp,"\n"); \
fprintf(fp,"\n"); \
fclose(fp); \
fclose(fp); \
} while (0)
} while (0)
#endif
/* _REDIS_DEBUGMACRO_H_ */
src/defrag.c
View file @
a83e3663
...
@@ -128,6 +128,27 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
...
@@ -128,6 +128,27 @@ robj *activeDefragStringOb(robj* ob, long *defragged) {
return
ret
;
return
ret
;
}
}
/* Defrag helper for lua scripts
*
* returns NULL in case the allocation wasn't moved.
* when it returns a non-null value, the old pointer was already released
* and should NOT be accessed. */
luaScript
*
activeDefragLuaScript
(
luaScript
*
script
,
long
*
defragged
)
{
luaScript
*
ret
=
NULL
;
/* try to defrag script struct */
if
((
ret
=
activeDefragAlloc
(
script
)))
{
script
=
ret
;
(
*
defragged
)
++
;
}
/* try to defrag actual script object */
robj
*
ob
=
activeDefragStringOb
(
script
->
body
,
defragged
);
if
(
ob
)
script
->
body
=
ob
;
return
ret
;
}
/* Defrag helper for dictEntries to be used during dict iteration (called on
/* Defrag helper for dictEntries to be used during dict iteration (called on
* each step). Returns a stat of how many pointers were moved. */
* each step). Returns a stat of how many pointers were moved. */
long
dictIterDefragEntry
(
dictIterator
*
iter
)
{
long
dictIterDefragEntry
(
dictIterator
*
iter
)
{
...
@@ -256,6 +277,7 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
...
@@ -256,6 +277,7 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
#define DEFRAG_SDS_DICT_VAL_IS_SDS 1
#define DEFRAG_SDS_DICT_VAL_IS_SDS 1
#define DEFRAG_SDS_DICT_VAL_IS_STROB 2
#define DEFRAG_SDS_DICT_VAL_IS_STROB 2
#define DEFRAG_SDS_DICT_VAL_VOID_PTR 3
#define DEFRAG_SDS_DICT_VAL_VOID_PTR 3
#define DEFRAG_SDS_DICT_VAL_LUA_SCRIPT 4
/* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */
/* Defrag a dict with sds key and optional value (either ptr, sds or robj string) */
long
activeDefragSdsDict
(
dict
*
d
,
int
val_type
)
{
long
activeDefragSdsDict
(
dict
*
d
,
int
val_type
)
{
...
@@ -280,6 +302,10 @@ long activeDefragSdsDict(dict* d, int val_type) {
...
@@ -280,6 +302,10 @@ long activeDefragSdsDict(dict* d, int val_type) {
void
*
newptr
,
*
ptr
=
dictGetVal
(
de
);
void
*
newptr
,
*
ptr
=
dictGetVal
(
de
);
if
((
newptr
=
activeDefragAlloc
(
ptr
)))
if
((
newptr
=
activeDefragAlloc
(
ptr
)))
de
->
v
.
val
=
newptr
,
defragged
++
;
de
->
v
.
val
=
newptr
,
defragged
++
;
}
else
if
(
val_type
==
DEFRAG_SDS_DICT_VAL_LUA_SCRIPT
)
{
void
*
newptr
,
*
ptr
=
dictGetVal
(
de
);
if
((
newptr
=
activeDefragLuaScript
(
ptr
,
&
defragged
)))
de
->
v
.
val
=
newptr
;
}
}
defragged
+=
dictIterDefragEntry
(
di
);
defragged
+=
dictIterDefragEntry
(
di
);
}
}
...
@@ -939,7 +965,7 @@ long defragOtherGlobals() {
...
@@ -939,7 +965,7 @@ long defragOtherGlobals() {
/* there are many more pointers to defrag (e.g. client argv, output / aof buffers, etc.
/* there are many more pointers to defrag (e.g. client argv, output / aof buffers, etc.
* but we assume most of these are short lived, we only need to defrag allocations
* but we assume most of these are short lived, we only need to defrag allocations
* that remain static for a long time */
* that remain static for a long time */
defragged
+=
activeDefragSdsDict
(
evalScriptsDict
(),
DEFRAG_SDS_DICT_VAL_
IS_STROB
);
defragged
+=
activeDefragSdsDict
(
evalScriptsDict
(),
DEFRAG_SDS_DICT_VAL_
LUA_SCRIPT
);
defragged
+=
moduleDefragGlobals
();
defragged
+=
moduleDefragGlobals
();
return
defragged
;
return
defragged
;
}
}
...
@@ -1130,7 +1156,7 @@ void activeDefragCycle(void) {
...
@@ -1130,7 +1156,7 @@ void activeDefragCycle(void) {
/* Move on to next database, and stop if we reached the last one. */
/* Move on to next database, and stop if we reached the last one. */
if
(
++
current_db
>=
server
.
dbnum
)
{
if
(
++
current_db
>=
server
.
dbnum
)
{
/* defrag other items not part of the db / keys */
/* defrag other items not part of the db / keys */
defragOtherGlobals
();
server
.
stat_active_defrag_hits
+=
defragOtherGlobals
();
long
long
now
=
ustime
();
long
long
now
=
ustime
();
size_t
frag_bytes
;
size_t
frag_bytes
;
...
...
src/eval.c
View file @
a83e3663
...
@@ -47,11 +47,6 @@ void ldbEnable(client *c);
...
@@ -47,11 +47,6 @@ void ldbEnable(client *c);
void
evalGenericCommandWithDebugging
(
client
*
c
,
int
evalsha
);
void
evalGenericCommandWithDebugging
(
client
*
c
,
int
evalsha
);
sds
ldbCatStackValue
(
sds
s
,
lua_State
*
lua
,
int
idx
);
sds
ldbCatStackValue
(
sds
s
,
lua_State
*
lua
,
int
idx
);
typedef
struct
luaScript
{
uint64_t
flags
;
robj
*
body
;
}
luaScript
;
static
void
dictLuaScriptDestructor
(
dict
*
d
,
void
*
val
)
{
static
void
dictLuaScriptDestructor
(
dict
*
d
,
void
*
val
)
{
UNUSED
(
d
);
UNUSED
(
d
);
if
(
val
==
NULL
)
return
;
/* Lazy freeing will set value to NULL. */
if
(
val
==
NULL
)
return
;
/* Lazy freeing will set value to NULL. */
...
@@ -63,7 +58,7 @@ static uint64_t dictStrCaseHash(const void *key) {
...
@@ -63,7 +58,7 @@ static uint64_t dictStrCaseHash(const void *key) {
return
dictGenCaseHashFunction
((
unsigned
char
*
)
key
,
strlen
((
char
*
)
key
));
return
dictGenCaseHashFunction
((
unsigned
char
*
)
key
,
strlen
((
char
*
)
key
));
}
}
/* server.lua_scripts sha (as sds string) -> scripts (as
robj
) cache. */
/* server.lua_scripts sha (as sds string) -> scripts (as
luaScript
) cache. */
dictType
shaScriptObjectDictType
=
{
dictType
shaScriptObjectDictType
=
{
dictStrCaseHash
,
/* hash function */
dictStrCaseHash
,
/* hash function */
NULL
,
/* key dup */
NULL
,
/* key dup */
...
@@ -246,11 +241,14 @@ void scriptingInit(int setup) {
...
@@ -246,11 +241,14 @@ void scriptingInit(int setup) {
" if i and i.what == 'C' then
\n
"
" if i and i.what == 'C' then
\n
"
" i = dbg.getinfo(3,'nSl')
\n
"
" i = dbg.getinfo(3,'nSl')
\n
"
" end
\n
"
" end
\n
"
" if type(err) ~= 'table' then
\n
"
" err = {err='ERR' .. tostring(err)}"
" end"
" if i then
\n
"
" if i then
\n
"
" return i.source .. ':' .. i.currentline .. ': ' .. err
\n
"
" err['source'] = i.source
\n
"
" else
\n
"
" err['line'] = i.currentline
\n
"
" end"
" return err
\n
"
" return err
\n
"
" end
\n
"
"end
\n
"
;
"end
\n
"
;
luaL_loadbuffer
(
lua
,
errh_func
,
strlen
(
errh_func
),
"@err_handler_def"
);
luaL_loadbuffer
(
lua
,
errh_func
,
strlen
(
errh_func
),
"@err_handler_def"
);
lua_pcall
(
lua
,
0
,
0
,
0
);
lua_pcall
(
lua
,
0
,
0
,
0
);
...
@@ -392,7 +390,7 @@ sds luaCreateFunction(client *c, robj *body) {
...
@@ -392,7 +390,7 @@ sds luaCreateFunction(client *c, robj *body) {
if
(
luaL_loadbuffer
(
lctx
.
lua
,
funcdef
,
sdslen
(
funcdef
),
"@user_script"
))
{
if
(
luaL_loadbuffer
(
lctx
.
lua
,
funcdef
,
sdslen
(
funcdef
),
"@user_script"
))
{
if
(
c
!=
NULL
)
{
if
(
c
!=
NULL
)
{
addReplyErrorFormat
(
c
,
addReplyErrorFormat
(
c
,
"Error compiling script (new function): %s
\n
"
,
"Error compiling script (new function): %s"
,
lua_tostring
(
lctx
.
lua
,
-
1
));
lua_tostring
(
lctx
.
lua
,
-
1
));
}
}
lua_pop
(
lctx
.
lua
,
1
);
lua_pop
(
lctx
.
lua
,
1
);
...
@@ -403,7 +401,7 @@ sds luaCreateFunction(client *c, robj *body) {
...
@@ -403,7 +401,7 @@ sds luaCreateFunction(client *c, robj *body) {
if
(
lua_pcall
(
lctx
.
lua
,
0
,
0
,
0
))
{
if
(
lua_pcall
(
lctx
.
lua
,
0
,
0
,
0
))
{
if
(
c
!=
NULL
)
{
if
(
c
!=
NULL
)
{
addReplyErrorFormat
(
c
,
"Error running script (new function): %s
\n
"
,
addReplyErrorFormat
(
c
,
"Error running script (new function): %s"
,
lua_tostring
(
lctx
.
lua
,
-
1
));
lua_tostring
(
lctx
.
lua
,
-
1
));
}
}
lua_pop
(
lctx
.
lua
,
1
);
lua_pop
(
lctx
.
lua
,
1
);
...
@@ -1479,8 +1477,8 @@ int ldbRepl(lua_State *lua) {
...
@@ -1479,8 +1477,8 @@ int ldbRepl(lua_State *lua) {
while
((
argv
=
ldbReplParseCommand
(
&
argc
,
&
err
))
==
NULL
)
{
while
((
argv
=
ldbReplParseCommand
(
&
argc
,
&
err
))
==
NULL
)
{
char
buf
[
1024
];
char
buf
[
1024
];
if
(
err
)
{
if
(
err
)
{
lua
_p
ush
string
(
lua
,
err
);
lua
P
ush
Error
(
lua
,
err
);
lua
_e
rror
(
lua
);
lua
E
rror
(
lua
);
}
}
int
nread
=
connRead
(
ldb
.
conn
,
buf
,
sizeof
(
buf
));
int
nread
=
connRead
(
ldb
.
conn
,
buf
,
sizeof
(
buf
));
if
(
nread
<=
0
)
{
if
(
nread
<=
0
)
{
...
@@ -1497,8 +1495,8 @@ int ldbRepl(lua_State *lua) {
...
@@ -1497,8 +1495,8 @@ int ldbRepl(lua_State *lua) {
if
(
sdslen
(
ldb
.
cbuf
)
>
1
<<
20
)
{
if
(
sdslen
(
ldb
.
cbuf
)
>
1
<<
20
)
{
sdsfree
(
ldb
.
cbuf
);
sdsfree
(
ldb
.
cbuf
);
ldb
.
cbuf
=
sdsempty
();
ldb
.
cbuf
=
sdsempty
();
lua
_p
ush
string
(
lua
,
"max client buffer reached"
);
lua
P
ush
Error
(
lua
,
"max client buffer reached"
);
lua
_e
rror
(
lua
);
lua
E
rror
(
lua
);
}
}
}
}
...
@@ -1558,8 +1556,8 @@ ldbLog(sdsnew(" next line of code."));
...
@@ -1558,8 +1556,8 @@ ldbLog(sdsnew(" next line of code."));
ldbEval
(
lua
,
argv
,
argc
);
ldbEval
(
lua
,
argv
,
argc
);
ldbSendLogs
();
ldbSendLogs
();
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"a"
)
||
!
strcasecmp
(
argv
[
0
],
"abort"
))
{
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"a"
)
||
!
strcasecmp
(
argv
[
0
],
"abort"
))
{
lua
_p
ush
string
(
lua
,
"script aborted for user request"
);
lua
P
ush
Error
(
lua
,
"script aborted for user request"
);
lua
_e
rror
(
lua
);
lua
E
rror
(
lua
);
}
else
if
(
argc
>
1
&&
}
else
if
(
argc
>
1
&&
(
!
strcasecmp
(
argv
[
0
],
"r"
)
||
!
strcasecmp
(
argv
[
0
],
"redis"
)))
{
(
!
strcasecmp
(
argv
[
0
],
"r"
)
||
!
strcasecmp
(
argv
[
0
],
"redis"
)))
{
ldbRedis
(
lua
,
argv
,
argc
);
ldbRedis
(
lua
,
argv
,
argc
);
...
@@ -1640,8 +1638,8 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
...
@@ -1640,8 +1638,8 @@ void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
/* If the client closed the connection and we have a timeout
/* If the client closed the connection and we have a timeout
* connection, let's kill the script otherwise the process
* connection, let's kill the script otherwise the process
* will remain blocked indefinitely. */
* will remain blocked indefinitely. */
lua
_p
ush
string
(
lua
,
"timeout during Lua debugging with client closing connection"
);
lua
P
ush
Error
(
lua
,
"timeout during Lua debugging with client closing connection"
);
lua
_e
rror
(
lua
);
lua
E
rror
(
lua
);
}
}
rctx
->
start_time
=
getMonotonicUs
();
rctx
->
start_time
=
getMonotonicUs
();
rctx
->
snapshot_time
=
mstime
();
rctx
->
snapshot_time
=
mstime
();
...
...
src/function_lua.c
View file @
a83e3663
...
@@ -86,8 +86,8 @@ static void luaEngineLoadHook(lua_State *lua, lua_Debug *ar) {
...
@@ -86,8 +86,8 @@ static void luaEngineLoadHook(lua_State *lua, lua_Debug *ar) {
if
(
duration
>
LOAD_TIMEOUT_MS
)
{
if
(
duration
>
LOAD_TIMEOUT_MS
)
{
lua_sethook
(
lua
,
luaEngineLoadHook
,
LUA_MASKLINE
,
0
);
lua_sethook
(
lua
,
luaEngineLoadHook
,
LUA_MASKLINE
,
0
);
lua
_p
ush
string
(
lua
,
"FUNCTION LOAD timeout"
);
lua
P
ush
Error
(
lua
,
"FUNCTION LOAD timeout"
);
lua
_e
rror
(
lua
);
lua
E
rror
(
lua
);
}
}
}
}
...
@@ -151,10 +151,13 @@ static int luaEngineCreate(void *engine_ctx, functionLibInfo *li, sds blob, sds
...
@@ -151,10 +151,13 @@ static int luaEngineCreate(void *engine_ctx, functionLibInfo *li, sds blob, sds
lua_sethook
(
lua
,
luaEngineLoadHook
,
LUA_MASKCOUNT
,
100000
);
lua_sethook
(
lua
,
luaEngineLoadHook
,
LUA_MASKCOUNT
,
100000
);
/* Run the compiled code to allow it to register functions */
/* Run the compiled code to allow it to register functions */
if
(
lua_pcall
(
lua
,
0
,
0
,
0
))
{
if
(
lua_pcall
(
lua
,
0
,
0
,
0
))
{
*
err
=
sdscatprintf
(
sdsempty
(),
"Error registering functions: %s"
,
lua_tostring
(
lua
,
-
1
));
errorInfo
err_info
=
{
0
};
luaExtractErrorInformation
(
lua
,
&
err_info
);
*
err
=
sdscatprintf
(
sdsempty
(),
"Error registering functions: %s"
,
err_info
.
msg
);
lua_pop
(
lua
,
2
);
/* pops the error and globals table */
lua_pop
(
lua
,
2
);
/* pops the error and globals table */
lua_sethook
(
lua
,
NULL
,
0
,
0
);
/* Disable hook */
lua_sethook
(
lua
,
NULL
,
0
,
0
);
/* Disable hook */
luaSaveOnRegistry
(
lua
,
REGISTRY_LOAD_CTX_NAME
,
NULL
);
luaSaveOnRegistry
(
lua
,
REGISTRY_LOAD_CTX_NAME
,
NULL
);
luaErrorInformationDiscard
(
&
err_info
);
return
C_ERR
;
return
C_ERR
;
}
}
lua_sethook
(
lua
,
NULL
,
0
,
0
);
/* Disable hook */
lua_sethook
(
lua
,
NULL
,
0
,
0
);
/* Disable hook */
...
@@ -429,11 +432,11 @@ static int luaRegisterFunction(lua_State *lua) {
...
@@ -429,11 +432,11 @@ static int luaRegisterFunction(lua_State *lua) {
loadCtx
*
load_ctx
=
luaGetFromRegistry
(
lua
,
REGISTRY_LOAD_CTX_NAME
);
loadCtx
*
load_ctx
=
luaGetFromRegistry
(
lua
,
REGISTRY_LOAD_CTX_NAME
);
if
(
!
load_ctx
)
{
if
(
!
load_ctx
)
{
luaPushError
(
lua
,
"redis.register_function can only be called on FUNCTION LOAD command"
);
luaPushError
(
lua
,
"redis.register_function can only be called on FUNCTION LOAD command"
);
return
lua
Raise
Error
(
lua
);
return
luaError
(
lua
);
}
}
if
(
luaRegisterFunctionReadArgs
(
lua
,
&
register_f_args
)
!=
C_OK
)
{
if
(
luaRegisterFunctionReadArgs
(
lua
,
&
register_f_args
)
!=
C_OK
)
{
return
lua
Raise
Error
(
lua
);
return
luaError
(
lua
);
}
}
sds
err
=
NULL
;
sds
err
=
NULL
;
...
@@ -441,7 +444,7 @@ static int luaRegisterFunction(lua_State *lua) {
...
@@ -441,7 +444,7 @@ static int luaRegisterFunction(lua_State *lua) {
luaRegisterFunctionArgsDispose
(
lua
,
&
register_f_args
);
luaRegisterFunctionArgsDispose
(
lua
,
&
register_f_args
);
luaPushError
(
lua
,
err
);
luaPushError
(
lua
,
err
);
sdsfree
(
err
);
sdsfree
(
err
);
return
lua
Raise
Error
(
lua
);
return
luaError
(
lua
);
}
}
return
0
;
return
0
;
...
@@ -475,11 +478,14 @@ int luaEngineInitEngine() {
...
@@ -475,11 +478,14 @@ int luaEngineInitEngine() {
" if i and i.what == 'C' then
\n
"
" if i and i.what == 'C' then
\n
"
" i = dbg.getinfo(3,'nSl')
\n
"
" i = dbg.getinfo(3,'nSl')
\n
"
" end
\n
"
" end
\n
"
" if type(err) ~= 'table' then
\n
"
" err = {err='ERR' .. tostring(err)}"
" end"
" if i then
\n
"
" if i then
\n
"
" return i.source .. ':' .. i.currentline .. ': ' .. err
\n
"
" err['source'] = i.source
\n
"
" else
\n
"
" err['line'] = i.currentline
\n
"
" end"
" return err
\n
"
" return err
\n
"
" end
\n
"
"end
\n
"
"end
\n
"
"return error_handler"
;
"return error_handler"
;
luaL_loadbuffer
(
lua_engine_ctx
->
lua
,
errh_func
,
strlen
(
errh_func
),
"@err_handler_def"
);
luaL_loadbuffer
(
lua_engine_ctx
->
lua
,
errh_func
,
strlen
(
errh_func
),
"@err_handler_def"
);
...
...
src/functions.c
View file @
a83e3663
...
@@ -808,7 +808,7 @@ void functionFlushCommand(client *c) {
...
@@ -808,7 +808,7 @@ void functionFlushCommand(client *c) {
void
functionHelpCommand
(
client
*
c
)
{
void
functionHelpCommand
(
client
*
c
)
{
const
char
*
help
[]
=
{
const
char
*
help
[]
=
{
"LOAD <ENGINE NAME> <LIBRARY NAME> [REPLACE] [DESC <LIBRARY DESCRIPTION>] <LIBRARY CODE>"
,
"LOAD <ENGINE NAME> <LIBRARY NAME> [REPLACE] [DESC
RIPTION
<LIBRARY DESCRIPTION>] <LIBRARY CODE>"
,
" Create a new library with the given library name and code."
,
" Create a new library with the given library name and code."
,
"DELETE <LIBRARY NAME>"
,
"DELETE <LIBRARY NAME>"
,
" Delete the given library."
,
" Delete the given library."
,
...
...
src/geohash.h
View file @
a83e3663
...
@@ -34,7 +34,6 @@
...
@@ -34,7 +34,6 @@
#include <stddef.h>
#include <stddef.h>
#include <stdint.h>
#include <stdint.h>
#include <stdint.h>
#if defined(__cplusplus)
#if defined(__cplusplus)
extern
"C"
{
extern
"C"
{
...
...
src/geohash_helper.c
View file @
a83e3663
...
@@ -92,7 +92,7 @@ uint8_t geohashEstimateStepsByRadius(double range_meters, double lat) {
...
@@ -92,7 +92,7 @@ uint8_t geohashEstimateStepsByRadius(double range_meters, double lat) {
* \ / / \ \ /
* \ / / \ \ /
* \ (long,lat) / / (long,lat) \ \ (long,lat) /
* \ (long,lat) / / (long,lat) \ \ (long,lat) /
* \ / / \ / \
* \ / / \ / \
* --------- /----------------\
/--------------\
* --------- /----------------\ /
-
--------------\
* Northern Hemisphere Southern Hemisphere Around the equator
* Northern Hemisphere Southern Hemisphere Around the equator
*/
*/
int
geohashBoundingBox
(
GeoShape
*
shape
,
double
*
bounds
)
{
int
geohashBoundingBox
(
GeoShape
*
shape
,
double
*
bounds
)
{
...
@@ -164,14 +164,14 @@ GeoHashRadius geohashCalculateAreasByShapeWGS84(GeoShape *shape) {
...
@@ -164,14 +164,14 @@ GeoHashRadius geohashCalculateAreasByShapeWGS84(GeoShape *shape) {
geohashDecode
(
long_range
,
lat_range
,
neighbors
.
east
,
&
east
);
geohashDecode
(
long_range
,
lat_range
,
neighbors
.
east
,
&
east
);
geohashDecode
(
long_range
,
lat_range
,
neighbors
.
west
,
&
west
);
geohashDecode
(
long_range
,
lat_range
,
neighbors
.
west
,
&
west
);
if
(
geohashGetDistance
(
longitude
,
latitude
,
longitude
,
north
.
latitude
.
max
)
if
(
north
.
latitude
.
max
<
max_lat
)
<
radius_meters
)
decrease_step
=
1
;
decrease_step
=
1
;
if
(
geohashGetDistance
(
longitude
,
latitude
,
longitude
,
south
.
latitude
.
min
)
if
(
south
.
latitude
.
min
>
min_lat
)
<
radius_meters
)
decrease_step
=
1
;
decrease_step
=
1
;
if
(
geohashGetDistance
(
longitude
,
latitude
,
east
.
longitude
.
max
,
latitude
)
if
(
east
.
longitude
.
max
<
max_lon
)
<
radius_meters
)
decrease_step
=
1
;
decrease_step
=
1
;
if
(
geohashGetDistance
(
longitude
,
latitude
,
west
.
longitude
.
min
,
latitude
)
if
(
west
.
longitude
.
min
>
min_lon
)
<
radius_meters
)
decrease_step
=
1
;
decrease_step
=
1
;
}
}
if
(
steps
>
1
&&
decrease_step
)
{
if
(
steps
>
1
&&
decrease_step
)
{
...
...
src/help.h
View file @
a83e3663
/* Automatically generated by
./
utils/generate-command-help.rb, do not edit. */
/* Automatically generated by utils/generate-command-help.rb, do not edit. */
#ifndef __REDIS_HELP_H
#ifndef __REDIS_HELP_H
#define __REDIS_HELP_H
#define __REDIS_HELP_H
...
@@ -429,6 +429,11 @@ struct commandHelp {
...
@@ -429,6 +429,11 @@ struct commandHelp {
"Extract keys given a full Redis command"
,
"Extract keys given a full Redis command"
,
9
,
9
,
"2.8.13"
},
"2.8.13"
},
{
"COMMAND GETKEYSANDFLAGS"
,
""
,
"Extract keys given a full Redis command"
,
9
,
"7.0.0"
},
{
"COMMAND HELP"
,
{
"COMMAND HELP"
,
""
,
""
,
"Show helpful text about the different subcommands"
,
"Show helpful text about the different subcommands"
,
...
@@ -571,12 +576,12 @@ struct commandHelp {
...
@@ -571,12 +576,12 @@ struct commandHelp {
"6.2.0"
},
"6.2.0"
},
{
"FCALL"
,
{
"FCALL"
,
"function numkeys key [key ...] arg [arg ...]"
,
"function numkeys key [key ...] arg [arg ...]"
,
"
PATCH__TBD__38__
"
,
"
Invoke a function
"
,
10
,
10
,
"7.0.0"
},
"7.0.0"
},
{
"FCALL_RO"
,
{
"FCALL_RO"
,
"function numkeys key [key ...] arg [arg ...]"
,
"function numkeys key [key ...] arg [arg ...]"
,
"
PATCH__TBD__7__
"
,
"
Invoke a read-only function
"
,
10
,
10
,
"7.0.0"
},
"7.0.0"
},
{
"FLUSHALL"
,
{
"FLUSHALL"
,
...
@@ -595,7 +600,7 @@ struct commandHelp {
...
@@ -595,7 +600,7 @@ struct commandHelp {
10
,
10
,
"7.0.0"
},
"7.0.0"
},
{
"FUNCTION DELETE"
,
{
"FUNCTION DELETE"
,
"
function
-name"
,
"
library
-name"
,
"Delete a function by name"
,
"Delete a function by name"
,
10
,
10
,
"7.0.0"
},
"7.0.0"
},
...
@@ -625,7 +630,7 @@ struct commandHelp {
...
@@ -625,7 +630,7 @@ struct commandHelp {
10
,
10
,
"7.0.0"
},
"7.0.0"
},
{
"FUNCTION LOAD"
,
{
"FUNCTION LOAD"
,
"engine-name library-name [REPLACE] [DESC library-description] function-code"
,
"engine-name library-name [REPLACE] [DESC
RIPTION
library-description] function-code"
,
"Create a function with the given arguments (name, code, description)"
,
"Create a function with the given arguments (name, code, description)"
,
10
,
10
,
"7.0.0"
},
"7.0.0"
},
...
@@ -820,7 +825,7 @@ struct commandHelp {
...
@@ -820,7 +825,7 @@ struct commandHelp {
1
,
1
,
"2.6.0"
},
"2.6.0"
},
{
"INFO"
,
{
"INFO"
,
"[section]"
,
"[section
[section ...]
]"
,
"Get information and statistics about the server"
,
"Get information and statistics about the server"
,
9
,
9
,
"1.0.0"
},
"1.0.0"
},
...
@@ -1180,7 +1185,7 @@ struct commandHelp {
...
@@ -1180,7 +1185,7 @@ struct commandHelp {
6
,
6
,
"7.0.0"
},
"7.0.0"
},
{
"PUBSUB SHARDNUMSUB"
,
{
"PUBSUB SHARDNUMSUB"
,
""
,
"
[channel [channel ...]]
"
,
"Get the count of subscribers for shard channels"
,
"Get the count of subscribers for shard channels"
,
6
,
6
,
"7.0.0"
},
"7.0.0"
},
...
@@ -1391,7 +1396,7 @@ struct commandHelp {
...
@@ -1391,7 +1396,7 @@ struct commandHelp {
"1.0.0"
},
"1.0.0"
},
{
"SLAVEOF"
,
{
"SLAVEOF"
,
"host port"
,
"host port"
,
"Make the server a replica of another instance, or promote it as master.
Deprecated starting with Redis 5. Use REPLICAOF instead.
"
,
"Make the server a replica of another instance, or promote it as master."
,
9
,
9
,
"1.0.0"
},
"1.0.0"
},
{
"SLOWLOG"
,
{
"SLOWLOG"
,
...
@@ -1590,7 +1595,7 @@ struct commandHelp {
...
@@ -1590,7 +1595,7 @@ struct commandHelp {
14
,
14
,
"5.0.0"
},
"5.0.0"
},
{
"XGROUP CREATE"
,
{
"XGROUP CREATE"
,
"key groupname id|$ [MKSTREAM]"
,
"key groupname id|$ [MKSTREAM]
[ENTRIESREAD entries_read]
"
,
"Create a consumer group."
,
"Create a consumer group."
,
14
,
14
,
"5.0.0"
},
"5.0.0"
},
...
@@ -1615,7 +1620,7 @@ struct commandHelp {
...
@@ -1615,7 +1620,7 @@ struct commandHelp {
14
,
14
,
"5.0.0"
},
"5.0.0"
},
{
"XGROUP SETID"
,
{
"XGROUP SETID"
,
"key groupname id|$"
,
"key groupname id|$
[ENTRIESREAD entries_read]
"
,
"Set a consumer group to an arbitrary last delivered ID value."
,
"Set a consumer group to an arbitrary last delivered ID value."
,
14
,
14
,
"5.0.0"
},
"5.0.0"
},
...
@@ -1675,7 +1680,7 @@ struct commandHelp {
...
@@ -1675,7 +1680,7 @@ struct commandHelp {
14
,
14
,
"5.0.0"
},
"5.0.0"
},
{
"XSETID"
,
{
"XSETID"
,
"key last-id"
,
"key last-id
[ENTRIESADDED entries_added] [MAXDELETEDID max_deleted_entry_id]
"
,
"An internal command for replicating stream values"
,
"An internal command for replicating stream values"
,
14
,
14
,
"5.0.0"
},
"5.0.0"
},
...
...
src/module.c
View file @
a83e3663
This diff is collapsed.
Click to expand it.
src/modules/Makefile
View file @
a83e3663
...
@@ -11,6 +11,13 @@ else
...
@@ -11,6 +11,13 @@ else
SHOBJ_LDFLAGS
?=
-bundle
-undefined
dynamic_lookup
SHOBJ_LDFLAGS
?=
-bundle
-undefined
dynamic_lookup
endif
endif
# OS X 11.x doesn't have /usr/lib/libSystem.dylib and needs an explicit setting.
ifeq
($(uname_S),Darwin)
ifeq
("$(wildcard /usr/lib/libSystem.dylib)","")
LIBS
=
-L
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
-lsystem
endif
endif
.SUFFIXES
:
.c .so .xo .o
.SUFFIXES
:
.c .so .xo .o
all
:
helloworld.so hellotype.so helloblock.so hellocluster.so hellotimer.so hellodict.so hellohook.so helloacl.so
all
:
helloworld.so hellotype.so helloblock.so hellocluster.so hellotimer.so hellodict.so hellohook.so helloacl.so
...
...
src/modules/hellocluster.c
View file @
a83e3663
...
@@ -76,7 +76,7 @@ int ListCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
...
@@ -76,7 +76,7 @@ int ListCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int
void
PingReceiver
(
RedisModuleCtx
*
ctx
,
const
char
*
sender_id
,
uint8_t
type
,
const
unsigned
char
*
payload
,
uint32_t
len
)
{
void
PingReceiver
(
RedisModuleCtx
*
ctx
,
const
char
*
sender_id
,
uint8_t
type
,
const
unsigned
char
*
payload
,
uint32_t
len
)
{
RedisModule_Log
(
ctx
,
"notice"
,
"PING (type %d) RECEIVED from %.*s: '%.*s'"
,
RedisModule_Log
(
ctx
,
"notice"
,
"PING (type %d) RECEIVED from %.*s: '%.*s'"
,
type
,
REDISMODULE_NODE_ID_LEN
,
sender_id
,(
int
)
len
,
payload
);
type
,
REDISMODULE_NODE_ID_LEN
,
sender_id
,(
int
)
len
,
payload
);
RedisModule_SendClusterMessage
(
ctx
,
NULL
,
MSGTYPE_PONG
,
(
unsigned
char
*
)
"Ohi!"
,
4
);
RedisModule_SendClusterMessage
(
ctx
,
NULL
,
MSGTYPE_PONG
,
"Ohi!"
,
4
);
RedisModuleCallReply
*
reply
=
RedisModule_Call
(
ctx
,
"INCR"
,
"c"
,
"pings_received"
);
RedisModuleCallReply
*
reply
=
RedisModule_Call
(
ctx
,
"INCR"
,
"c"
,
"pings_received"
);
RedisModule_FreeCallReply
(
reply
);
RedisModule_FreeCallReply
(
reply
);
}
}
...
...
src/multi.c
View file @
a83e3663
This diff is collapsed.
Click to expand it.
src/networking.c
View file @
a83e3663
This diff is collapsed.
Click to expand it.
src/rdb.c
View file @
a83e3663
This diff is collapsed.
Click to expand it.
src/rdb.h
View file @
a83e3663
...
@@ -94,10 +94,11 @@
...
@@ -94,10 +94,11 @@
#define RDB_TYPE_HASH_LISTPACK 16
#define RDB_TYPE_HASH_LISTPACK 16
#define RDB_TYPE_ZSET_LISTPACK 17
#define RDB_TYPE_ZSET_LISTPACK 17
#define RDB_TYPE_LIST_QUICKLIST_2 18
#define RDB_TYPE_LIST_QUICKLIST_2 18
#define RDB_TYPE_STREAM_LISTPACKS_2 19
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* NOTE: WHEN ADDING NEW RDB TYPE, UPDATE rdbIsObjectType() BELOW */
/* Test if a type is an object type. */
/* Test if a type is an object type. */
#define rdbIsObjectType(t) ((t >= 0 && t <= 7) || (t >= 9 && t <= 1
8
))
#define rdbIsObjectType(t) ((t >= 0 && t <= 7) || (t >= 9 && t <= 1
9
))
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
#define RDB_OPCODE_FUNCTION 246
/* engine data */
#define RDB_OPCODE_FUNCTION 246
/* engine data */
...
...
Prev
1
2
3
4
5
6
7
8
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment