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
3f9e2322
Commit
3f9e2322
authored
Apr 07, 2017
by
antirez
Browse files
Rax library updated.
parent
1409c545
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/db.c
View file @
3f9e2322
...
@@ -1315,9 +1315,9 @@ void slotToKeyUpdateKey(robj *key, int add) {
...
@@ -1315,9 +1315,9 @@ void slotToKeyUpdateKey(robj *key, int add) {
indexed
[
1
]
=
hashslot
&
0xff
;
indexed
[
1
]
=
hashslot
&
0xff
;
memcpy
(
indexed
+
2
,
key
->
ptr
,
keylen
);
memcpy
(
indexed
+
2
,
key
->
ptr
,
keylen
);
if
(
add
)
{
if
(
add
)
{
raxInsert
(
server
.
cluster
->
slots_to_keys
,
indexed
,
keylen
+
2
,
NULL
);
raxInsert
(
server
.
cluster
->
slots_to_keys
,
indexed
,
keylen
+
2
,
NULL
,
NULL
);
}
else
{
}
else
{
raxRemove
(
server
.
cluster
->
slots_to_keys
,
indexed
,
keylen
+
2
);
raxRemove
(
server
.
cluster
->
slots_to_keys
,
indexed
,
keylen
+
2
,
NULL
);
}
}
if
(
indexed
!=
buf
)
zfree
(
indexed
);
if
(
indexed
!=
buf
)
zfree
(
indexed
);
}
}
...
@@ -1348,8 +1348,8 @@ unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int coun
...
@@ -1348,8 +1348,8 @@ unsigned int getKeysInSlot(unsigned int hashslot, robj **keys, unsigned int coun
indexed
[
0
]
=
(
hashslot
>>
8
)
&
0xff
;
indexed
[
0
]
=
(
hashslot
>>
8
)
&
0xff
;
indexed
[
1
]
=
hashslot
&
0xff
;
indexed
[
1
]
=
hashslot
&
0xff
;
raxStart
(
&
iter
,
server
.
cluster
->
slots_to_keys
);
raxStart
(
&
iter
,
server
.
cluster
->
slots_to_keys
);
raxSeek
(
&
iter
,
indexed
,
2
,
">="
);
raxSeek
(
&
iter
,
">="
,
indexed
,
2
);
while
(
count
--
&&
raxNext
(
&
iter
,
NULL
,
0
,
NULL
))
{
while
(
count
--
&&
raxNext
(
&
iter
))
{
if
(
iter
.
key
[
0
]
!=
indexed
[
0
]
||
iter
.
key
[
1
]
!=
indexed
[
1
])
break
;
if
(
iter
.
key
[
0
]
!=
indexed
[
0
]
||
iter
.
key
[
1
]
!=
indexed
[
1
])
break
;
keys
[
j
++
]
=
createStringObject
((
char
*
)
iter
.
key
+
2
,
iter
.
key_len
-
2
);
keys
[
j
++
]
=
createStringObject
((
char
*
)
iter
.
key
+
2
,
iter
.
key_len
-
2
);
}
}
...
@@ -1368,8 +1368,8 @@ unsigned int delKeysInSlot(unsigned int hashslot) {
...
@@ -1368,8 +1368,8 @@ unsigned int delKeysInSlot(unsigned int hashslot) {
indexed
[
1
]
=
hashslot
&
0xff
;
indexed
[
1
]
=
hashslot
&
0xff
;
raxStart
(
&
iter
,
server
.
cluster
->
slots_to_keys
);
raxStart
(
&
iter
,
server
.
cluster
->
slots_to_keys
);
while
(
server
.
cluster
->
slots_keys_count
[
hashslot
])
{
while
(
server
.
cluster
->
slots_keys_count
[
hashslot
])
{
raxSeek
(
&
iter
,
indexed
,
2
,
">="
);
raxSeek
(
&
iter
,
">="
,
indexed
,
2
);
raxNext
(
&
iter
,
NULL
,
0
,
NULL
);
raxNext
(
&
iter
);
robj
*
key
=
createStringObject
((
char
*
)
iter
.
key
+
2
,
iter
.
key_len
-
2
);
robj
*
key
=
createStringObject
((
char
*
)
iter
.
key
+
2
,
iter
.
key_len
-
2
);
dbDelete
(
&
server
.
db
[
0
],
key
);
dbDelete
(
&
server
.
db
[
0
],
key
);
...
...
src/rax.c
View file @
3f9e2322
...
@@ -33,8 +33,14 @@
...
@@ -33,8 +33,14 @@
#include <assert.h>
#include <assert.h>
#include <stdio.h>
#include <stdio.h>
#include <errno.h>
#include <errno.h>
#include <math.h>
#include "rax.h"
#include "rax.h"
#include "rax_malloc.h"
#ifndef RAX_MALLOC_INCLUDE
#define RAX_MALLOC_INCLUDE "rax_malloc.h"
#endif
#include RAX_MALLOC_INCLUDE
/* This is a special pointer that is guaranteed to never have the same value
/* This is a special pointer that is guaranteed to never have the same value
* of a radix tree node. It's used in order to report "not found" error without
* of a radix tree node. It's used in order to report "not found" error without
...
@@ -84,6 +90,7 @@ static inline int raxStackPush(raxStack *ts, void *ptr) {
...
@@ -84,6 +90,7 @@ static inline int raxStackPush(raxStack *ts, void *ptr) {
if
(
ts
->
stack
==
NULL
)
{
if
(
ts
->
stack
==
NULL
)
{
ts
->
stack
=
ts
->
static_items
;
ts
->
stack
=
ts
->
static_items
;
ts
->
oom
=
1
;
ts
->
oom
=
1
;
errno
=
ENOMEM
;
return
0
;
return
0
;
}
}
memcpy
(
ts
->
stack
,
ts
->
static_items
,
sizeof
(
void
*
)
*
ts
->
maxitems
);
memcpy
(
ts
->
stack
,
ts
->
static_items
,
sizeof
(
void
*
)
*
ts
->
maxitems
);
...
@@ -91,6 +98,7 @@ static inline int raxStackPush(raxStack *ts, void *ptr) {
...
@@ -91,6 +98,7 @@ static inline int raxStackPush(raxStack *ts, void *ptr) {
void
**
newalloc
=
rax_realloc
(
ts
->
stack
,
sizeof
(
void
*
)
*
ts
->
maxitems
*
2
);
void
**
newalloc
=
rax_realloc
(
ts
->
stack
,
sizeof
(
void
*
)
*
ts
->
maxitems
*
2
);
if
(
newalloc
==
NULL
)
{
if
(
newalloc
==
NULL
)
{
ts
->
oom
=
1
;
ts
->
oom
=
1
;
errno
=
ENOMEM
;
return
0
;
return
0
;
}
}
ts
->
stack
=
newalloc
;
ts
->
stack
=
newalloc
;
...
@@ -205,7 +213,7 @@ void *raxGetData(raxNode *n) {
...
@@ -205,7 +213,7 @@ void *raxGetData(raxNode *n) {
* On success the new parent node pointer is returned (it may change because
* On success the new parent node pointer is returned (it may change because
* of the realloc, so the caller should discard 'n' and use the new value).
* of the realloc, so the caller should discard 'n' and use the new value).
* On out of memory NULL is returned, and the old node is still valid. */
* On out of memory NULL is returned, and the old node is still valid. */
raxNode
*
raxAddChild
(
raxNode
*
n
,
char
c
,
raxNode
**
childptr
,
raxNode
***
parentlink
)
{
raxNode
*
raxAddChild
(
raxNode
*
n
,
unsigned
char
c
,
raxNode
**
childptr
,
raxNode
***
parentlink
)
{
assert
(
n
->
iscompr
==
0
);
assert
(
n
->
iscompr
==
0
);
size_t
curlen
=
sizeof
(
raxNode
)
+
size_t
curlen
=
sizeof
(
raxNode
)
+
...
@@ -330,7 +338,7 @@ raxNode *raxCompressNode(raxNode *n, unsigned char *s, size_t len, raxNode **chi
...
@@ -330,7 +338,7 @@ raxNode *raxCompressNode(raxNode *n, unsigned char *s, size_t len, raxNode **chi
memcpy
(
n
->
data
,
s
,
len
);
memcpy
(
n
->
data
,
s
,
len
);
if
(
n
->
iskey
)
raxSetData
(
n
,
data
);
if
(
n
->
iskey
)
raxSetData
(
n
,
data
);
raxNode
**
childfield
=
raxNodeLastChildPtr
(
n
);
raxNode
**
childfield
=
raxNodeLastChildPtr
(
n
);
memcpy
(
childfield
,
&
child
,
sizeof
(
child
));
memcpy
(
childfield
,
child
,
sizeof
(
*
child
));
return
n
;
return
n
;
}
}
...
@@ -399,7 +407,7 @@ static inline size_t raxLowWalk(rax *rax, unsigned char *s, size_t len, raxNode
...
@@ -399,7 +407,7 @@ static inline size_t raxLowWalk(rax *rax, unsigned char *s, size_t len, raxNode
* data is updated, and 0 is returned, otherwise the element is inserted
* data is updated, and 0 is returned, otherwise the element is inserted
* and 1 is returned. On out of memory the function returns 0 as well but
* and 1 is returned. On out of memory the function returns 0 as well but
* sets errno to ENOMEM, otherwise errno will be set to 0. */
* sets errno to ENOMEM, otherwise errno will be set to 0. */
int
raxInsert
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
*
data
)
{
int
raxInsert
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
*
data
,
void
**
old
)
{
size_t
i
;
size_t
i
;
int
j
=
0
;
/* Split position. If raxLowWalk() stops in a compressed
int
j
=
0
;
/* Split position. If raxLowWalk() stops in a compressed
node, the index 'j' represents the char we stopped within the
node, the index 'j' represents the char we stopped within the
...
@@ -417,6 +425,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
...
@@ -417,6 +425,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
* data pointer. */
* data pointer. */
if
(
i
==
len
&&
(
!
h
->
iscompr
||
j
==
0
/* not in the middle if j is 0 */
))
{
if
(
i
==
len
&&
(
!
h
->
iscompr
||
j
==
0
/* not in the middle if j is 0 */
))
{
if
(
h
->
iskey
)
{
if
(
h
->
iskey
)
{
if
(
old
)
*
old
=
raxGetData
(
h
);
raxSetData
(
h
,
data
);
raxSetData
(
h
,
data
);
errno
=
0
;
errno
=
0
;
return
0
;
/* Element already exists. */
return
0
;
/* Element already exists. */
...
@@ -720,6 +729,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
...
@@ -720,6 +729,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
/* Finish! We don't need to contine with the insertion
/* Finish! We don't need to contine with the insertion
* algorithm for ALGO 2. The key is already inserted. */
* algorithm for ALGO 2. The key is already inserted. */
rax
->
numele
++
;
rax
->
numele
++
;
rax_free
(
h
);
return
1
;
/* Key inserted. */
return
1
;
/* Key inserted. */
}
}
...
@@ -729,7 +739,6 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
...
@@ -729,7 +739,6 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
* since i == len. */
* since i == len. */
while
(
i
<
len
)
{
while
(
i
<
len
)
{
raxNode
*
child
;
raxNode
*
child
;
rax
->
numnodes
++
;
/* If this node is going to have a single child, and there
/* If this node is going to have a single child, and there
* are other characters, so that that would result in a chain
* are other characters, so that that would result in a chain
...
@@ -755,6 +764,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
...
@@ -755,6 +764,7 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
parentlink
=
new_parentlink
;
parentlink
=
new_parentlink
;
i
++
;
i
++
;
}
}
rax
->
numnodes
++
;
h
=
child
;
h
=
child
;
}
}
raxNode
*
newh
=
raxReallocForData
(
h
,
data
);
raxNode
*
newh
=
raxReallocForData
(
h
,
data
);
...
@@ -767,10 +777,16 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
...
@@ -767,10 +777,16 @@ int raxInsert(rax *rax, unsigned char *s, size_t len, void *data) {
oom:
oom:
/* This code path handles out of memory after part of the sub-tree was
/* This code path handles out of memory after part of the sub-tree was
* already added. Set the node as a key, and then remove it. */
* already modified. Set the node as a key, and then remove it. However we
h
->
isnull
=
1
;
* do that only if the node is a terminal node, otherwise if the OOM
h
->
iskey
=
1
;
* happened reallocating a node in the middle, we don't need to free
raxRemove
(
rax
,
s
,
i
);
* anything. */
if
(
h
->
size
==
0
)
{
h
->
isnull
=
1
;
h
->
iskey
=
1
;
rax
->
numele
++
;
/* Compensate the next remove. */
assert
(
raxRemove
(
rax
,
s
,
i
,
NULL
)
!=
0
);
}
errno
=
ENOMEM
;
errno
=
ENOMEM
;
return
0
;
return
0
;
}
}
...
@@ -830,7 +846,7 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
...
@@ -830,7 +846,7 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
*
*
* 1. To start we seek the first element in both the children
* 1. To start we seek the first element in both the children
* pointers and edge bytes in the node. */
* pointers and edge bytes in the node. */
raxNode
**
cp
=
raxNode
La
stChildPtr
(
parent
)
-
(
parent
->
size
-
1
)
;
raxNode
**
cp
=
raxNode
Fir
stChildPtr
(
parent
);
raxNode
**
c
=
cp
;
raxNode
**
c
=
cp
;
unsigned
char
*
e
=
parent
->
data
;
unsigned
char
*
e
=
parent
->
data
;
...
@@ -855,7 +871,7 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
...
@@ -855,7 +871,7 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
memmove
(((
char
*
)
cp
)
-
1
,
cp
,(
parent
->
size
-
taillen
-
1
)
*
sizeof
(
raxNode
**
));
memmove
(((
char
*
)
cp
)
-
1
,
cp
,(
parent
->
size
-
taillen
-
1
)
*
sizeof
(
raxNode
**
));
/* Move the remaining "tail" pointer at the right position as well. */
/* Move the remaining "tail" pointer at the right position as well. */
memmove
(((
char
*
)
c
)
-
1
,
c
+
1
,
taillen
*
sizeof
(
raxNode
**
));
memmove
(((
char
*
)
c
)
-
1
,
c
+
1
,
taillen
*
sizeof
(
raxNode
**
)
+
parent
->
iskey
*
sizeof
(
void
*
)
);
/* 4. Update size. */
/* 4. Update size. */
parent
->
size
--
;
parent
->
size
--
;
...
@@ -863,7 +879,9 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
...
@@ -863,7 +879,9 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
/* realloc the node according to the theoretical memory usage, to free
/* realloc the node according to the theoretical memory usage, to free
* data if we are over-allocating right now. */
* data if we are over-allocating right now. */
raxNode
*
newnode
=
rax_realloc
(
parent
,
raxNodeCurrentLength
(
parent
));
raxNode
*
newnode
=
rax_realloc
(
parent
,
raxNodeCurrentLength
(
parent
));
debugnode
(
"raxRemoveChild after"
,
newnode
);
if
(
newnode
)
{
debugnode
(
"raxRemoveChild after"
,
newnode
);
}
/* Note: if rax_realloc() fails we just return the old address, which
/* Note: if rax_realloc() fails we just return the old address, which
* is valid. */
* is valid. */
return
newnode
?
newnode
:
parent
;
return
newnode
?
newnode
:
parent
;
...
@@ -871,18 +889,19 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
...
@@ -871,18 +889,19 @@ raxNode *raxRemoveChild(raxNode *parent, raxNode *child) {
/* Remove the specified item. Returns 1 if the item was found and
/* Remove the specified item. Returns 1 if the item was found and
* deleted, 0 otherwise. */
* deleted, 0 otherwise. */
int
raxRemove
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
)
{
int
raxRemove
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
**
old
)
{
raxNode
*
h
;
raxNode
*
h
;
raxStack
ts
;
raxStack
ts
;
debugf
(
"### Delete: %.*s
\n
"
,
(
int
)
len
,
s
);
debugf
(
"### Delete: %.*s
\n
"
,
(
int
)
len
,
s
);
raxStackInit
(
&
ts
);
raxStackInit
(
&
ts
);
int
splitpos
=
0
;
int
splitpos
=
0
;
size_t
i
=
raxLowWalk
(
rax
,
s
,
len
,
&
h
,
NULL
,
NULL
,
&
ts
);
size_t
i
=
raxLowWalk
(
rax
,
s
,
len
,
&
h
,
NULL
,
&
splitpos
,
&
ts
);
if
(
i
!=
len
||
(
h
->
iscompr
&&
splitpos
!=
0
)
||
!
h
->
iskey
)
{
if
(
i
!=
len
||
(
h
->
iscompr
&&
splitpos
!=
0
)
||
!
h
->
iskey
)
{
raxStackFree
(
&
ts
);
raxStackFree
(
&
ts
);
return
0
;
return
0
;
}
}
if
(
old
)
*
old
=
raxGetData
(
h
);
h
->
iskey
=
0
;
h
->
iskey
=
0
;
rax
->
numele
--
;
rax
->
numele
--
;
...
@@ -1009,6 +1028,9 @@ int raxRemove(rax *rax, unsigned char *s, size_t len) {
...
@@ -1009,6 +1028,9 @@ int raxRemove(rax *rax, unsigned char *s, size_t len) {
raxNode
**
cp
=
raxNodeLastChildPtr
(
h
);
raxNode
**
cp
=
raxNodeLastChildPtr
(
h
);
memcpy
(
&
h
,
cp
,
sizeof
(
h
));
memcpy
(
&
h
,
cp
,
sizeof
(
h
));
if
(
h
->
iskey
||
(
!
h
->
iscompr
&&
h
->
size
!=
1
))
break
;
if
(
h
->
iskey
||
(
!
h
->
iscompr
&&
h
->
size
!=
1
))
break
;
/* Stop here if going to the next node would result into
* a compressed node larger than h->size can hold. */
if
(
comprsize
+
h
->
size
>
RAX_NODE_MAX_SIZE
)
break
;
nodes
++
;
nodes
++
;
comprsize
+=
h
->
size
;
comprsize
+=
h
->
size
;
}
}
...
@@ -1115,6 +1137,7 @@ int raxIteratorAddChars(raxIterator *it, unsigned char *s, size_t len) {
...
@@ -1115,6 +1137,7 @@ int raxIteratorAddChars(raxIterator *it, unsigned char *s, size_t len) {
it
->
key
=
rax_realloc
(
old
,
new_max
);
it
->
key
=
rax_realloc
(
old
,
new_max
);
if
(
it
->
key
==
NULL
)
{
if
(
it
->
key
==
NULL
)
{
it
->
key
=
(
!
old
)
?
it
->
key_static_string
:
old
;
it
->
key
=
(
!
old
)
?
it
->
key_static_string
:
old
;
errno
=
ENOMEM
;
return
0
;
return
0
;
}
}
if
(
old
==
NULL
)
memcpy
(
it
->
key
,
it
->
key_static_string
,
it
->
key_len
);
if
(
old
==
NULL
)
memcpy
(
it
->
key
,
it
->
key_static_string
,
it
->
key_len
);
...
@@ -1190,6 +1213,8 @@ int raxIteratorNextStep(raxIterator *it, int noup) {
...
@@ -1190,6 +1213,8 @@ int raxIteratorNextStep(raxIterator *it, int noup) {
* children representing keys lexicographically greater than the
* children representing keys lexicographically greater than the
* current key. */
* current key. */
while
(
1
)
{
while
(
1
)
{
int
old_noup
=
noup
;
/* Already on head? Can't go up, iteration finished. */
/* Already on head? Can't go up, iteration finished. */
if
(
!
noup
&&
it
->
node
==
it
->
rt
->
head
)
{
if
(
!
noup
&&
it
->
node
==
it
->
rt
->
head
)
{
it
->
flags
|=
RAX_ITER_EOF
;
it
->
flags
|=
RAX_ITER_EOF
;
...
@@ -1211,9 +1236,9 @@ int raxIteratorNextStep(raxIterator *it, int noup) {
...
@@ -1211,9 +1236,9 @@ int raxIteratorNextStep(raxIterator *it, int noup) {
int
todel
=
it
->
node
->
iscompr
?
it
->
node
->
size
:
1
;
int
todel
=
it
->
node
->
iscompr
?
it
->
node
->
size
:
1
;
raxIteratorDelChars
(
it
,
todel
);
raxIteratorDelChars
(
it
,
todel
);
/* Try visitng the next child if there was at least one
/* Try visit
i
ng the next child if there was at least one
* additional child. */
* additional child. */
if
(
!
it
->
node
->
iscompr
&&
it
->
node
->
size
>
1
)
{
if
(
!
it
->
node
->
iscompr
&&
it
->
node
->
size
>
(
old_noup
?
0
:
1
)
)
{
raxNode
**
cp
=
raxNodeFirstChildPtr
(
it
->
node
);
raxNode
**
cp
=
raxNodeFirstChildPtr
(
it
->
node
);
int
i
=
0
;
int
i
=
0
;
while
(
i
<
it
->
node
->
size
)
{
while
(
i
<
it
->
node
->
size
)
{
...
@@ -1276,6 +1301,8 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
...
@@ -1276,6 +1301,8 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
raxNode
*
orig_node
=
it
->
node
;
raxNode
*
orig_node
=
it
->
node
;
while
(
1
)
{
while
(
1
)
{
int
old_noup
=
noup
;
/* Already on head? Can't go up, iteration finished. */
/* Already on head? Can't go up, iteration finished. */
if
(
!
noup
&&
it
->
node
==
it
->
rt
->
head
)
{
if
(
!
noup
&&
it
->
node
==
it
->
rt
->
head
)
{
it
->
flags
|=
RAX_ITER_EOF
;
it
->
flags
|=
RAX_ITER_EOF
;
...
@@ -1297,9 +1324,9 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
...
@@ -1297,9 +1324,9 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
int
todel
=
it
->
node
->
iscompr
?
it
->
node
->
size
:
1
;
int
todel
=
it
->
node
->
iscompr
?
it
->
node
->
size
:
1
;
raxIteratorDelChars
(
it
,
todel
);
raxIteratorDelChars
(
it
,
todel
);
/* Try visiting the prev child if there
wa
s at least one
/* Try visiting the prev child if there
i
s at least one
*
additional
child. */
* child. */
if
(
!
it
->
node
->
iscompr
&&
it
->
node
->
size
>
1
)
{
if
(
!
it
->
node
->
iscompr
&&
it
->
node
->
size
>
(
old_noup
?
0
:
1
)
)
{
raxNode
**
cp
=
raxNodeLastChildPtr
(
it
->
node
);
raxNode
**
cp
=
raxNodeLastChildPtr
(
it
->
node
);
int
i
=
it
->
node
->
size
-
1
;
int
i
=
it
->
node
->
size
-
1
;
while
(
i
>=
0
)
{
while
(
i
>=
0
)
{
...
@@ -1334,8 +1361,9 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
...
@@ -1334,8 +1361,9 @@ int raxIteratorPrevStep(raxIterator *it, int noup) {
/* Seek an iterator at the specified element.
/* Seek an iterator at the specified element.
* Return 0 if the seek failed for syntax error or out of memory. Otherwise
* Return 0 if the seek failed for syntax error or out of memory. Otherwise
* 1 is returned. */
* 1 is returned. When 0 is returned for out of memory, errno is set to
int
raxSeek
(
raxIterator
*
it
,
unsigned
char
*
ele
,
size_t
len
,
const
char
*
op
)
{
* the ENOMEM value. */
int
raxSeek
(
raxIterator
*
it
,
const
char
*
op
,
unsigned
char
*
ele
,
size_t
len
)
{
int
eq
=
0
,
lt
=
0
,
gt
=
0
,
first
=
0
,
last
=
0
;
int
eq
=
0
,
lt
=
0
,
gt
=
0
,
first
=
0
,
last
=
0
;
it
->
stack
.
items
=
0
;
/* Just resetting. Intialized by raxStart(). */
it
->
stack
.
items
=
0
;
/* Just resetting. Intialized by raxStart(). */
...
@@ -1358,6 +1386,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
...
@@ -1358,6 +1386,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
}
else
if
(
op
[
0
]
==
'$'
)
{
}
else
if
(
op
[
0
]
==
'$'
)
{
last
=
1
;
last
=
1
;
}
else
{
}
else
{
errno
=
0
;
return
0
;
/* Error. */
return
0
;
/* Error. */
}
}
...
@@ -1371,7 +1400,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
...
@@ -1371,7 +1400,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
if
(
first
)
{
if
(
first
)
{
/* Seeking the first key greater or equal to the empty string
/* Seeking the first key greater or equal to the empty string
* is equivalent to seeking the smaller key available. */
* is equivalent to seeking the smaller key available. */
return
raxSeek
(
it
,
NULL
,
0
,
">="
);
return
raxSeek
(
it
,
">="
,
NULL
,
0
);
}
}
if
(
last
)
{
if
(
last
)
{
...
@@ -1398,7 +1427,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
...
@@ -1398,7 +1427,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
/* We found our node, since the key matches and we have an
/* We found our node, since the key matches and we have an
* "equal" condition. */
* "equal" condition. */
if
(
!
raxIteratorAddChars
(
it
,
ele
,
len
))
return
0
;
/* OOM. */
if
(
!
raxIteratorAddChars
(
it
,
ele
,
len
))
return
0
;
/* OOM. */
}
else
{
}
else
if
(
lt
||
gt
)
{
/* Exact key not found or eq flag not set. We have to set as current
/* Exact key not found or eq flag not set. We have to set as current
* key the one represented by the node we stopped at, and perform
* key the one represented by the node we stopped at, and perform
* a next/prev operation to seek. To reconstruct the key at this node
* a next/prev operation to seek. To reconstruct the key at this node
...
@@ -1490,6 +1519,10 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
...
@@ -1490,6 +1519,10 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
if
(
lt
&&
!
raxIteratorPrevStep
(
it
,
0
))
return
0
;
if
(
lt
&&
!
raxIteratorPrevStep
(
it
,
0
))
return
0
;
it
->
flags
|=
RAX_ITER_JUST_SEEKED
;
/* Ignore next call. */
it
->
flags
|=
RAX_ITER_JUST_SEEKED
;
/* Ignore next call. */
}
}
}
else
{
/* If we are here just eq was set but no match was found. */
it
->
flags
|=
RAX_ITER_EOF
;
return
1
;
}
}
return
1
;
return
1
;
}
}
...
@@ -1497,7 +1530,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
...
@@ -1497,7 +1530,7 @@ int raxSeek(raxIterator *it, unsigned char *ele, size_t len, const char *op) {
/* Go to the next element in the scope of the iterator 'it'.
/* Go to the next element in the scope of the iterator 'it'.
* If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
* If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
* returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
* returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
int
raxNext
(
raxIterator
*
it
,
unsigned
char
*
stop
,
size_t
stoplen
,
char
*
op
)
{
int
raxNext
(
raxIterator
*
it
)
{
if
(
!
raxIteratorNextStep
(
it
,
0
))
{
if
(
!
raxIteratorNextStep
(
it
,
0
))
{
errno
=
ENOMEM
;
errno
=
ENOMEM
;
return
0
;
return
0
;
...
@@ -1512,7 +1545,7 @@ int raxNext(raxIterator *it, unsigned char *stop, size_t stoplen, char *op) {
...
@@ -1512,7 +1545,7 @@ int raxNext(raxIterator *it, unsigned char *stop, size_t stoplen, char *op) {
/* Go to the previous element in the scope of the iterator 'it'.
/* Go to the previous element in the scope of the iterator 'it'.
* If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
* If EOF (or out of memory) is reached, 0 is returned, otherwise 1 is
* returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
* returned. In case 0 is returned because of OOM, errno is set to ENOMEM. */
int
raxPrev
(
raxIterator
*
it
,
unsigned
char
*
stop
,
size_t
stoplen
,
char
*
op
)
{
int
raxPrev
(
raxIterator
*
it
)
{
if
(
!
raxIteratorPrevStep
(
it
,
0
))
{
if
(
!
raxIteratorPrevStep
(
it
,
0
))
{
errno
=
ENOMEM
;
errno
=
ENOMEM
;
return
0
;
return
0
;
...
@@ -1524,6 +1557,87 @@ int raxPrev(raxIterator *it, unsigned char *stop, size_t stoplen, char *op) {
...
@@ -1524,6 +1557,87 @@ int raxPrev(raxIterator *it, unsigned char *stop, size_t stoplen, char *op) {
return
1
;
return
1
;
}
}
/* Perform a random walk starting in the current position of the iterator.
* Return 0 if the tree is empty or on out of memory. Otherwise 1 is returned
* and the iterator is set to the node reached after doing a random walk
* of 'steps' steps. If the 'steps' argument is 0, the random walk is performed
* using a random number of steps between 1 and two times the logarithm of
* the number of elements.
*
* NOTE: if you use this function to generate random elements from the radix
* tree, expect a disappointing distribution. A random walk produces good
* random elements if the tree is not sparse, however in the case of a radix
* tree certain keys will be reported much more often than others. At least
* this function should be able to expore every possible element eventually. */
int
raxRandomWalk
(
raxIterator
*
it
,
size_t
steps
)
{
if
(
it
->
rt
->
numele
==
0
)
{
it
->
flags
|=
RAX_ITER_EOF
;
return
0
;
}
if
(
steps
==
0
)
{
size_t
fle
=
floor
(
log
(
it
->
rt
->
numele
));
fle
*=
2
;
steps
=
1
+
rand
()
%
fle
;
}
raxNode
*
n
=
it
->
node
;
while
(
steps
>
0
||
!
n
->
iskey
)
{
int
numchildren
=
n
->
iscompr
?
1
:
n
->
size
;
int
r
=
rand
()
%
(
numchildren
+
(
n
!=
it
->
rt
->
head
));
if
(
r
==
numchildren
)
{
/* Go up to parent. */
n
=
raxStackPop
(
&
it
->
stack
);
int
todel
=
n
->
iscompr
?
n
->
size
:
1
;
raxIteratorDelChars
(
it
,
todel
);
}
else
{
/* Select a random child. */
if
(
n
->
iscompr
)
{
if
(
!
raxIteratorAddChars
(
it
,
n
->
data
,
n
->
size
))
return
0
;
}
else
{
if
(
!
raxIteratorAddChars
(
it
,
n
->
data
+
r
,
1
))
return
0
;
}
raxNode
**
cp
=
raxNodeFirstChildPtr
(
n
)
+
r
;
if
(
!
raxStackPush
(
&
it
->
stack
,
n
))
return
0
;
memcpy
(
&
n
,
cp
,
sizeof
(
n
));
}
if
(
n
->
iskey
)
steps
--
;
}
it
->
node
=
n
;
return
1
;
}
/* Compare the key currently pointed by the iterator to the specified
* key according to the specified operator. Returns 1 if the comparison is
* true, otherwise 0 is returned. */
int
raxCompare
(
raxIterator
*
iter
,
const
char
*
op
,
unsigned
char
*
key
,
size_t
key_len
)
{
int
eq
=
0
,
lt
=
0
,
gt
=
0
;
if
(
op
[
0
]
==
'='
||
op
[
1
]
==
'='
)
eq
=
1
;
if
(
op
[
1
]
==
'>'
)
gt
=
1
;
else
if
(
op
[
1
]
==
'<'
)
lt
=
1
;
else
if
(
op
[
1
]
!=
'='
)
return
0
;
/* Syntax error. */
size_t
minlen
=
key_len
<
iter
->
key_len
?
key_len
:
iter
->
key_len
;
int
cmp
=
memcmp
(
iter
->
key
,
key
,
minlen
);
/* Handle == */
if
(
lt
==
0
&&
gt
==
0
)
return
cmp
==
0
&&
key_len
==
iter
->
key_len
;
/* Handle >, >=, <, <= */
if
(
cmp
==
0
)
{
/* Same prefix: longer wins. */
if
(
eq
&&
key_len
==
iter
->
key_len
)
return
1
;
else
if
(
lt
)
return
iter
->
key_len
<
key_len
;
else
if
(
gt
)
return
iter
->
key_len
>
key_len
;
}
if
(
cmp
>
0
)
{
return
gt
?
1
:
0
;
}
else
/* (cmp < 0) */
{
return
lt
?
1
:
0
;
}
}
/* Free the iterator. */
/* Free the iterator. */
void
raxStop
(
raxIterator
*
it
)
{
void
raxStop
(
raxIterator
*
it
)
{
if
(
it
->
key
!=
it
->
key_static_string
)
rax_free
(
it
->
key
);
if
(
it
->
key
!=
it
->
key_static_string
)
rax_free
(
it
->
key
);
...
@@ -1613,233 +1727,4 @@ void raxDebugShowNode(const char *msg, raxNode *n) {
...
@@ -1613,233 +1727,4 @@ void raxDebugShowNode(const char *msg, raxNode *n) {
fflush
(
stdout
);
fflush
(
stdout
);
}
}
#ifdef BENCHMARK_MAIN
#include <stdio.h>
#include <sys/time.h>
/* This is a simple Feistel network in order to turn every possible
* uint32_t input into another "randomly" looking uint32_t. It is a
* one to one map so there are no repetitions. */
static
uint32_t
int2int
(
uint32_t
input
)
{
uint16_t
l
=
input
&
0xffff
;
uint16_t
r
=
input
>>
16
;
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
uint16_t
nl
=
r
;
uint16_t
F
=
(((
r
*
31
)
+
(
r
>>
5
)
+
7
*
371
)
^
r
)
&
0xffff
;
r
=
l
^
F
;
l
=
nl
;
}
return
(
r
<<
16
)
|
l
;
}
/* Turn an uint32_t integer into an alphanumerical key and return its
* length. This function is used in order to generate keys that have
* a large charset, so that the radix tree can be testsed with many
* children per node. */
static
size_t
int2alphakey
(
char
*
s
,
size_t
maxlen
,
uint32_t
i
)
{
const
char
*
set
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
;
const
size_t
setlen
=
62
;
if
(
maxlen
==
0
)
return
0
;
maxlen
--
;
/* Space for null term char. */
size_t
len
=
0
;
while
(
len
<
maxlen
)
{
s
[
len
++
]
=
set
[
i
%
setlen
];
i
/=
setlen
;
if
(
i
==
0
)
break
;
}
s
[
len
]
=
'\0'
;
return
len
;
}
/* Return the UNIX time in microseconds */
static
long
long
ustime
(
void
)
{
struct
timeval
tv
;
long
long
ust
;
gettimeofday
(
&
tv
,
NULL
);
ust
=
((
long
long
)
tv
.
tv_sec
)
*
1000000
;
ust
+=
tv
.
tv_usec
;
return
ust
;
}
/* Turn the integer 'i' into a key according to 'mode'.
* mode = 0, just represents the integer as a string.
* mode = 1, turn it into a random-looking alphanumerical string
* according to the int2alphakey() function. */
static
size_t
int2key
(
char
*
s
,
size_t
maxlen
,
uint32_t
i
,
int
mode
)
{
if
(
mode
==
0
)
{
return
snprintf
(
s
,
maxlen
,
"%lu"
,(
unsigned
long
)
i
);
}
else
{
i
=
int2int
(
i
);
return
int2alphakey
(
s
,
maxlen
,
i
);
}
}
int
main
(
void
)
{
for
(
int
mode
=
0
;
mode
<
2
;
mode
++
)
{
printf
(
"Benchmark with %s keys:
\n
"
,
(
mode
==
0
)
?
"integer"
:
"alphanumerical"
);
rax
*
t
=
raxNew
();
long
long
start
=
ustime
();
for
(
int
i
=
0
;
i
<
5000000
;
i
++
)
{
char
buf
[
64
];
int
len
=
int2key
(
buf
,
sizeof
(
buf
),
i
,
mode
);
raxInsert
(
t
,(
unsigned
char
*
)
buf
,
len
,(
void
*
)(
long
)
i
);
}
printf
(
"Insert: %f
\n
"
,
(
double
)(
ustime
()
-
start
)
/
1000000
);
printf
(
"%llu total nodes
\n
"
,
(
unsigned
long
long
)
t
->
numnodes
);
printf
(
"%llu total elements
\n
"
,
(
unsigned
long
long
)
t
->
numele
);
start
=
ustime
();
for
(
int
i
=
0
;
i
<
5000000
;
i
++
)
{
char
buf
[
64
];
int
len
=
int2key
(
buf
,
sizeof
(
buf
),
i
,
mode
);
void
*
data
=
raxFind
(
t
,(
unsigned
char
*
)
buf
,
len
);
if
(
data
!=
(
void
*
)(
long
)
i
)
{
printf
(
"Issue with %s: %p instead of %p
\n
"
,
buf
,
data
,
(
void
*
)(
long
)
i
);
}
}
printf
(
"Lookup: %f
\n
"
,
(
double
)(
ustime
()
-
start
)
/
1000000
);
start
=
ustime
();
for
(
int
i
=
0
;
i
<
5000000
;
i
++
)
{
char
buf
[
64
];
int
r
=
rand
()
%
5000000
;
int
len
=
int2key
(
buf
,
sizeof
(
buf
),
r
,
mode
);
void
*
data
=
raxFind
(
t
,(
unsigned
char
*
)
buf
,
len
);
if
(
data
!=
(
void
*
)(
long
)
r
)
{
printf
(
"Issue with %s: %p instead of %p
\n
"
,
buf
,
data
,
(
void
*
)(
long
)
r
);
}
}
printf
(
"Random lookup: %f
\n
"
,
(
double
)(
ustime
()
-
start
)
/
1000000
);
start
=
ustime
();
int
count
=
0
;
for
(
int
i
=
0
;
i
<
5000000
;
i
++
)
{
char
buf
[
64
];
int
len
=
int2key
(
buf
,
sizeof
(
buf
),
i
,
mode
);
buf
[
i
%
len
]
=
'!'
;
/* "!" is never set into keys. */
void
*
data
=
raxFind
(
t
,(
unsigned
char
*
)
buf
,
len
);
if
(
data
!=
(
void
*
)(
long
)
i
)
count
++
;
}
printf
(
"Failed lookup: %f
\n
"
,
(
double
)(
ustime
()
-
start
)
/
1000000
);
start
=
ustime
();
for
(
int
i
=
0
;
i
<
5000000
;
i
++
)
{
char
buf
[
64
];
int
len
=
int2key
(
buf
,
sizeof
(
buf
),
i
,
mode
);
int
retval
=
raxRemove
(
t
,(
unsigned
char
*
)
buf
,
len
);
assert
(
retval
==
1
);
}
printf
(
"Deletion: %f
\n
"
,
(
double
)(
ustime
()
-
start
)
/
1000000
);
printf
(
"%llu total nodes
\n
"
,
(
unsigned
long
long
)
t
->
numnodes
);
printf
(
"%llu total elements
\n
"
,
(
unsigned
long
long
)
t
->
numele
);
raxFree
(
t
);
}
return
0
;
}
#endif
#ifdef TEST_MAIN
#include <stdio.h>
#include <time.h>
int
main
(
void
)
{
printf
(
"notfound = %p
\n
"
,
raxNotFound
);
rax
*
t
=
raxNew
();
char
*
toadd
[]
=
{
"alligator"
,
"alien"
,
"baloon"
,
"chromodynamic"
,
"romane"
,
"romanus"
,
"romulus"
,
"rubens"
,
"ruber"
,
"rubicon"
,
"rubicundus"
,
"all"
,
"rub"
,
"ba"
,
NULL
};
srand
(
time
(
NULL
));
for
(
int
x
=
0
;
x
<
10000
;
x
++
)
rand
();
long
items
=
0
;
while
(
toadd
[
items
]
!=
NULL
)
items
++
;
for
(
long
i
=
0
;
i
<
items
;
i
++
)
{
raxInsert
(
t
,(
unsigned
char
*
)
toadd
[
i
],
strlen
(
toadd
[
i
]),(
void
*
)
i
);
printf
(
"Added %s
\n
"
,
toadd
[
i
]);
}
raxShow
(
t
);
raxIterator
iter
;
raxStart
(
&
iter
,
t
);
// OK: all this tests will need to go in the Rax unit test.
// raxSeek(&iter,(unsigned char*)"rpxxx",5,"<=");
// raxSeek(&iter,(unsigned char*)"rom",3,">=");
// raxSeek(&iter,(unsigned char*)"rub",3,">=");
// raxSeek(&iter,(unsigned char*)"rub",3,">");
// raxSeek(&iter,(unsigned char*)"rub",3,"<");
// raxSeek(&iter,(unsigned char*)"rom",3,">");
// raxSeek(&iter,(unsigned char*)"chro",4,">");
// raxSeek(&iter,(unsigned char*)"chro",4,"<");
// raxSeek(&iter,(unsigned char*)"chromz",6,"<");
// raxSeek(&iter,NULL,0,"^");
// raxSeek(&iter,"zorro",5,"<=");
// raxSeek(&iter,"zorro",5,"<");
// raxSeek(&iter,NULL,0,"$");
// STILL TO TEST
raxSeek
(
&
iter
,(
unsigned
char
*
)
"ro"
,
2
,
">="
);
printf
(
"EOF: %d
\n
"
,
(
iter
.
flags
&
RAX_ITER_EOF
)
!=
0
);
printf
(
"SEEKED: %.*s, val %p
\n
"
,
(
int
)
iter
.
key_len
,
(
char
*
)
iter
.
key
,
iter
.
data
);
printf
(
"NEXT
\n
"
);
while
(
raxNext
(
&
iter
,
NULL
,
0
,
NULL
))
{
printf
(
"--- key: %.*s, val %p
\n
"
,
(
int
)
iter
.
key_len
,
(
char
*
)
iter
.
key
,
iter
.
data
);
}
printf
(
"After EOF element is: %.*s
\n
"
,
(
int
)
iter
.
key_len
,
(
char
*
)
iter
.
key
);
printf
(
"~~~~~~~~~~~~~~
\n
"
);
printf
(
"PREV
\n
"
);
raxSeek
(
&
iter
,
iter
.
key
,
iter
.
key_len
,
"=="
);
while
(
raxPrev
(
&
iter
,
NULL
,
0
,
NULL
))
{
printf
(
"--- key: %.*s, val %p
\n
"
,
(
int
)
iter
.
key_len
,
(
char
*
)
iter
.
key
,
iter
.
data
);
}
printf
(
"After EOF element is: %.*s
\n
"
,
(
int
)
iter
.
key_len
,
(
char
*
)
iter
.
key
);
raxStop
(
&
iter
);
#if 0
raxStop(&iter);
#endif
exit
(
0
);
int
rnum
=
rand
();
int
survivor
=
rnum
%
items
;
#if 1
printf
(
"Removing everything but %s in random order
\n
"
,
toadd
[
survivor
]);
for
(
long
i
=
0
;
i
<
1000
;
i
++
)
{
int
r
=
rand
()
%
items
;
if
(
r
==
survivor
)
continue
;
raxRemove
(
t
,(
unsigned
char
*
)
toadd
[
r
],
strlen
(
toadd
[
r
]));
}
#else
printf
(
"Removing rubicon
\n
"
);
raxRemove
(
t
,(
unsigned
char
*
)
"rubicon"
,
7
);
#endif
printf
(
"%llu total nodes
\n
"
,
(
unsigned
long
long
)
t
->
numnodes
);
printf
(
"%llu total elements
\n
"
,
(
unsigned
long
long
)
t
->
numele
);
raxShow
(
t
);
raxFree
(
t
);
}
#endif
src/rax.h
View file @
3f9e2322
...
@@ -144,14 +144,16 @@ extern void *raxNotFound;
...
@@ -144,14 +144,16 @@ extern void *raxNotFound;
/* Exported API. */
/* Exported API. */
rax
*
raxNew
(
void
);
rax
*
raxNew
(
void
);
int
raxInsert
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
*
data
);
int
raxInsert
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
*
data
,
void
**
old
);
int
raxRemove
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
);
int
raxRemove
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
,
void
**
old
);
void
*
raxFind
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
);
void
*
raxFind
(
rax
*
rax
,
unsigned
char
*
s
,
size_t
len
);
void
raxFree
(
rax
*
rax
);
void
raxFree
(
rax
*
rax
);
void
raxStart
(
raxIterator
*
it
,
rax
*
rt
);
void
raxStart
(
raxIterator
*
it
,
rax
*
rt
);
int
raxSeek
(
raxIterator
*
it
,
unsigned
char
*
ele
,
size_t
len
,
const
char
*
op
);
int
raxSeek
(
raxIterator
*
it
,
const
char
*
op
,
unsigned
char
*
ele
,
size_t
len
);
int
raxNext
(
raxIterator
*
it
,
unsigned
char
*
stop
,
size_t
stoplen
,
char
*
op
);
int
raxNext
(
raxIterator
*
it
);
int
raxPrev
(
raxIterator
*
it
,
unsigned
char
*
stop
,
size_t
stoplen
,
char
*
op
);
int
raxPrev
(
raxIterator
*
it
);
int
raxRandomWalk
(
raxIterator
*
it
,
size_t
steps
);
int
raxCompare
(
raxIterator
*
iter
,
const
char
*
op
,
unsigned
char
*
key
,
size_t
key_len
);
void
raxStop
(
raxIterator
*
it
);
void
raxStop
(
raxIterator
*
it
);
void
raxShow
(
rax
*
rax
);
void
raxShow
(
rax
*
rax
);
...
...
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