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
9e67df2a
Commit
9e67df2a
authored
Jul 21, 2015
by
Oran Agra
Browse files
rebase from unstable
parents
f472bb10
bcb4d091
Changes
60
Expand all
Show whitespace changes
Inline
Side-by-side
src/config.c
View file @
9e67df2a
This diff is collapsed.
Click to expand it.
src/db.c
View file @
9e67df2a
...
...
@@ -318,13 +318,17 @@ void delCommand(redisClient *c) {
addReplyLongLong
(
c
,
deleted
);
}
/* EXISTS key1 key2 ... key_N.
* Return value is the number of keys existing. */
void
existsCommand
(
redisClient
*
c
)
{
expireIfNeeded
(
c
->
db
,
c
->
argv
[
1
]);
if
(
dbExists
(
c
->
db
,
c
->
argv
[
1
]))
{
addReply
(
c
,
shared
.
cone
);
}
else
{
addReply
(
c
,
shared
.
czero
);
long
long
count
=
0
;
int
j
;
for
(
j
=
1
;
j
<
c
->
argc
;
j
++
)
{
expireIfNeeded
(
c
->
db
,
c
->
argv
[
j
]);
if
(
dbExists
(
c
->
db
,
c
->
argv
[
j
]))
count
++
;
}
addReplyLongLong
(
c
,
count
);
}
void
selectCommand
(
redisClient
*
c
)
{
...
...
src/debug.c
View file @
9e67df2a
...
...
@@ -425,6 +425,27 @@ void debugCommand(redisClient *c) {
sizes
=
sdscatprintf
(
sizes
,
"dictentry:%d "
,
(
int
)
sizeof
(
dictEntry
));
sizes
=
sdscatprintf
(
sizes
,
"sdshdr:%d"
,
(
int
)
sizeof
(
struct
sdshdr
));
addReplyBulkSds
(
c
,
sizes
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"htstats"
)
&&
c
->
argc
==
3
)
{
long
dbid
;
sds
stats
=
sdsempty
();
char
buf
[
4096
];
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
dbid
,
NULL
)
!=
REDIS_OK
)
return
;
if
(
dbid
<
0
||
dbid
>=
server
.
dbnum
)
{
addReplyError
(
c
,
"Out of range database"
);
return
;
}
stats
=
sdscatprintf
(
stats
,
"[Dictionary HT]
\n
"
);
dictGetStats
(
buf
,
sizeof
(
buf
),
server
.
db
[
dbid
].
dict
);
stats
=
sdscat
(
stats
,
buf
);
stats
=
sdscatprintf
(
stats
,
"[Expires HT]
\n
"
);
dictGetStats
(
buf
,
sizeof
(
buf
),
server
.
db
[
dbid
].
expires
);
stats
=
sdscat
(
stats
,
buf
);
addReplyBulkSds
(
c
,
stats
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"jemalloc"
)
&&
c
->
argc
==
3
)
{
#if defined(USE_JEMALLOC)
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"info"
))
{
...
...
src/dict.c
View file @
9e67df2a
...
...
@@ -687,10 +687,10 @@ dictEntry *dictGetRandomKey(dict *d)
* statistics. However the function is much faster than dictGetRandomKey()
* at producing N elements. */
unsigned
int
dictGetSomeKeys
(
dict
*
d
,
dictEntry
**
des
,
unsigned
int
count
)
{
unsigned
int
j
;
/* internal hash table id, 0 or 1. */
unsigned
int
tables
;
/* 1 or 2 tables? */
unsigned
int
stored
=
0
,
maxsizemask
;
unsigned
int
maxsteps
;
unsigned
long
j
;
/* internal hash table id, 0 or 1. */
unsigned
long
tables
;
/* 1 or 2 tables? */
unsigned
long
stored
=
0
,
maxsizemask
;
unsigned
long
maxsteps
;
if
(
dictSize
(
d
)
<
count
)
count
=
dictSize
(
d
);
maxsteps
=
count
*
10
;
...
...
@@ -709,14 +709,14 @@ unsigned int dictGetSomeKeys(dict *d, dictEntry **des, unsigned int count) {
maxsizemask
=
d
->
ht
[
1
].
sizemask
;
/* Pick a random point inside the larger table. */
unsigned
int
i
=
random
()
&
maxsizemask
;
unsigned
int
emptylen
=
0
;
/* Continuous empty entries so far. */
unsigned
long
i
=
random
()
&
maxsizemask
;
unsigned
long
emptylen
=
0
;
/* Continuous empty entries so far. */
while
(
stored
<
count
&&
maxsteps
--
)
{
for
(
j
=
0
;
j
<
tables
;
j
++
)
{
/* Invariant of the dict.c rehashing: up to the indexes already
* visited in ht[0] during the rehashing, there are no populated
* buckets, so we can skip ht[0] for indexes between 0 and idx-1. */
if
(
tables
==
2
&&
j
==
0
&&
i
<
d
->
rehashidx
)
{
if
(
tables
==
2
&&
j
==
0
&&
i
<
(
unsigned
long
)
d
->
rehashidx
)
{
/* Moreover, if we are currently out of range in the second
* table, there will be no elements in both tables up to
* the current rehashing index, so we jump if possible.
...
...
@@ -1002,24 +1002,21 @@ void dictDisableResize(void) {
dict_can_resize
=
0
;
}
#if 0
/* The following is code that we don't use for Redis currently, but that is part
of the library. */
/* ----------------------- Debugging ------------------------*/
/* ------------------------------- Debugging ---------------------------------*/
#define DICT_STATS_VECTLEN 50
s
tatic void
_dict
Prin
tStatsHt(
dictht *ht
) {
s
ize_t
_dict
Ge
tStatsHt
(
char
*
buf
,
size_t
bufsize
,
dictht
*
ht
,
int
tableid
)
{
unsigned
long
i
,
slots
=
0
,
chainlen
,
maxchainlen
=
0
;
unsigned
long
totchainlen
=
0
;
unsigned
long
clvector
[
DICT_STATS_VECTLEN
];
size_t
l
=
0
;
if
(
ht
->
used
==
0
)
{
printf("No stats available for empty dictionaries\n");
return
;
return
snprintf
(
buf
,
bufsize
,
"No stats available for empty dictionaries
\n
"
)
;
}
/* Compute stats. */
for
(
i
=
0
;
i
<
DICT_STATS_VECTLEN
;
i
++
)
clvector
[
i
]
=
0
;
for
(
i
=
0
;
i
<
ht
->
size
;
i
++
)
{
dictEntry
*
he
;
...
...
@@ -1040,89 +1037,46 @@ static void _dictPrintStatsHt(dictht *ht) {
if
(
chainlen
>
maxchainlen
)
maxchainlen
=
chainlen
;
totchainlen
+=
chainlen
;
}
printf("Hash table stats:\n");
printf(" table size: %ld\n", ht->size);
printf(" number of elements: %ld\n", ht->used);
printf(" different slots: %ld\n", slots);
printf(" max chain length: %ld\n", maxchainlen);
printf(" avg chain length (counted): %.02f\n", (float)totchainlen/slots);
printf(" avg chain length (computed): %.02f\n", (float)ht->used/slots);
printf(" Chain length distribution:\n");
/* Generate human readable stats. */
l
+=
snprintf
(
buf
+
l
,
bufsize
-
l
,
"Hash table %d stats (%s):
\n
"
" table size: %ld
\n
"
" number of elements: %ld
\n
"
" different slots: %ld
\n
"
" max chain length: %ld
\n
"
" avg chain length (counted): %.02f
\n
"
" avg chain length (computed): %.02f
\n
"
" Chain length distribution:
\n
"
,
tableid
,
(
tableid
==
0
)
?
"main hash table"
:
"rehashing target"
,
ht
->
size
,
ht
->
used
,
slots
,
maxchainlen
,
(
float
)
totchainlen
/
slots
,
(
float
)
ht
->
used
/
slots
);
for
(
i
=
0
;
i
<
DICT_STATS_VECTLEN
-
1
;
i
++
)
{
if
(
clvector
[
i
]
==
0
)
continue
;
printf(" %s%ld: %ld (%.02f%%)\n",(i == DICT_STATS_VECTLEN-1)?">= ":"", i, clvector[i], ((float)clvector[i]/ht->size)*100);
if
(
l
>=
bufsize
)
break
;
l
+=
snprintf
(
buf
+
l
,
bufsize
-
l
,
" %s%ld: %ld (%.02f%%)
\n
"
,
(
i
==
DICT_STATS_VECTLEN
-
1
)
?
">= "
:
""
,
i
,
clvector
[
i
],
((
float
)
clvector
[
i
]
/
ht
->
size
)
*
100
);
}
}
void dictPrintStats(dict *d) {
_dictPrintStatsHt(&d->ht[0]);
if (dictIsRehashing(d)) {
printf("-- Rehashing into ht[1]:\n");
_dictPrintStatsHt(&d->ht[1]);
}
}
/* ----------------------- StringCopy Hash Table Type ------------------------*/
static unsigned int _dictStringCopyHTHashFunction(const void *key)
{
return dictGenHashFunction(key, strlen(key));
}
static void *_dictStringDup(void *privdata, const void *key)
{
int len = strlen(key);
char *copy = zmalloc(len+1);
DICT_NOTUSED(privdata);
memcpy(copy, key, len);
copy[len
] = '\0';
return
copy
;
/* Unlike snprintf(), teturn the number of characters actually written. */
if
(
bufsize
)
buf
[
bufsize
-
1
]
=
'\0'
;
return
strlen
(
buf
)
;
}
static int _dictStringCopyHTKeyCompare(void *privdata, const void *key1,
const void *key2)
{
DICT_NOTUSED(privdata)
;
void
dictGetStats
(
char
*
buf
,
size_t
bufsize
,
dict
*
d
)
{
size_t
l
;
char
*
orig_buf
=
buf
;
size_t
orig_bufsize
=
bufsize
;
return strcmp(key1, key2) == 0
;
}
static void _dictStringDestructor(void *privdata, void *key)
{
DICT_NOTUSED(privdata);
zfree(key)
;
l
=
_dictGetStatsHt
(
buf
,
bufsize
,
&
d
->
ht
[
0
],
0
)
;
buf
+=
l
;
bufsize
-=
l
;
if
(
dictIsRehashing
(
d
)
&&
bufsize
>
0
)
{
_dictGetStatsHt
(
buf
,
bufsize
,
&
d
->
ht
[
1
],
1
);
}
/* Make sure there is a NULL term at the end. */
if
(
orig_bufsize
)
orig_buf
[
orig_bufsize
-
1
]
=
'\0'
;
}
dictType dictTypeHeapStringCopyKey = {
_dictStringCopyHTHashFunction, /* hash function */
_dictStringDup, /* key dup */
NULL, /* val dup */
_dictStringCopyHTKeyCompare, /* key compare */
_dictStringDestructor, /* key destructor */
NULL /* val destructor */
};
/* This is like StringCopy but does not auto-duplicate the key.
* It's used for intepreter's shared strings. */
dictType dictTypeHeapStrings = {
_dictStringCopyHTHashFunction, /* hash function */
NULL, /* key dup */
NULL, /* val dup */
_dictStringCopyHTKeyCompare, /* key compare */
_dictStringDestructor, /* key destructor */
NULL /* val destructor */
};
/* This is like StringCopy but also automatically handle dynamic
* allocated C strings as values. */
dictType dictTypeHeapStringCopyKeyValue = {
_dictStringCopyHTHashFunction, /* hash function */
_dictStringDup, /* key dup */
_dictStringDup, /* val dup */
_dictStringCopyHTKeyCompare, /* key compare */
_dictStringDestructor, /* key destructor */
_dictStringDestructor, /* val destructor */
};
#endif
src/dict.h
View file @
9e67df2a
...
...
@@ -165,7 +165,7 @@ dictEntry *dictNext(dictIterator *iter);
void
dictReleaseIterator
(
dictIterator
*
iter
);
dictEntry
*
dictGetRandomKey
(
dict
*
d
);
unsigned
int
dictGetSomeKeys
(
dict
*
d
,
dictEntry
**
des
,
unsigned
int
count
);
void
dict
Prin
tStats
(
dict
*
d
);
void
dict
Ge
tStats
(
char
*
buf
,
size_t
bufsize
,
dict
*
d
);
unsigned
int
dictGenHashFunction
(
const
void
*
key
,
int
len
);
unsigned
int
dictGenCaseHashFunction
(
const
unsigned
char
*
buf
,
int
len
);
void
dictEmpty
(
dict
*
d
,
void
(
callback
)(
void
*
));
...
...
src/geo.c
0 → 100644
View file @
9e67df2a
This diff is collapsed.
Click to expand it.
src/geo.h
0 → 100644
View file @
9e67df2a
#ifndef __GEO_H__
#define __GEO_H__
#include "redis.h"
/* Structures used inside geo.c in order to represent points and array of
* points on the earth. */
typedef
struct
geoPoint
{
double
longitude
;
double
latitude
;
double
dist
;
double
score
;
char
*
member
;
}
geoPoint
;
typedef
struct
geoArray
{
struct
geoPoint
*
array
;
size_t
buckets
;
size_t
used
;
}
geoArray
;
#endif
src/latency.c
View file @
9e67df2a
...
...
@@ -248,7 +248,7 @@ sds createLatencyReport(void) {
dictEntry
*
de
;
int
eventnum
=
0
;
di
=
dictGetIterator
(
server
.
latency_events
);
di
=
dictGet
Safe
Iterator
(
server
.
latency_events
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
char
*
event
=
dictGetKey
(
de
);
struct
latencyTimeSeries
*
ts
=
dictGetVal
(
de
);
...
...
src/networking.c
View file @
9e67df2a
...
...
@@ -135,23 +135,49 @@ redisClient *createClient(int fd) {
* returns REDIS_OK, and make sure to install the write handler in our event
* loop so that when the socket is writable new data gets written.
*
* If the client should not receive new data, because it is a fake client,
* a master, a slave not yet online, or because the setup of the write handler
* failed, the function returns REDIS_ERR.
* If the client should not receive new data, because it is a fake client
* (used to load AOF in memory), a master or because the setup of the write
* handler failed, the function returns REDIS_ERR.
*
* The function may return REDIS_OK without actually installing the write
* event handler in the following cases:
*
* 1) The event handler should already be installed since the output buffer
* already contained something.
* 2) The client is a slave but not yet online, so we want to just accumulate
* writes in the buffer but not actually sending them yet.
*
* Typically gets called every time a reply is built, before adding more
* data to the clients output buffers. If the function returns REDIS_ERR no
* data should be appended to the output buffers. */
int
prepareClientToWrite
(
redisClient
*
c
)
{
/* If it's the Lua client we always return ok without installing any
* handler since there is no socket at all. */
if
(
c
->
flags
&
REDIS_LUA_CLIENT
)
return
REDIS_OK
;
/* Masters don't receive replies, unless REDIS_MASTER_FORCE_REPLY flag
* is set. */
if
((
c
->
flags
&
REDIS_MASTER
)
&&
!
(
c
->
flags
&
REDIS_MASTER_FORCE_REPLY
))
return
REDIS_ERR
;
if
(
c
->
fd
<=
0
)
return
REDIS_ERR
;
/* Fake client */
if
(
c
->
fd
<=
0
)
return
REDIS_ERR
;
/* Fake client for AOF loading. */
/* Only install the handler if not already installed and, in case of
* slaves, if the client can actually receive writes. */
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
(
c
->
replstate
==
REDIS_REPL_NONE
||
c
->
replstate
==
REDIS_REPL_ONLINE
)
&&
!
c
->
repl_put_online_on_ack
&&
aeCreateFileEvent
(
server
.
el
,
c
->
fd
,
AE_WRITABLE
,
sendReplyToClient
,
c
)
==
AE_ERR
)
return
REDIS_ERR
;
(
c
->
replstate
==
REDIS_REPL_ONLINE
&&
!
c
->
repl_put_online_on_ack
)))
{
/* Try to install the write handler. */
if
(
aeCreateFileEvent
(
server
.
el
,
c
->
fd
,
AE_WRITABLE
,
sendReplyToClient
,
c
)
==
AE_ERR
)
{
freeClientAsync
(
c
);
return
REDIS_ERR
;
}
}
/* Authorize the caller to queue in the output buffer of this client. */
return
REDIS_OK
;
}
...
...
@@ -175,7 +201,7 @@ robj *dupLastObjectIfNeeded(list *reply) {
* Low level functions to add more data to output buffers.
* -------------------------------------------------------------------------- */
int
_addReplyToBuffer
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
int
_addReplyToBuffer
(
redisClient
*
c
,
const
char
*
s
,
size_t
len
)
{
size_t
available
=
sizeof
(
c
->
buf
)
-
c
->
bufpos
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
REDIS_OK
;
...
...
@@ -255,7 +281,7 @@ void _addReplySdsToList(redisClient *c, sds s) {
asyncCloseClientOnOutputBufferLimitReached
(
c
);
}
void
_addReplyStringToList
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
_addReplyStringToList
(
redisClient
*
c
,
const
char
*
s
,
size_t
len
)
{
robj
*
tail
;
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
;
...
...
@@ -341,19 +367,19 @@ void addReplySds(redisClient *c, sds s) {
}
}
void
addReplyString
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
addReplyString
(
redisClient
*
c
,
const
char
*
s
,
size_t
len
)
{
if
(
prepareClientToWrite
(
c
)
!=
REDIS_OK
)
return
;
if
(
_addReplyToBuffer
(
c
,
s
,
len
)
!=
REDIS_OK
)
_addReplyStringToList
(
c
,
s
,
len
);
}
void
addReplyErrorLength
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
addReplyErrorLength
(
redisClient
*
c
,
const
char
*
s
,
size_t
len
)
{
addReplyString
(
c
,
"-ERR "
,
5
);
addReplyString
(
c
,
s
,
len
);
addReplyString
(
c
,
"
\r\n
"
,
2
);
}
void
addReplyError
(
redisClient
*
c
,
char
*
err
)
{
void
addReplyError
(
redisClient
*
c
,
const
char
*
err
)
{
addReplyErrorLength
(
c
,
err
,
strlen
(
err
));
}
...
...
@@ -373,13 +399,13 @@ void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
sdsfree
(
s
);
}
void
addReplyStatusLength
(
redisClient
*
c
,
char
*
s
,
size_t
len
)
{
void
addReplyStatusLength
(
redisClient
*
c
,
const
char
*
s
,
size_t
len
)
{
addReplyString
(
c
,
"+"
,
1
);
addReplyString
(
c
,
s
,
len
);
addReplyString
(
c
,
"
\r\n
"
,
2
);
}
void
addReplyStatus
(
redisClient
*
c
,
char
*
status
)
{
void
addReplyStatus
(
redisClient
*
c
,
const
char
*
status
)
{
addReplyStatusLength
(
c
,
status
,
strlen
(
status
));
}
...
...
@@ -454,10 +480,10 @@ void addReplyLongLongWithPrefix(redisClient *c, long long ll, char prefix) {
/* Things like $3\r\n or *2\r\n are emitted very often by the protocol
* so we have a few shared objects to use if the integer is small
* like it is most of the times. */
if
(
prefix
==
'*'
&&
ll
<
REDIS_SHARED_BULKHDR_LEN
)
{
if
(
prefix
==
'*'
&&
ll
<
REDIS_SHARED_BULKHDR_LEN
&&
ll
>=
0
)
{
addReply
(
c
,
shared
.
mbulkhdr
[
ll
]);
return
;
}
else
if
(
prefix
==
'$'
&&
ll
<
REDIS_SHARED_BULKHDR_LEN
)
{
}
else
if
(
prefix
==
'$'
&&
ll
<
REDIS_SHARED_BULKHDR_LEN
&&
ll
>=
0
)
{
addReply
(
c
,
shared
.
bulkhdr
[
ll
]);
return
;
}
...
...
@@ -519,7 +545,7 @@ void addReplyBulk(redisClient *c, robj *obj) {
}
/* Add a C buffer as bulk reply */
void
addReplyBulkCBuffer
(
redisClient
*
c
,
void
*
p
,
size_t
len
)
{
void
addReplyBulkCBuffer
(
redisClient
*
c
,
const
void
*
p
,
size_t
len
)
{
addReplyLongLongWithPrefix
(
c
,
len
,
'$'
);
addReplyString
(
c
,
p
,
len
);
addReply
(
c
,
shared
.
crlf
);
...
...
@@ -534,7 +560,7 @@ void addReplyBulkSds(redisClient *c, sds s) {
}
/* Add a C nul term string as bulk reply */
void
addReplyBulkCString
(
redisClient
*
c
,
char
*
s
)
{
void
addReplyBulkCString
(
redisClient
*
c
,
const
char
*
s
)
{
if
(
s
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
}
else
{
...
...
@@ -779,7 +805,7 @@ void freeClient(redisClient *c) {
* a context where calling freeClient() is not possible, because the client
* should be valid for the continuation of the flow of the program. */
void
freeClientAsync
(
redisClient
*
c
)
{
if
(
c
->
flags
&
REDIS_CLOSE_ASAP
)
return
;
if
(
c
->
flags
&
REDIS_CLOSE_ASAP
||
c
->
flags
&
REDIS_LUA_CLIENT
)
return
;
c
->
flags
|=
REDIS_CLOSE_ASAP
;
listAddNodeTail
(
server
.
clients_to_close
,
c
);
}
...
...
@@ -957,7 +983,7 @@ int processInlineBuffer(redisClient *c) {
/* Helper function. Trims query buffer to make the function that processes
* multi bulk requests idempotent. */
static
void
setProtocolError
(
redisClient
*
c
,
int
pos
)
{
if
(
server
.
verbosity
>
=
REDIS_VERBOSE
)
{
if
(
server
.
verbosity
<
=
REDIS_VERBOSE
)
{
sds
client
=
catClientInfoString
(
sdsempty
(),
c
);
redisLog
(
REDIS_VERBOSE
,
"Protocol error from client: %s"
,
client
);
...
...
@@ -1501,6 +1527,16 @@ void rewriteClientCommandVector(redisClient *c, int argc, ...) {
va_end
(
ap
);
}
/* Completely replace the client command vector with the provided one. */
void
replaceClientCommandVector
(
redisClient
*
c
,
int
argc
,
robj
**
argv
)
{
freeClientArgv
(
c
);
zfree
(
c
->
argv
);
c
->
argv
=
argv
;
c
->
argc
=
argc
;
c
->
cmd
=
lookupCommandOrOriginal
(
c
->
argv
[
0
]
->
ptr
);
redisAssertWithInfo
(
c
,
NULL
,
c
->
cmd
!=
NULL
);
}
/* Rewrite a single item in the command vector.
* The new val ref count is incremented, and the old decremented. */
void
rewriteClientCommandArgument
(
redisClient
*
c
,
int
i
,
robj
*
newval
)
{
...
...
@@ -1676,7 +1712,9 @@ void pauseClients(mstime_t end) {
/* Return non-zero if clients are currently paused. As a side effect the
* function checks if the pause time was reached and clear it. */
int
clientsArePaused
(
void
)
{
if
(
server
.
clients_paused
&&
server
.
clients_pause_end_time
<
server
.
mstime
)
{
if
(
server
.
clients_paused
&&
server
.
clients_pause_end_time
<
server
.
mstime
)
{
listNode
*
ln
;
listIter
li
;
redisClient
*
c
;
...
...
@@ -1689,7 +1727,10 @@ int clientsArePaused(void) {
while
((
ln
=
listNext
(
&
li
))
!=
NULL
)
{
c
=
listNodeValue
(
ln
);
if
(
c
->
flags
&
REDIS_SLAVE
)
continue
;
/* Don't touch slaves and blocked clients. The latter pending
* requests be processed when unblocked. */
if
(
c
->
flags
&
(
REDIS_SLAVE
|
REDIS_BLOCKED
))
continue
;
c
->
flags
|=
REDIS_UNBLOCKED
;
listAddNodeTail
(
server
.
unblocked_clients
,
c
);
}
}
...
...
src/object.c
View file @
9e67df2a
...
...
@@ -50,14 +50,14 @@ robj *createObject(int type, void *ptr) {
/* Create a string object with encoding REDIS_ENCODING_RAW, that is a plain
* string object where o->ptr points to a proper sds string. */
robj
*
createRawStringObject
(
char
*
ptr
,
size_t
len
)
{
robj
*
createRawStringObject
(
const
char
*
ptr
,
size_t
len
)
{
return
createObject
(
REDIS_STRING
,
sdsnewlen
(
ptr
,
len
));
}
/* Create a string object with encoding REDIS_ENCODING_EMBSTR, that is
* an object where the sds string is actually an unmodifiable string
* allocated in the same chunk as the object itself. */
robj
*
createEmbeddedStringObject
(
char
*
ptr
,
size_t
len
)
{
robj
*
createEmbeddedStringObject
(
const
char
*
ptr
,
size_t
len
)
{
robj
*
o
=
zmalloc
(
sizeof
(
robj
)
+
sizeof
(
struct
sdshdr
)
+
len
+
1
);
struct
sdshdr
*
sh
=
(
void
*
)(
o
+
1
);
...
...
@@ -85,7 +85,7 @@ robj *createEmbeddedStringObject(char *ptr, size_t len) {
* The current limit of 39 is chosen so that the biggest string object
* we allocate as EMBSTR will still fit into the 64 byte arena of jemalloc. */
#define REDIS_ENCODING_EMBSTR_SIZE_LIMIT 39
robj
*
createStringObject
(
char
*
ptr
,
size_t
len
)
{
robj
*
createStringObject
(
const
char
*
ptr
,
size_t
len
)
{
if
(
len
<=
REDIS_ENCODING_EMBSTR_SIZE_LIMIT
)
return
createEmbeddedStringObject
(
ptr
,
len
);
else
...
...
src/rdb.c
View file @
9e67df2a
...
...
@@ -869,9 +869,9 @@ int rdbSave(char *filename) {
return
REDIS_OK
;
werr:
redisLog
(
REDIS_WARNING
,
"Write error saving DB on disk: %s"
,
strerror
(
errno
));
fclose
(
fp
);
unlink
(
tmpfile
);
redisLog
(
REDIS_WARNING
,
"Write error saving DB on disk: %s"
,
strerror
(
errno
));
return
REDIS_ERR
;
}
...
...
src/redis-cli.c
View file @
9e67df2a
...
...
@@ -644,9 +644,9 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
output_raw
=
0
;
if
(
!
strcasecmp
(
command
,
"info"
)
||
(
argc
=
=
3
&&
!
strcasecmp
(
command
,
"debug"
)
&&
(
!
strcasecmp
(
argv
[
1
],
"jemalloc"
)
&&
!
strcasecmp
(
argv
[
2
],
"
info
"
)))
||
(
argc
>
=
2
&&
!
strcasecmp
(
command
,
"debug"
)
&&
(
!
strcasecmp
(
argv
[
1
],
"jemalloc"
)
||
!
strcasecmp
(
argv
[
1
],
"
htstats
"
)))
||
(
argc
==
2
&&
!
strcasecmp
(
command
,
"cluster"
)
&&
(
!
strcasecmp
(
argv
[
1
],
"nodes"
)
||
!
strcasecmp
(
argv
[
1
],
"info"
)))
||
...
...
src/redis.c
View file @
9e67df2a
...
...
@@ -53,7 +53,7 @@
#include <sys/resource.h>
#include <sys/utsname.h>
#include <locale.h>
#include <sys/s
ysctl
.h>
#include <sys/s
ocket
.h>
/* Our shared "common" objects */
...
...
@@ -131,7 +131,7 @@ struct redisCommand redisCommandTable[] = {
{
"append"
,
appendCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"strlen"
,
strlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
"w"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"exists"
,
existsCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"exists"
,
existsCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"setbit"
,
setbitCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"getbit"
,
getbitCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"setrange"
,
setrangeCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
...
...
@@ -281,9 +281,15 @@ struct redisCommand redisCommandTable[] = {
{
"bitpos"
,
bitposCommand
,
-
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"wait"
,
waitCommand
,
3
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"command"
,
commandCommand
,
0
,
"rlt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geoadd"
,
geoaddCommand
,
-
5
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"georadius"
,
georadiusCommand
,
-
6
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"georadiusbymember"
,
georadiusByMemberCommand
,
-
5
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"geohash"
,
geohashCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"geopos"
,
geoposCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"geodist"
,
geodistCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfselftest"
,
pfselftestCommand
,
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pfadd"
,
pfaddCommand
,
-
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"pfmerge"
,
pfmergeCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"pfdebug"
,
pfdebugCommand
,
-
3
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"latency"
,
latencyCommand
,
-
2
,
"arslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
...
...
@@ -905,9 +911,12 @@ long long getInstantaneousMetric(int metric) {
return
sum
/
REDIS_METRIC_SAMPLES
;
}
/* Check for timeouts. Returns non-zero if the client was terminated */
int
clientsCronHandleTimeout
(
redisClient
*
c
)
{
time_t
now
=
server
.
unixtime
;
/* Check for timeouts. Returns non-zero if the client was terminated.
* The function gets the current time in milliseconds as argument since
* it gets called multiple times in a loop, so calling gettimeofday() for
* each iteration would be costly without any actual gain. */
int
clientsCronHandleTimeout
(
redisClient
*
c
,
mstime_t
now_ms
)
{
time_t
now
=
now_ms
/
1000
;
if
(
server
.
maxidletime
&&
!
(
c
->
flags
&
REDIS_SLAVE
)
&&
/* no timeout for slaves */
...
...
@@ -923,11 +932,16 @@ int clientsCronHandleTimeout(redisClient *c) {
/* Blocked OPS timeout is handled with milliseconds resolution.
* However note that the actual resolution is limited by
* server.hz. */
mstime_t
now_ms
=
mstime
();
if
(
c
->
bpop
.
timeout
!=
0
&&
c
->
bpop
.
timeout
<
now_ms
)
{
/* Handle blocking operation specific timeout. */
replyToBlockedClientTimedOut
(
c
);
unblockClient
(
c
);
}
else
if
(
server
.
cluster_enabled
)
{
/* Cluster: handle unblock & redirect of clients blocked
* into keys no longer served by this server. */
if
(
clusterRedirectBlockedClientIfNeeded
(
c
))
unblockClient
(
c
);
}
}
return
0
;
...
...
@@ -959,17 +973,23 @@ int clientsCronResizeQueryBuffer(redisClient *c) {
return
0
;
}
#define CLIENTS_CRON_MIN_ITERATIONS 5
void
clientsCron
(
void
)
{
/* Make sure to process at least 1/(server.hz*10) of clients per call.
* Since this function is called server.hz times per second we are sure that
* in the worst case we process all the clients in 10 seconds.
* In normal conditions (a reasonable number of clients) we process
* all the clients in a shorter time. */
/* Make sure to process at least numclients/server.hz of clients
* per call. Since this function is called server.hz times per second
* we are sure that in the worst case we process all the clients in 1
* second. */
int
numclients
=
listLength
(
server
.
clients
);
int
iterations
=
numclients
/
(
server
.
hz
*
10
);
int
iterations
=
numclients
/
server
.
hz
;
mstime_t
now
=
mstime
();
/* Process at least a few clients while we are at it, even if we need
* to process less than CLIENTS_CRON_MIN_ITERATIONS to meet our contract
* of processing each client once per second. */
if
(
iterations
<
CLIENTS_CRON_MIN_ITERATIONS
)
iterations
=
(
numclients
<
CLIENTS_CRON_MIN_ITERATIONS
)
?
numclients
:
CLIENTS_CRON_MIN_ITERATIONS
;
if
(
iterations
<
50
)
iterations
=
(
numclients
<
50
)
?
numclients
:
50
;
while
(
listLength
(
server
.
clients
)
&&
iterations
--
)
{
redisClient
*
c
;
listNode
*
head
;
...
...
@@ -983,7 +1003,7 @@ void clientsCron(void) {
/* The following functions do different service checks on the client.
* The protocol is that they return non-zero if the client was
* terminated. */
if
(
clientsCronHandleTimeout
(
c
))
continue
;
if
(
clientsCronHandleTimeout
(
c
,
now
))
continue
;
if
(
clientsCronResizeQueryBuffer
(
c
))
continue
;
}
}
...
...
@@ -1260,6 +1280,12 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
void
beforeSleep
(
struct
aeEventLoop
*
eventLoop
)
{
REDIS_NOTUSED
(
eventLoop
);
/* Call the Redis Cluster before sleep function. Note that this function
* may change the state of Redis Cluster (from ok to fail or vice versa),
* so it's a good idea to call it before serving the unblocked clients
* later in this function. */
if
(
server
.
cluster_enabled
)
clusterBeforeSleep
();
/* Run a fast expire cycle (the called function will return
* ASAP if a fast cycle is not needed). */
if
(
server
.
active_expire_enabled
&&
server
.
masterhost
==
NULL
)
...
...
@@ -1291,9 +1317,6 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
/* Write the AOF buffer on disk */
flushAppendOnlyFile
(
0
);
/* Call the Redis Cluster before sleep function. */
if
(
server
.
cluster_enabled
)
clusterBeforeSleep
();
}
/* =========================== Server initialization ======================== */
...
...
@@ -1740,6 +1763,7 @@ void resetServerStats(void) {
}
server
.
stat_net_input_bytes
=
0
;
server
.
stat_net_output_bytes
=
0
;
server
.
aof_delayed_fsync
=
0
;
}
void
initServer
(
void
)
{
...
...
@@ -1784,7 +1808,7 @@ void initServer(void) {
server
.
sofd
=
anetUnixServer
(
server
.
neterr
,
server
.
unixsocket
,
server
.
unixsocketperm
,
server
.
tcp_backlog
);
if
(
server
.
sofd
==
ANET_ERR
)
{
redisLog
(
REDIS_WARNING
,
"Opening socket: %s"
,
server
.
neterr
);
redisLog
(
REDIS_WARNING
,
"Opening
Unix
socket: %s"
,
server
.
neterr
);
exit
(
1
);
}
anetNonBlock
(
NULL
,
server
.
sofd
);
...
...
@@ -2199,36 +2223,22 @@ int processCommand(redisClient *c) {
* 2) The command has no key arguments. */
if
(
server
.
cluster_enabled
&&
!
(
c
->
flags
&
REDIS_MASTER
)
&&
!
(
c
->
flags
&
REDIS_LUA_CLIENT
&&
server
.
lua_caller
->
flags
&
REDIS_MASTER
)
&&
!
(
c
->
cmd
->
getkeys_proc
==
NULL
&&
c
->
cmd
->
firstkey
==
0
))
{
int
hashslot
;
if
(
server
.
cluster
->
state
!=
REDIS_CLUSTER_OK
)
{
flagTransaction
(
c
);
addReplySds
(
c
,
sdsnew
(
"-CLUSTERDOWN The cluster is down. Use CLUSTER INFO for more information
\r\n
"
)
);
clusterRedirectClient
(
c
,
NULL
,
0
,
REDIS_CLUSTER_REDIR_DOWN_STATE
);
return
REDIS_OK
;
}
else
{
int
error_code
;
clusterNode
*
n
=
getNodeByQuery
(
c
,
c
->
cmd
,
c
->
argv
,
c
->
argc
,
&
hashslot
,
&
error_code
);
if
(
n
==
NULL
)
{
flagTransaction
(
c
);
if
(
error_code
==
REDIS_CLUSTER_REDIR_CROSS_SLOT
)
{
addReplySds
(
c
,
sdsnew
(
"-CROSSSLOT Keys in request don't hash to the same slot
\r\n
"
));
}
else
if
(
error_code
==
REDIS_CLUSTER_REDIR_UNSTABLE
)
{
/* The request spawns mutliple keys in the same slot,
* but the slot is not "stable" currently as there is
* a migration or import in progress. */
addReplySds
(
c
,
sdsnew
(
"-TRYAGAIN Multiple keys request during rehashing of slot
\r\n
"
));
}
else
{
redisPanic
(
"getNodeByQuery() unknown error."
);
}
return
REDIS_OK
;
}
else
if
(
n
!=
server
.
cluster
->
myself
)
{
if
(
n
==
NULL
||
n
!=
server
.
cluster
->
myself
)
{
flagTransaction
(
c
);
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
"-%s %d %s:%d
\r\n
"
,
(
error_code
==
REDIS_CLUSTER_REDIR_ASK
)
?
"ASK"
:
"MOVED"
,
hashslot
,
n
->
ip
,
n
->
port
));
clusterRedirectClient
(
c
,
n
,
hashslot
,
error_code
);
return
REDIS_OK
;
}
}
...
...
@@ -2745,7 +2755,7 @@ sds genRedisInfoString(char *section) {
char
maxmemory_hmem
[
64
];
size_t
zmalloc_used
=
zmalloc_used_memory
();
size_t
total_system_mem
=
server
.
system_memory_size
;
char
*
evict_policy
=
maxmemoryToString
();
const
char
*
evict_policy
=
maxmemoryToString
();
long
long
memory_lua
=
(
long
long
)
lua_gc
(
server
.
lua
,
LUA_GCCOUNT
,
0
)
*
1024
;
/* Peak memory is updated from time to time by serverCron() so it
...
...
src/redis.h
View file @
9e67df2a
...
...
@@ -1053,14 +1053,14 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask);
void
acceptUnixHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
readQueryFromClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
addReplyBulk
(
redisClient
*
c
,
robj
*
obj
);
void
addReplyBulkCString
(
redisClient
*
c
,
char
*
s
);
void
addReplyBulkCBuffer
(
redisClient
*
c
,
void
*
p
,
size_t
len
);
void
addReplyBulkCString
(
redisClient
*
c
,
const
char
*
s
);
void
addReplyBulkCBuffer
(
redisClient
*
c
,
const
void
*
p
,
size_t
len
);
void
addReplyBulkLongLong
(
redisClient
*
c
,
long
long
ll
);
void
addReply
(
redisClient
*
c
,
robj
*
obj
);
void
addReplySds
(
redisClient
*
c
,
sds
s
);
void
addReplyBulkSds
(
redisClient
*
c
,
sds
s
);
void
addReplyError
(
redisClient
*
c
,
char
*
err
);
void
addReplyStatus
(
redisClient
*
c
,
char
*
status
);
void
addReplyError
(
redisClient
*
c
,
const
char
*
err
);
void
addReplyStatus
(
redisClient
*
c
,
const
char
*
status
);
void
addReplyDouble
(
redisClient
*
c
,
double
d
);
void
addReplyLongLong
(
redisClient
*
c
,
long
long
ll
);
void
addReplyMultiBulkLen
(
redisClient
*
c
,
long
length
);
...
...
@@ -1074,6 +1074,7 @@ sds catClientInfoString(sds s, redisClient *client);
sds
getAllClientsInfoString
(
void
);
void
rewriteClientCommandVector
(
redisClient
*
c
,
int
argc
,
...);
void
rewriteClientCommandArgument
(
redisClient
*
c
,
int
i
,
robj
*
newval
);
void
replaceClientCommandVector
(
redisClient
*
c
,
int
argc
,
robj
**
argv
);
unsigned
long
getClientOutputBufferMemoryUsage
(
redisClient
*
c
);
void
freeClientsInAsyncFreeQueue
(
void
);
void
asyncCloseClientOnOutputBufferLimitReached
(
redisClient
*
c
);
...
...
@@ -1136,9 +1137,9 @@ void freeSetObject(robj *o);
void
freeZsetObject
(
robj
*
o
);
void
freeHashObject
(
robj
*
o
);
robj
*
createObject
(
int
type
,
void
*
ptr
);
robj
*
createStringObject
(
char
*
ptr
,
size_t
len
);
robj
*
createRawStringObject
(
char
*
ptr
,
size_t
len
);
robj
*
createEmbeddedStringObject
(
char
*
ptr
,
size_t
len
);
robj
*
createStringObject
(
const
char
*
ptr
,
size_t
len
);
robj
*
createRawStringObject
(
const
char
*
ptr
,
size_t
len
);
robj
*
createEmbeddedStringObject
(
const
char
*
ptr
,
size_t
len
);
robj
*
dupStringObject
(
robj
*
o
);
int
isObjectRepresentableAsLongLong
(
robj
*
o
,
long
long
*
llongval
);
robj
*
tryObjectEncoding
(
robj
*
o
);
...
...
@@ -1241,6 +1242,7 @@ void zzlNext(unsigned char *zl, unsigned char **eptr, unsigned char **sptr);
void
zzlPrev
(
unsigned
char
*
zl
,
unsigned
char
**
eptr
,
unsigned
char
**
sptr
);
unsigned
int
zsetLength
(
robj
*
zobj
);
void
zsetConvert
(
robj
*
zobj
,
int
encoding
);
int
zsetScore
(
robj
*
zobj
,
robj
*
member
,
double
*
score
);
unsigned
long
zslGetRank
(
zskiplist
*
zsl
,
double
score
,
robj
*
o
);
/* Core functions */
...
...
@@ -1275,7 +1277,7 @@ void closeListeningSockets(int unlink_unix_socket);
void
updateCachedTime
(
void
);
void
resetServerStats
(
void
);
unsigned
int
getLRUClock
(
void
);
char
*
maxmemoryToString
(
void
);
const
char
*
maxmemoryToString
(
void
);
/* Set data type */
robj
*
setTypeCreate
(
robj
*
value
);
...
...
@@ -1328,7 +1330,7 @@ void loadServerConfig(char *filename, char *options);
void
appendServerSaveParams
(
time_t
seconds
,
int
changes
);
void
resetServerSaveParams
(
void
);
struct
rewriteConfigState
;
/* Forward declaration to export API. */
void
rewriteConfigRewriteLine
(
struct
rewriteConfigState
*
state
,
char
*
option
,
sds
line
,
int
force
);
void
rewriteConfigRewriteLine
(
struct
rewriteConfigState
*
state
,
const
char
*
option
,
sds
line
,
int
force
);
int
rewriteConfig
(
char
*
path
);
/* db.c -- Keyspace access API */
...
...
@@ -1396,6 +1398,7 @@ void blockClient(redisClient *c, int btype);
void
unblockClient
(
redisClient
*
c
);
void
replyToBlockedClientTimedOut
(
redisClient
*
c
);
int
getTimeoutFromObjectOrReply
(
redisClient
*
c
,
robj
*
object
,
mstime_t
*
timeout
,
int
unit
);
void
disconnectAllBlockedClients
(
void
);
/* Git SHA1 */
char
*
redisGitSHA1
(
void
);
...
...
@@ -1556,6 +1559,14 @@ void bitcountCommand(redisClient *c);
void
bitposCommand
(
redisClient
*
c
);
void
replconfCommand
(
redisClient
*
c
);
void
waitCommand
(
redisClient
*
c
);
void
geoencodeCommand
(
redisClient
*
c
);
void
geodecodeCommand
(
redisClient
*
c
);
void
georadiusByMemberCommand
(
redisClient
*
c
);
void
georadiusCommand
(
redisClient
*
c
);
void
geoaddCommand
(
redisClient
*
c
);
void
geohashCommand
(
redisClient
*
c
);
void
geoposCommand
(
redisClient
*
c
);
void
geodistCommand
(
redisClient
*
c
);
void
pfselftestCommand
(
redisClient
*
c
);
void
pfaddCommand
(
redisClient
*
c
);
void
pfcountCommand
(
redisClient
*
c
);
...
...
src/replication.c
View file @
9e67df2a
...
...
@@ -652,7 +652,8 @@ void replconfCommand(redisClient *c) {
*
* It does a few things:
*
* 1) Put the slave in ONLINE state.
* 1) Put the slave in ONLINE state (useless when the function is called
* because state is already ONLINE but repl_put_online_on_ack is true).
* 2) Make sure the writable event is re-installed, since calling the SYNC
* command disables it, so that we can accumulate output buffer without
* sending it to the slave.
...
...
@@ -660,7 +661,7 @@ void replconfCommand(redisClient *c) {
void
putSlaveOnline
(
redisClient
*
slave
)
{
slave
->
replstate
=
REDIS_REPL_ONLINE
;
slave
->
repl_put_online_on_ack
=
0
;
slave
->
repl_ack_time
=
server
.
unixtime
;
slave
->
repl_ack_time
=
server
.
unixtime
;
/* Prevent false timeout. */
if
(
aeCreateFileEvent
(
server
.
el
,
slave
->
fd
,
AE_WRITABLE
,
sendReplyToClient
,
slave
)
==
AE_ERR
)
{
redisLog
(
REDIS_WARNING
,
"Unable to register writable event for slave bulk transfer: %s"
,
strerror
(
errno
));
...
...
@@ -773,7 +774,7 @@ void updateSlavesWaitingBgsave(int bgsaveerr, int type) {
* is technically online now. */
slave
->
replstate
=
REDIS_REPL_ONLINE
;
slave
->
repl_put_online_on_ack
=
1
;
slave
->
repl_ack_time
=
server
.
unixtime
;
slave
->
repl_ack_time
=
server
.
unixtime
;
/* Timeout otherwise. */
}
else
{
if
(
bgsaveerr
!=
REDIS_OK
)
{
freeClient
(
slave
);
...
...
@@ -1443,7 +1444,7 @@ error:
int
connectWithMaster
(
void
)
{
int
fd
;
fd
=
anetTcpNonBlockBindConnect
(
NULL
,
fd
=
anetTcpNonBlockB
estEffortB
indConnect
(
NULL
,
server
.
masterhost
,
server
.
masterport
,
REDIS_BIND_ADDR
);
if
(
fd
==
-
1
)
{
redisLog
(
REDIS_WARNING
,
"Unable to connect to MASTER: %s"
,
...
...
@@ -1505,6 +1506,7 @@ void replicationSetMaster(char *ip, int port) {
server
.
masterhost
=
sdsnew
(
ip
);
server
.
masterport
=
port
;
if
(
server
.
master
)
freeClient
(
server
.
master
);
disconnectAllBlockedClients
();
/* Clients blocked in master, now slave. */
disconnectSlaves
();
/* Force our slaves to resync with us as well. */
replicationDiscardCachedMaster
();
/* Don't try a PSYNC. */
freeReplicationBacklog
();
/* Don't allow our chained slaves to PSYNC. */
...
...
src/scripting.c
View file @
9e67df2a
...
...
@@ -357,8 +357,9 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
if
(
cmd
->
flags
&
REDIS_CMD_WRITE
)
server
.
lua_write_dirty
=
1
;
/* If this is a Redis Cluster node, we need to make sure Lua is not
* trying to access non-local keys. */
if
(
server
.
cluster_enabled
)
{
* trying to access non-local keys, with the exception of commands
* received from our master. */
if
(
server
.
cluster_enabled
&&
!
(
server
.
lua_caller
->
flags
&
REDIS_MASTER
))
{
/* Duplicate relevant flags in the lua client. */
c
->
flags
&=
~
(
REDIS_READONLY
|
REDIS_ASKING
);
c
->
flags
|=
server
.
lua_caller
->
flags
&
(
REDIS_READONLY
|
REDIS_ASKING
);
...
...
@@ -611,11 +612,12 @@ void scriptingEnableGlobalsProtection(lua_State *lua) {
/* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
* Modified to be adapted to Redis. */
s
[
j
++
]
=
"local dbg=debug
\n
"
;
s
[
j
++
]
=
"local mt = {}
\n
"
;
s
[
j
++
]
=
"setmetatable(_G, mt)
\n
"
;
s
[
j
++
]
=
"mt.__newindex = function (t, n, v)
\n
"
;
s
[
j
++
]
=
" if d
ebu
g.getinfo(2) then
\n
"
;
s
[
j
++
]
=
" local w = d
ebu
g.getinfo(2,
\"
S
\"
).what
\n
"
;
s
[
j
++
]
=
" if d
b
g.getinfo(2) then
\n
"
;
s
[
j
++
]
=
" local w = d
b
g.getinfo(2,
\"
S
\"
).what
\n
"
;
s
[
j
++
]
=
" if w ~=
\"
main
\"
and w ~=
\"
C
\"
then
\n
"
;
s
[
j
++
]
=
" error(
\"
Script attempted to create global variable '
\"
..tostring(n)..
\"
'
\"
, 2)
\n
"
;
s
[
j
++
]
=
" end
\n
"
;
...
...
@@ -623,11 +625,12 @@ void scriptingEnableGlobalsProtection(lua_State *lua) {
s
[
j
++
]
=
" rawset(t, n, v)
\n
"
;
s
[
j
++
]
=
"end
\n
"
;
s
[
j
++
]
=
"mt.__index = function (t, n)
\n
"
;
s
[
j
++
]
=
" if d
ebu
g.getinfo(2) and d
ebu
g.getinfo(2,
\"
S
\"
).what ~=
\"
C
\"
then
\n
"
;
s
[
j
++
]
=
" if d
b
g.getinfo(2) and d
b
g.getinfo(2,
\"
S
\"
).what ~=
\"
C
\"
then
\n
"
;
s
[
j
++
]
=
" error(
\"
Script attempted to access unexisting global variable '
\"
..tostring(n)..
\"
'
\"
, 2)
\n
"
;
s
[
j
++
]
=
" end
\n
"
;
s
[
j
++
]
=
" return rawget(t, n)
\n
"
;
s
[
j
++
]
=
"end
\n
"
;
s
[
j
++
]
=
"debug = nil
\n
"
;
s
[
j
++
]
=
NULL
;
for
(
j
=
0
;
s
[
j
]
!=
NULL
;
j
++
)
code
=
sdscatlen
(
code
,
s
[
j
],
strlen
(
s
[
j
]));
...
...
@@ -731,10 +734,11 @@ void scriptingInit(void) {
* information about the caller, that's what makes sense from the point
* of view of the user debugging a script. */
{
char
*
errh_func
=
"function __redis__err__handler(err)
\n
"
" local i = debug.getinfo(2,'nSl')
\n
"
char
*
errh_func
=
"local dbg = debug
\n
"
"function __redis__err__handler(err)
\n
"
" local i = dbg.getinfo(2,'nSl')
\n
"
" if i and i.what == 'C' then
\n
"
" i = d
ebu
g.getinfo(3,'nSl')
\n
"
" i = d
b
g.getinfo(3,'nSl')
\n
"
" end
\n
"
" if i then
\n
"
" return i.source .. ':' .. i.currentline .. ': ' .. err
\n
"
...
...
@@ -876,7 +880,7 @@ void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) {
}
/* Define a lua function with the specified function name and body.
* The function name musts be a 2 characters long string, since all the
* The function name musts be a
4
2 characters long string, since all the
* functions we defined in the Lua context are in the form:
*
* f_<hex sha1 sum>
...
...
src/sds.c
View file @
9e67df2a
...
...
@@ -71,7 +71,7 @@ sds sdsempty(void) {
return
sdsnewlen
(
""
,
0
);
}
/* Create a new sds string starting from a null termined C string. */
/* Create a new sds string starting from a null termin
at
ed C string. */
sds
sdsnew
(
const
char
*
init
)
{
size_t
initlen
=
(
init
==
NULL
)
?
0
:
strlen
(
init
);
return
sdsnewlen
(
init
,
initlen
);
...
...
@@ -557,7 +557,7 @@ sds sdscatfmt(sds s, char const *fmt, ...) {
* Example:
*
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s = sdstrim(s,"A. :");
* s = sdstrim(s,"A
a
. :");
* printf("%s\n", s);
*
* Output will be just "Hello World".
...
...
@@ -1098,6 +1098,7 @@ int sdsTest(int argc, char *argv[]) {
unsigned
int
oldfree
;
sdsfree
(
x
);
sdsfree
(
y
);
x
=
sdsnew
(
"0"
);
sh
=
(
void
*
)
(
x
-
(
sizeof
(
struct
sdshdr
)));
test_cond
(
"sdsnew() free/len buffers"
,
sh
->
len
==
1
&&
sh
->
free
==
0
);
...
...
@@ -1110,6 +1111,8 @@ int sdsTest(int argc, char *argv[]) {
test_cond
(
"sdsIncrLen() -- content"
,
x
[
0
]
==
'0'
&&
x
[
1
]
==
'1'
);
test_cond
(
"sdsIncrLen() -- len"
,
sh
->
len
==
2
);
test_cond
(
"sdsIncrLen() -- free"
,
sh
->
free
==
oldfree
-
1
);
sdsfree
(
x
);
}
}
test_report
()
...
...
src/sentinel.c
View file @
9e67df2a
This diff is collapsed.
Click to expand it.
src/sha1.c
View file @
9e67df2a
...
...
@@ -23,7 +23,7 @@ A million repetitions of "a"
#include <stdio.h>
#include <string.h>
#include <s
ys/types.h>
/* for u_int*_t */
#include <s
tdint.h>
#include "solarisfixes.h"
#include "sha1.h"
#include "config.h"
...
...
@@ -53,12 +53,12 @@ A million repetitions of "a"
/* Hash a single 512-bit block. This is the core of the algorithm. */
void
SHA1Transform
(
u
_
int32_t
state
[
5
],
const
unsigned
char
buffer
[
64
])
void
SHA1Transform
(
uint32_t
state
[
5
],
const
unsigned
char
buffer
[
64
])
{
u
_
int32_t
a
,
b
,
c
,
d
,
e
;
uint32_t
a
,
b
,
c
,
d
,
e
;
typedef
union
{
unsigned
char
c
[
64
];
u
_
int32_t
l
[
16
];
uint32_t
l
[
16
];
}
CHAR64LONG16
;
#ifdef SHA1HANDSOFF
CHAR64LONG16
block
[
1
];
/* use array to appear as a pointer */
...
...
@@ -128,9 +128,9 @@ void SHA1Init(SHA1_CTX* context)
/* Run your data through this. */
void
SHA1Update
(
SHA1_CTX
*
context
,
const
unsigned
char
*
data
,
u
_
int32_t
len
)
void
SHA1Update
(
SHA1_CTX
*
context
,
const
unsigned
char
*
data
,
uint32_t
len
)
{
u
_
int32_t
i
,
j
;
uint32_t
i
,
j
;
j
=
context
->
count
[
0
];
if
((
context
->
count
[
0
]
+=
len
<<
3
)
<
j
)
...
...
@@ -168,7 +168,7 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
for (i = 0; i < 2; i++)
{
u
_
int32_t t = context->count[i];
uint32_t t = context->count[i];
int j;
for (j = 0; j < 4; t >>= 8, j++)
...
...
src/sha1.h
View file @
9e67df2a
...
...
@@ -8,14 +8,14 @@ By Steve Reid <steve@edmweb.com>
*/
typedef
struct
{
u
_
int32_t
state
[
5
];
u
_
int32_t
count
[
2
];
uint32_t
state
[
5
];
uint32_t
count
[
2
];
unsigned
char
buffer
[
64
];
}
SHA1_CTX
;
void
SHA1Transform
(
u
_
int32_t
state
[
5
],
const
unsigned
char
buffer
[
64
]);
void
SHA1Transform
(
uint32_t
state
[
5
],
const
unsigned
char
buffer
[
64
]);
void
SHA1Init
(
SHA1_CTX
*
context
);
void
SHA1Update
(
SHA1_CTX
*
context
,
const
unsigned
char
*
data
,
u
_
int32_t
len
);
void
SHA1Update
(
SHA1_CTX
*
context
,
const
unsigned
char
*
data
,
uint32_t
len
);
void
SHA1Final
(
unsigned
char
digest
[
20
],
SHA1_CTX
*
context
);
#ifdef REDIS_TEST
...
...
Prev
1
2
3
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