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
1259672f
Commit
1259672f
authored
Nov 03, 2009
by
antirez
Browse files
client libs removed from Redis git
parent
5762b7f0
Changes
110
Show whitespace changes
Inline
Side-by-side
client-libraries/cpp/test_client.cpp
deleted
100644 → 0
View file @
5762b7f0
#include "redisclient.h"
#include <iostream>
using
namespace
std
;
#define ASSERT_EQUAL(x,y) assert_equal(x, y, __LINE__)
#define ASSERT_NOT_EQUAL(x,y) assert_not_equal(x, y, __LINE__)
#define ASSERT_GT(x,y) assert_gt(x, y, __LINE__)
template
<
typename
T
>
void
assert_equal
(
const
T
&
actual
,
const
T
&
expected
,
int
lineno
)
{
#ifndef NDEBUG
cerr
<<
"assert_equal('"
<<
expected
<<
"', '"
<<
actual
<<
"')"
<<
endl
;
#endif
if
(
expected
!=
actual
)
{
cerr
<<
"expected '"
<<
expected
<<
"' got '"
<<
actual
<<
"'"
<<
endl
<<
"failing test called from line "
<<
lineno
<<
endl
;
exit
(
1
);
}
#ifndef NDEBUG
cerr
<<
"... OK"
<<
endl
;
#endif
}
template
<
typename
T
>
void
assert_not_equal
(
const
T
&
a
,
const
T
&
b
,
int
lineno
)
{
if
(
a
==
b
)
{
cerr
<<
"expected inequality"
<<
endl
<<
"failing test called from line "
<<
lineno
<<
endl
;
exit
(
1
);
}
}
template
<
typename
T
>
void
assert_gt
(
const
T
&
a
,
const
T
&
b
,
int
lineno
)
{
#ifndef NDEBUG
cerr
<<
"assert_gt('"
<<
a
<<
"', '"
<<
b
<<
"')"
<<
endl
;
#endif
if
(
a
<=
b
)
{
cerr
<<
"expected '"
<<
a
<<
"' > '"
<<
b
<<
"'"
<<
endl
<<
"failing test called from line "
<<
lineno
<<
endl
;
exit
(
1
);
}
#ifndef NDEBUG
cerr
<<
"... OK"
<<
endl
;
#endif
}
void
test
(
const
string
&
name
)
{
#ifndef NDEBUG
cerr
<<
"------------------------------"
<<
endl
<<
"starting test: "
<<
name
<<
endl
;
#endif
}
int
main
(
int
argc
,
char
**
argv
)
{
try
{
redis
::
client
c
;
// Test on high number databases
c
.
select
(
14
);
c
.
flushdb
();
c
.
select
(
15
);
c
.
flushdb
();
string
foo
(
"foo"
),
bar
(
"bar"
),
baz
(
"baz"
),
buz
(
"buz"
),
goo
(
"goo"
);
test
(
"auth"
);
{
// TODO ... needs a conf for redis-server
}
test
(
"info"
);
{
// doesn't throw? then, has valid numbers and known info-keys.
redis
::
server_info
info
;
c
.
info
(
info
);
}
test
(
"set, get"
);
{
c
.
set
(
foo
,
bar
);
ASSERT_EQUAL
(
c
.
get
(
foo
),
bar
);
}
test
(
"getset"
);
{
ASSERT_EQUAL
(
c
.
getset
(
foo
,
baz
),
bar
);
ASSERT_EQUAL
(
c
.
get
(
foo
),
baz
);
}
test
(
"mget"
);
{
string
x_val
(
"hello"
),
y_val
(
"world"
);
c
.
set
(
"x"
,
x_val
);
c
.
set
(
"y"
,
y_val
);
redis
::
client
::
string_vector
keys
;
keys
.
push_back
(
"x"
);
keys
.
push_back
(
"y"
);
redis
::
client
::
string_vector
vals
;
c
.
mget
(
keys
,
vals
);
ASSERT_EQUAL
(
vals
.
size
(),
size_t
(
2
));
ASSERT_EQUAL
(
vals
[
0
],
x_val
);
ASSERT_EQUAL
(
vals
[
1
],
y_val
);
}
test
(
"setnx"
);
{
ASSERT_EQUAL
(
c
.
setnx
(
foo
,
bar
),
false
);
ASSERT_EQUAL
(
c
.
setnx
(
buz
,
baz
),
true
);
ASSERT_EQUAL
(
c
.
get
(
buz
),
baz
);
}
test
(
"incr"
);
{
ASSERT_EQUAL
(
c
.
incr
(
"goo"
),
1L
);
test
(
"nonexistent (0) -> 1"
);
ASSERT_EQUAL
(
c
.
incr
(
"goo"
),
2L
);
test
(
"1->2"
);
}
test
(
"decr"
);
{
ASSERT_EQUAL
(
c
.
decr
(
"goo"
),
1L
);
test
(
"2->1"
);
ASSERT_EQUAL
(
c
.
decr
(
"goo"
),
0L
);
test
(
"1->0"
);
}
test
(
"incrby"
);
{
ASSERT_EQUAL
(
c
.
incrby
(
"goo"
,
3
),
3L
);
test
(
"0->3"
);
ASSERT_EQUAL
(
c
.
incrby
(
"goo"
,
2
),
5L
);
test
(
"3->5"
);
}
test
(
"exists"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"goo"
),
true
);
}
test
(
"del"
);
{
c
.
del
(
"goo"
);
ASSERT_EQUAL
(
c
.
exists
(
"goo"
),
false
);
}
test
(
"type (basic)"
);
{
ASSERT_EQUAL
(
c
.
type
(
goo
),
redis
::
client
::
datatype_none
);
test
(
"we deleted it"
);
c
.
set
(
goo
,
"redis"
);
ASSERT_EQUAL
(
c
.
type
(
goo
),
redis
::
client
::
datatype_string
);
}
test
(
"keys"
);
{
redis
::
client
::
string_vector
keys
;
ASSERT_EQUAL
(
c
.
keys
(
"*oo"
,
keys
),
2L
);
ASSERT_EQUAL
(
keys
.
size
(),
2UL
);
ASSERT_EQUAL
(
keys
[
0
],
foo
);
ASSERT_EQUAL
(
keys
[
1
],
goo
);
}
test
(
"randomkey"
);
{
ASSERT_GT
(
c
.
randomkey
().
size
(),
0UL
);
}
test
(
"rename"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"foo"
),
true
);
ASSERT_EQUAL
(
c
.
exists
(
"doo"
),
false
);
c
.
rename
(
"foo"
,
"doo"
);
ASSERT_EQUAL
(
c
.
exists
(
"foo"
),
false
);
ASSERT_EQUAL
(
c
.
exists
(
"doo"
),
true
);
}
test
(
"renamenx"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"doo"
),
true
);
ASSERT_EQUAL
(
c
.
exists
(
"foo"
),
false
);
ASSERT_EQUAL
(
c
.
renamenx
(
"doo"
,
"foo"
),
true
);
ASSERT_EQUAL
(
c
.
exists
(
"doo"
),
false
);
ASSERT_EQUAL
(
c
.
exists
(
"foo"
),
true
);
ASSERT_EQUAL
(
c
.
renamenx
(
"goo"
,
"foo"
),
false
);
ASSERT_EQUAL
(
c
.
exists
(
"foo"
),
true
);
ASSERT_EQUAL
(
c
.
exists
(
"goo"
),
true
);
}
test
(
"dbsize"
);
{
ASSERT_GT
(
c
.
dbsize
(),
0L
);
}
test
(
"expire"
);
{
c
.
expire
(
"goo"
,
1
);
#ifndef NDEBUG
cerr
<<
"please wait a few seconds.."
<<
endl
;
#endif
sleep
(
2
);
ASSERT_EQUAL
(
c
.
exists
(
"goo"
),
false
);
}
test
(
"rpush"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
false
);
c
.
rpush
(
"list1"
,
"val1"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
ASSERT_EQUAL
(
c
.
type
(
"list1"
),
redis
::
client
::
datatype_list
);
c
.
rpush
(
"list1"
,
"val2"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"val1"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"val2"
));
}
test
(
"lpush"
);
{
c
.
del
(
"list1"
);
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
false
);
c
.
lpush
(
"list1"
,
"val1"
);
ASSERT_EQUAL
(
c
.
type
(
"list1"
),
redis
::
client
::
datatype_list
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
c
.
lpush
(
"list1"
,
"val2"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"val2"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"val1"
));
}
test
(
"llen"
);
{
c
.
del
(
"list1"
);
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
false
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
0L
);
c
.
lpush
(
"list1"
,
"x"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
c
.
lpush
(
"list1"
,
"y"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
}
test
(
"lrange"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
true
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
redis
::
client
::
string_vector
vals
;
ASSERT_EQUAL
(
c
.
lrange
(
"list1"
,
0
,
-
1
,
vals
),
2L
);
ASSERT_EQUAL
(
vals
.
size
(),
2UL
);
ASSERT_EQUAL
(
vals
[
0
],
string
(
"y"
));
ASSERT_EQUAL
(
vals
[
1
],
string
(
"x"
));
}
test
(
"lrange with subset of full list"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
true
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
redis
::
client
::
string_vector
vals
;
ASSERT_EQUAL
(
c
.
lrange
(
"list1"
,
0
,
1
,
vals
),
2L
);
// inclusive, so entire list
ASSERT_EQUAL
(
vals
.
size
(),
2UL
);
ASSERT_EQUAL
(
vals
[
0
],
string
(
"y"
));
ASSERT_EQUAL
(
vals
[
1
],
string
(
"x"
));
redis
::
client
::
string_vector
vals2
;
ASSERT_EQUAL
(
c
.
lrange
(
"list1"
,
0
,
0
,
vals2
),
1L
);
// inclusive, so first item
ASSERT_EQUAL
(
vals2
.
size
(),
1UL
);
ASSERT_EQUAL
(
vals2
[
0
],
string
(
"y"
));
redis
::
client
::
string_vector
vals3
;
ASSERT_EQUAL
(
c
.
lrange
(
"list1"
,
-
1
,
-
1
,
vals3
),
1L
);
// inclusive, so first item
ASSERT_EQUAL
(
vals3
.
size
(),
1UL
);
ASSERT_EQUAL
(
vals3
[
0
],
string
(
"x"
));
}
test
(
"get_list"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
true
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
redis
::
client
::
string_vector
vals
;
ASSERT_EQUAL
(
c
.
get_list
(
"list1"
,
vals
),
2L
);
ASSERT_EQUAL
(
vals
.
size
(),
2UL
);
ASSERT_EQUAL
(
vals
[
0
],
string
(
"y"
));
ASSERT_EQUAL
(
vals
[
1
],
string
(
"x"
));
}
test
(
"ltrim"
);
{
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
true
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
c
.
ltrim
(
"list1"
,
0
,
0
);
ASSERT_EQUAL
(
c
.
exists
(
"list1"
),
true
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
redis
::
client
::
string_vector
vals
;
ASSERT_EQUAL
(
c
.
get_list
(
"list1"
,
vals
),
1L
);
ASSERT_EQUAL
(
vals
[
0
],
string
(
"y"
));
}
test
(
"lindex"
);
{
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
c
.
rpush
(
"list1"
,
"x"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
-
1
),
string
(
"x"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"x"
));
}
test
(
"lset"
);
{
c
.
lset
(
"list1"
,
1
,
"z"
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"z"
));
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
}
test
(
"lrem"
);
{
c
.
lrem
(
"list1"
,
1
,
"z"
);
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
// list1 = [ y ]
ASSERT_EQUAL
(
c
.
lrem
(
"list1"
,
0
,
"q"
),
0L
);
c
.
rpush
(
"list1"
,
"z"
);
c
.
rpush
(
"list1"
,
"z"
);
c
.
rpush
(
"list1"
,
"z"
);
c
.
rpush
(
"list1"
,
"a"
);
// list1 = [ y, z, z, z, a ]
ASSERT_EQUAL
(
c
.
lrem
(
"list1"
,
2
,
"z"
),
2L
);
// list1 = [ y, z, a ]
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
3L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"z"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
2
),
string
(
"a"
));
c
.
rpush
(
"list1"
,
"z"
);
// list1 = [ y, z, a, z ]
ASSERT_EQUAL
(
c
.
lrem
(
"list1"
,
-
1
,
"z"
),
1L
);
// <0 => rm R to L
// list1 = [ y, z, a ]
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
3L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"z"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
2
),
string
(
"a"
));
// list1 = [ y, z, a ]
// try to remove 5 'a's but there's only 1 ... no problem.
ASSERT_EQUAL
(
c
.
lrem
(
"list1"
,
5
,
"a"
),
1L
);
// list1 = [ y, z ]
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
2L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
1
),
string
(
"z"
));
}
test
(
"lrem_exact"
);
{
// list1 = [ y, z ]
// try to remove 5 'z's but there's only 1 ... now it's a problem.
bool
threw
=
false
;
try
{
c
.
lrem_exact
(
"list1"
,
5
,
"z"
);
}
catch
(
redis
::
value_error
&
e
)
{
threw
=
true
;
}
ASSERT_EQUAL
(
threw
,
true
);
// This DOES remove the one 'z' though
// list1 = [ y ]
ASSERT_EQUAL
(
c
.
llen
(
"list1"
),
1L
);
ASSERT_EQUAL
(
c
.
lindex
(
"list1"
,
0
),
string
(
"y"
));
}
test
(
"lpop"
);
{
ASSERT_EQUAL
(
c
.
lpop
(
"list1"
),
string
(
"y"
));
// list1 = []
ASSERT_EQUAL
(
c
.
lpop
(
"list1"
),
redis
::
client
::
missing_value
);
}
test
(
"rpop"
);
{
c
.
rpush
(
"list1"
,
"hello"
);
c
.
rpush
(
"list1"
,
"world"
);
ASSERT_EQUAL
(
c
.
rpop
(
"list1"
),
string
(
"world"
));
ASSERT_EQUAL
(
c
.
rpop
(
"list1"
),
string
(
"hello"
));
ASSERT_EQUAL
(
c
.
lpop
(
"list1"
),
redis
::
client
::
missing_value
);
}
test
(
"sadd"
);
{
c
.
sadd
(
"set1"
,
"sval1"
);
ASSERT_EQUAL
(
c
.
exists
(
"set1"
),
true
);
ASSERT_EQUAL
(
c
.
type
(
"set1"
),
redis
::
client
::
datatype_set
);
ASSERT_EQUAL
(
c
.
sismember
(
"set1"
,
"sval1"
),
true
);
}
test
(
"srem"
);
{
c
.
srem
(
"set1"
,
"sval1"
);
ASSERT_EQUAL
(
c
.
exists
(
"set1"
),
true
);
ASSERT_EQUAL
(
c
.
type
(
"set1"
),
redis
::
client
::
datatype_set
);
ASSERT_EQUAL
(
c
.
sismember
(
"set1"
,
"sval1"
),
false
);
}
test
(
"smove"
);
{
c
.
sadd
(
"set1"
,
"hi"
);
// set1 = { hi }
ASSERT_EQUAL
(
c
.
exists
(
"set2"
),
false
);
c
.
smove
(
"set1"
,
"set2"
,
"hi"
);
ASSERT_EQUAL
(
c
.
sismember
(
"set1"
,
"hi"
),
false
);
ASSERT_EQUAL
(
c
.
sismember
(
"set2"
,
"hi"
),
true
);
}
test
(
"scard"
);
{
ASSERT_EQUAL
(
c
.
scard
(
"set1"
),
0L
);
ASSERT_EQUAL
(
c
.
scard
(
"set2"
),
1L
);
}
test
(
"sismember"
);
{
// see above
}
test
(
"smembers"
);
{
c
.
sadd
(
"set2"
,
"bye"
);
redis
::
client
::
string_set
members
;
ASSERT_EQUAL
(
c
.
smembers
(
"set2"
,
members
),
2L
);
ASSERT_EQUAL
(
members
.
size
(),
2UL
);
ASSERT_NOT_EQUAL
(
members
.
find
(
"hi"
),
members
.
end
());
ASSERT_NOT_EQUAL
(
members
.
find
(
"bye"
),
members
.
end
());
}
test
(
"sinter"
);
{
c
.
sadd
(
"set3"
,
"bye"
);
c
.
sadd
(
"set3"
,
"bye2"
);
redis
::
client
::
string_vector
keys
;
keys
.
push_back
(
"set2"
);
keys
.
push_back
(
"set3"
);
redis
::
client
::
string_set
intersection
;
ASSERT_EQUAL
(
c
.
sinter
(
keys
,
intersection
),
1L
);
ASSERT_EQUAL
(
intersection
.
size
(),
1UL
);
ASSERT_NOT_EQUAL
(
intersection
.
find
(
"bye"
),
intersection
.
end
());
}
test
(
"sinterstore"
);
{
c
.
sadd
(
"seta"
,
"1"
);
c
.
sadd
(
"seta"
,
"2"
);
c
.
sadd
(
"seta"
,
"3"
);
c
.
sadd
(
"setb"
,
"2"
);
c
.
sadd
(
"setb"
,
"3"
);
c
.
sadd
(
"setb"
,
"4"
);
redis
::
client
::
string_vector
keys
;
keys
.
push_back
(
"seta"
);
keys
.
push_back
(
"setb"
);
ASSERT_EQUAL
(
c
.
sinterstore
(
"setc"
,
keys
),
2L
);
redis
::
client
::
string_set
members
;
ASSERT_EQUAL
(
c
.
smembers
(
"setc"
,
members
),
2L
);
ASSERT_EQUAL
(
members
.
size
(),
2UL
);
ASSERT_NOT_EQUAL
(
members
.
find
(
"2"
),
members
.
end
());
ASSERT_NOT_EQUAL
(
members
.
find
(
"3"
),
members
.
end
());
}
test
(
"sunion"
);
{
c
.
sadd
(
"setd"
,
"1"
);
c
.
sadd
(
"sete"
,
"2"
);
redis
::
client
::
string_vector
keys
;
keys
.
push_back
(
"setd"
);
keys
.
push_back
(
"sete"
);
redis
::
client
::
string_set
a_union
;
ASSERT_EQUAL
(
c
.
sunion
(
keys
,
a_union
),
2L
);
ASSERT_EQUAL
(
a_union
.
size
(),
2UL
);
ASSERT_NOT_EQUAL
(
a_union
.
find
(
"1"
),
a_union
.
end
());
ASSERT_NOT_EQUAL
(
a_union
.
find
(
"2"
),
a_union
.
end
());
}
test
(
"sunionstore"
);
{
c
.
sadd
(
"setf"
,
"1"
);
c
.
sadd
(
"setg"
,
"2"
);
redis
::
client
::
string_vector
keys
;
keys
.
push_back
(
"setf"
);
keys
.
push_back
(
"setg"
);
ASSERT_EQUAL
(
c
.
sunionstore
(
"seth"
,
keys
),
2L
);
redis
::
client
::
string_set
members
;
ASSERT_EQUAL
(
c
.
smembers
(
"seth"
,
members
),
2L
);
ASSERT_EQUAL
(
members
.
size
(),
2UL
);
ASSERT_NOT_EQUAL
(
members
.
find
(
"1"
),
members
.
end
());
ASSERT_NOT_EQUAL
(
members
.
find
(
"2"
),
members
.
end
());
}
test
(
"move"
);
{
c
.
select
(
14
);
ASSERT_EQUAL
(
c
.
exists
(
"ttt"
),
false
);
c
.
select
(
15
);
c
.
set
(
"ttt"
,
"uuu"
);
c
.
move
(
"ttt"
,
14
);
c
.
select
(
14
);
ASSERT_EQUAL
(
c
.
exists
(
"ttt"
),
true
);
c
.
select
(
15
);
ASSERT_EQUAL
(
c
.
exists
(
"ttt"
),
false
);
}
test
(
"move should fail since key exists already"
);
{
c
.
select
(
14
);
c
.
set
(
"ttt"
,
"xxx"
);
c
.
select
(
15
);
c
.
set
(
"ttt"
,
"uuu"
);
bool
threw
=
false
;
try
{
c
.
move
(
"ttt"
,
14
);
}
catch
(
redis
::
protocol_error
&
e
)
{
threw
=
true
;
}
ASSERT_EQUAL
(
threw
,
true
);
c
.
select
(
14
);
ASSERT_EQUAL
(
c
.
exists
(
"ttt"
),
true
);
c
.
select
(
15
);
ASSERT_EQUAL
(
c
.
exists
(
"ttt"
),
true
);
}
test
(
"sort ascending"
);
{
c
.
sadd
(
"sort1"
,
"3"
);
c
.
sadd
(
"sort1"
,
"2"
);
c
.
sadd
(
"sort1"
,
"1"
);
redis
::
client
::
string_vector
sorted
;
ASSERT_EQUAL
(
c
.
sort
(
"sort1"
,
sorted
),
3L
);
ASSERT_EQUAL
(
sorted
.
size
(),
3UL
);
ASSERT_EQUAL
(
sorted
[
0
],
string
(
"1"
));
ASSERT_EQUAL
(
sorted
[
1
],
string
(
"2"
));
ASSERT_EQUAL
(
sorted
[
2
],
string
(
"3"
));
}
test
(
"sort descending"
);
{
redis
::
client
::
string_vector
sorted
;
ASSERT_EQUAL
(
c
.
sort
(
"sort1"
,
sorted
,
redis
::
client
::
sort_order_descending
),
3L
);
ASSERT_EQUAL
(
sorted
.
size
(),
3UL
);
ASSERT_EQUAL
(
sorted
[
0
],
string
(
"3"
));
ASSERT_EQUAL
(
sorted
[
1
],
string
(
"2"
));
ASSERT_EQUAL
(
sorted
[
2
],
string
(
"1"
));
}
test
(
"sort with limit"
);
{
// TODO
}
test
(
"sort lexicographically"
);
{
// TODO
}
test
(
"sort with pattern and weights"
);
{
// TODO
}
test
(
"save"
);
{
c
.
save
();
}
test
(
"bgsave"
);
{
c
.
bgsave
();
}
test
(
"lastsave"
);
{
ASSERT_GT
(
c
.
lastsave
(),
0L
);
}
test
(
"shutdown"
);
{
// You can test this if you really want to ...
// c.shutdown();
}
}
catch
(
redis
::
redis_error
&
e
)
{
cerr
<<
"got exception: "
<<
string
(
e
)
<<
endl
<<
"FAIL"
<<
endl
;
return
1
;
}
cout
<<
endl
<<
"testing completed successfully"
<<
endl
;
return
0
;
}
client-libraries/erlang/.hg_archival.txt
deleted
100644 → 0
View file @
5762b7f0
repo: 9e1f35ed7fdc7b3da7f5ff66a71d1975b85e2ae5
node: 85e28ca5597e22ff1dde18ed4625f41923128993
client-libraries/erlang/.hgignore
deleted
100644 → 0
View file @
5762b7f0
syntax: glob
*.beam
\ No newline at end of file
client-libraries/erlang/LICENSE
deleted
100644 → 0
View file @
5762b7f0
Copyright (c) 2009
adroll.com
Valentino Volonghi
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
client-libraries/erlang/Makefile
deleted
100644 → 0
View file @
5762b7f0
LIBDIR
=
`
erl
-eval
'io:format("~s~n", [code:lib_dir()])'
-s
init stop
-noshell
`
all
:
mkdir
-p
ebin/
(
cd
src
;
$(MAKE)
)
(
cd test
;
$(MAKE)
)
clean
:
clean_tests
(
cd
src
;
$(MAKE)
clean
)
rm
-rf
erl_crash.dump
*
.beam
clean_tests
:
(
cd test
;
$(MAKE)
clean
)
rm
-rf
erl_crash.dump
*
.beam
test
:
clean
mkdir
-p
ebin/
(
cd
src
;
$(MAKE)
)
(
cd test
;
$(MAKE)
)
(
cd test
;
$(MAKE)
test
)
testrun
:
all
mkdir
-p
ebin/
(
cd test
;
$(MAKE)
test
)
install
:
all
mkdir
-p
${LIBDIR}
/erldis-0.0.1/
{
ebin,include
}
for
i
in
ebin/
*
.beam
;
do
install
$$
i
$(LIBDIR)
/erldis-0.0.1/
$$
i
;
done
for
i
in
include/
*
.hrl
;
do
install
$$
i
$(LIBDIR)
/erldis-0.0.1/
$$
i
;
done
client-libraries/erlang/include/erldis.hrl
deleted
100644 → 0
View file @
5762b7f0
-
record
(
redis
,
{
socket
,
buffer
=
[],
reply_caller
,
calls
=
0
,
remaining
=
0
,
pstate
=
empty
,
results
=
[]}).
client-libraries/erlang/src/Makefile
deleted
100644 → 0
View file @
5762b7f0
include
../support/include.mk
all
:
$(EBIN_FILES)
debug
:
$(MAKE)
DEBUG
=
-DDEBUG
clean
:
rm
-rf
$(EBIN_FILES)
erl_crash.dump
client-libraries/erlang/src/client.erl
deleted
100644 → 0
View file @
5762b7f0
-
module
(
client
).
-
behavior
(
gen_server
).
-
export
([
start
/
1
,
start
/
2
,
connect
/
1
,
connect
/
2
,
asend
/
2
,
send
/
3
,
send
/
2
,
disconnect
/
1
,
ssend
/
3
,
str
/
1
,
format
/
1
,
sformat
/
1
,
ssend
/
2
,
get_all_results
/
1
]).
-
export
([
init
/
1
,
handle_call
/
3
,
handle_cast
/
2
,
handle_info
/
2
,
terminate
/
2
,
code_change
/
3
]).
-
include
(
"erldis.hrl"
).
-
define
(
EOL
,
"
\r\n
"
).
%% Helpers
str
(
X
)
when
is_list
(
X
)
->
X
;
str
(
X
)
when
is_atom
(
X
)
->
atom_to_list
(
X
);
str
(
X
)
when
is_binary
(
X
)
->
binary_to_list
(
X
);
str
(
X
)
when
is_integer
(
X
)
->
integer_to_list
(
X
);
str
(
X
)
when
is_float
(
X
)
->
float_to_list
(
X
).
format
([],
Result
)
->
string
:
join
(
lists
:
reverse
(
Result
),
?
EOL
);
format
([
Line
|
Rest
],
Result
)
->
JoinedLine
=
string
:
join
([
str
(
X
)
||
X
<-
Line
],
" "
),
format
(
Rest
,
[
JoinedLine
|
Result
]).
format
(
Lines
)
->
format
(
Lines
,
[]).
sformat
(
Line
)
->
format
([
Line
],
[]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Exported API
start
(
Host
)
->
connect
(
Host
).
start
(
Host
,
Port
)
->
connect
(
Host
,
Port
).
connect
(
Host
)
->
connect
(
Host
,
6379
).
connect
(
Host
,
Port
)
->
gen_server
:
start_link
(
?
MODULE
,
[
Host
,
Port
],
[]).
% This is the simple send with a single row of commands
ssend
(
Client
,
Cmd
)
->
ssend
(
Client
,
Cmd
,
[]).
ssend
(
Client
,
Cmd
,
Args
)
->
gen_server
:
cast
(
Client
,
{
send
,
sformat
([
Cmd
|
Args
])}).
% This is the complete send with multiple rows
send
(
Client
,
Cmd
)
->
send
(
Client
,
Cmd
,
[]).
send
(
Client
,
Cmd
,
Args
)
->
gen_server
:
cast
(
Client
,
{
send
,
string
:
join
([
str
(
Cmd
),
format
(
Args
)],
" "
)}).
% asynchronous send, we don't care about the result.
asend
(
Client
,
Cmd
)
->
gen_server
:
cast
(
Client
,
{
asend
,
Cmd
}).
disconnect
(
Client
)
->
gen_server
:
call
(
Client
,
disconnect
).
get_all_results
(
Client
)
->
gen_server
:
call
(
Client
,
get_all_results
).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% gen_server callbacks
init
([
Host
,
Port
])
->
process_flag
(
trap_exit
,
true
),
ConnectOptions
=
[
list
,
{
active
,
once
},
{
packet
,
line
},
{
nodelay
,
true
}],
case
gen_tcp
:
connect
(
Host
,
Port
,
ConnectOptions
)
of
{
error
,
Why
}
->
{
error
,
{
socket_error
,
Why
}};
{
ok
,
Socket
}
->
{
ok
,
#redis
{
socket
=
Socket
,
calls
=
0
}}
end
.
handle_call
({
send
,
Cmd
},
From
,
State
)
->
gen_tcp
:
send
(
State
#redis.socket
,
[
Cmd
|
?
EOL
]),
{
noreply
,
State
#redis
{
reply_caller
=
fun
(
V
)
->
gen_server
:
reply
(
From
,
lists
:
nth
(
1
,
V
))
end
,
remaining
=
1
}};
handle_call
(
disconnect
,
_
From
,
State
)
->
{
stop
,
normal
,
ok
,
State
};
handle_call
(
get_all_results
,
From
,
State
)
->
case
State
#redis.calls
of
0
->
% answers came earlier than we could start listening...
% Very unlikely but totally possible.
{
reply
,
lists
:
reverse
(
State
#redis.results
),
State
#redis
{
results
=
[],
calls
=
0
}};
_
->
% We are here earlier than results came, so just make
% ourselves wait until stuff is ready.
{
noreply
,
State
#redis
{
reply_caller
=
fun
(
V
)
->
gen_server
:
reply
(
From
,
V
)
end
}}
end
;
handle_call
(_,
_
From
,
State
)
->
{
noreply
,
State
}.
handle_cast
({
asend
,
Cmd
},
State
)
->
gen_tcp
:
send
(
State
#redis.socket
,
[
Cmd
|
?
EOL
]),
{
noreply
,
State
};
handle_cast
({
send
,
Cmd
},
State
=
#redis
{
remaining
=
Remaining
,
calls
=
Calls
})
->
% how we should do here: if remaining is already != 0 then we'll
% let handle_info take care of keeping track how many remaining things
% there are. If instead it's 0 we are the first call so let's just
% do it.
gen_tcp
:
send
(
State
#redis.socket
,
[
Cmd
|
?
EOL
]),
case
Remaining
of
0
->
{
noreply
,
State
#redis
{
remaining
=
1
,
calls
=
1
}};
_
->
{
noreply
,
State
#redis
{
calls
=
Calls
+
1
}}
end
;
handle_cast
(_
Msg
,
State
)
->
{
noreply
,
State
}.
trim2
({
ok
,
S
})
->
string
:
substr
(
S
,
1
,
length
(
S
)
-
2
);
trim2
(
S
)
->
trim2
({
ok
,
S
}).
% This function helps with pipelining by creating a pubsub system with
% the caller. The caller could submit multiple requests and not listen
% until later when all or some of them have been answered, at that
% point 2 conditions can be true:
% 1) We still need to process more things in this response chain
% 2) We are finished.
%
% And these 2 are together with the following 2:
% 1) We called get_all_results before the end of the responses.
% 2) We called get_all_results after the end of the responses.
%
% If there's stuff missing in the chain we just push results, this also
% happens when there's nothing more to process BUT we haven't requested
% results yet.
% In case we have requested results: if requests are not yet ready we
% just push them, otherwise we finally answer all of them.
save_or_reply
(
Result
,
State
=
#redis
{
calls
=
Calls
,
results
=
Results
,
reply_caller
=
ReplyCaller
})
->
case
Calls
of
0
->
% We don't reverse results here because if all the requests
% come in and then we submit another one, if we reverse
% they will be scrambled in the results field of the record.
% instead if we wait just before we reply they will be
% in the right order.
FullResults
=
[
Result
|
Results
],
NewState
=
case
ReplyCaller
of
undefined
->
State
#redis
{
results
=
FullResults
};
_
->
ReplyCaller
(
lists
:
reverse
(
FullResults
)),
State
#redis
{
results
=
[]}
end
,
NewState
#redis
{
remaining
=
0
,
pstate
=
empty
,
reply_caller
=
undefined
,
buffer
=
[],
calls
=
0
};
_
->
State
#redis
{
results
=
[
Result
|
Results
],
remaining
=
1
,
pstate
=
empty
,
buffer
=
[],
calls
=
Calls
}
end
.
handle_info
({
tcp
,
Socket
,
Data
},
State
=
#redis
{
calls
=
Calls
})
->
Trimmed
=
trim2
(
Data
),
NewState
=
case
{
State
#redis.remaining
-
1
,
proto
:
parse
(
State
#redis.pstate
,
Trimmed
)}
of
% This line contained an error code. Next line will hold
% The error message that we will parse.
{
0
,
error
}
->
State
#redis
{
remaining
=
1
,
pstate
=
error
};
% The stateful parser just started and tells us the number
% of results that we will have to parse for those calls
% where more than one result is expected. The next
% line will start with the first item to read.
{
0
,
{
hold
,
Remaining
}}
->
case
Remaining
of
nil
->
save_or_reply
(
nil
,
State
#redis
{
calls
=
Calls
-
1
});
_
->
% Reset the remaining value to the number of results that we need to parse.
State
#redis
{
remaining
=
Remaining
,
pstate
=
read
}
end
;
% We either had only one thing to read or we are at the
% end of the stuff that we need to read. either way
% just pack up the buffer and send.
{
0
,
{
read
,
NBytes
}}
->
CurrentValue
=
case
NBytes
of
nil
->
nil
;
_
->
inet
:
setopts
(
Socket
,
[{
packet
,
0
}]),
% go into raw mode to read bytes
CV
=
trim2
(
gen_tcp
:
recv
(
Socket
,
NBytes
+
2
)),
% also consume the \r\n
inet
:
setopts
(
Socket
,
[{
packet
,
line
}]),
% go back to line mode
CV
end
,
OldBuffer
=
State
#redis.buffer
,
case
OldBuffer
of
[]
->
save_or_reply
(
CurrentValue
,
State
#redis
{
calls
=
Calls
-
1
});
_
->
save_or_reply
(
lists
:
reverse
([
CurrentValue
|
OldBuffer
]),
State
#redis
{
calls
=
Calls
-
1
})
end
;
% The stateful parser tells us to read some bytes
{
N
,
{
read
,
NBytes
}}
->
% annoying repetition... I should reuse this code.
CurrentValue
=
case
NBytes
of
nil
->
nil
;
_
->
inet
:
setopts
(
Socket
,
[{
packet
,
0
}]),
% go into raw mode to read bytes
CV
=
trim2
(
gen_tcp
:
recv
(
Socket
,
NBytes
+
2
)),
% also consume the \r\n
inet
:
setopts
(
Socket
,
[{
packet
,
line
}]),
% go back to line mode
CV
end
,
OldBuffer
=
State
#redis.buffer
,
State
#redis
{
remaining
=
N
,
buffer
=
[
CurrentValue
|
OldBuffer
],
pstate
=
read
};
% Simple return values contained in a single line
{
0
,
Value
}
->
save_or_reply
(
Value
,
State
#redis
{
calls
=
Calls
-
1
})
end
,
inet
:
setopts
(
Socket
,
[{
active
,
once
}]),
{
noreply
,
NewState
};
handle_info
(_
Info
,
State
)
->
{
noreply
,
State
}.
terminate
(_
Reason
,
State
)
->
case
State
#redis.socket
of
undefined
->
pass
;
Socket
->
gen_tcp
:
close
(
Socket
)
end
,
ok
.
code_change
(_
OldVsn
,
State
,
_
Extra
)
->
{
ok
,
State
}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
client-libraries/erlang/src/erldis.erl
deleted
100644 → 0
View file @
5762b7f0
-
module
(
erldis
).
-
compile
(
export_all
).
-
define
(
EOL
,
"
\r\n
"
).
%% helpers
flatten
({
error
,
Message
})
->
{
error
,
Message
};
flatten
(
List
)
when
is_list
(
List
)
->
lists
:
flatten
(
List
).
%% exposed API
connect
(
Host
)
->
client
:
connect
(
Host
).
quit
(
Client
)
->
client
:
asend
(
Client
,
"QUIT"
),
client
:
disconnect
(
Client
).
%% Commands operating on string values
internal_set_like
(
Client
,
Command
,
Key
,
Value
)
->
client
:
send
(
Client
,
Command
,
[[
Key
,
length
(
Value
)],
[
Value
]]).
get_all_results
(
Client
)
->
client
:
get_all_results
(
Client
).
auth
(
Client
,
Password
)
->
client
:
ssend
(
Client
,
auth
,
[
Password
]).
set
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
set
,
Key
,
Value
).
get
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
get
,
[
Key
]).
getset
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
getset
,
Key
,
Value
).
mget
(
Client
,
Keys
)
->
client
:
ssend
(
Client
,
mget
,
Keys
).
setnx
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
setnx
,
Key
,
Value
).
incr
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
incr
,
[
Key
]).
incrby
(
Client
,
Key
,
By
)
->
client
:
ssend
(
Client
,
incrby
,
[
Key
,
By
]).
decr
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
decr
,
[
Key
]).
decrby
(
Client
,
Key
,
By
)
->
client
:
ssend
(
Client
,
decrby
,
[
Key
,
By
]).
%% Commands operating on every value
exists
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
exists
,
[
Key
]).
del
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
del
,
[
Key
]).
type
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
type
,
[
Key
]).
keys
(
Client
,
Pattern
)
->
client
:
ssend
(
Client
,
keys
,
[
Pattern
]).
randomkey
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
randomkey
,
[
Key
]).
rename
(
Client
,
OldKey
,
NewKey
)
->
client
:
ssend
(
Client
,
rename
,
[
OldKey
,
NewKey
]).
renamenx
(
Client
,
OldKey
,
NewKey
)
->
client
:
ssend
(
Client
,
renamenx
,
[
OldKey
,
NewKey
]).
dbsize
(
Client
)
->
client
:
ssend
(
Client
,
dbsize
).
expire
(
Client
,
Key
,
Seconds
)
->
client
:
ssend
(
Client
,
expire
,
[
Key
,
Seconds
]).
ttl
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
ttl
,
[
Key
]).
%% Commands operating on lists
rpush
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
rpush
,
Key
,
Value
).
lpush
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
lpush
,
Key
,
Value
).
llen
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
llen
,
[
Key
]).
lrange
(
Client
,
Key
,
Start
,
End
)
->
client
:
ssend
(
Client
,
lrange
,
[
Key
,
Start
,
End
]).
ltrim
(
Client
,
Key
,
Start
,
End
)
->
client
:
ssend
(
Client
,
ltrim
,
[
Key
,
Start
,
End
]).
lindex
(
Client
,
Key
,
Index
)
->
client
:
ssend
(
Client
,
lindex
,
[
Key
,
Index
]).
lset
(
Client
,
Key
,
Index
,
Value
)
->
client
:
send
(
Client
,
lset
,
[[
Key
,
Index
,
length
(
Value
)],
[
Value
]]).
lrem
(
Client
,
Key
,
Number
,
Value
)
->
client
:
send
(
Client
,
lrem
,
[[
Key
,
Number
,
length
(
Value
)],
[
Value
]]).
lpop
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
lpop
,
[
Key
]).
rpop
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
rpop
,
[
Key
]).
%% Commands operating on sets
sadd
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
sadd
,
Key
,
Value
).
srem
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
srem
,
Key
,
Value
).
smove
(
Client
,
SrcKey
,
DstKey
,
Member
)
->
client
:
send
(
Client
,
smove
,
[[
SrcKey
,
DstKey
,
length
(
Member
)],
[
Member
]]).
scard
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
scard
,
[
Key
]).
sismember
(
Client
,
Key
,
Value
)
->
internal_set_like
(
Client
,
sismember
,
Key
,
Value
).
sintersect
(
Client
,
Keys
)
->
client
:
ssend
(
Client
,
sinter
,
Keys
).
sinter
(
Client
,
Keys
)
->
sintersect
(
Client
,
Keys
).
sinterstore
(
Client
,
DstKey
,
Keys
)
->
client
:
ssend
(
Client
,
sinterstore
,
[
DstKey
|
Keys
]).
sunion
(
Client
,
Keys
)
->
client
:
ssend
(
Client
,
sunion
,
Keys
).
sunionstore
(
Client
,
DstKey
,
Keys
)
->
client
:
ssend
(
Client
,
sunionstore
,
[
DstKey
|
Keys
]).
sdiff
(
Client
,
Keys
)
->
client
:
ssend
(
Client
,
sdiff
,
Keys
).
sdiffstore
(
Client
,
DstKey
,
Keys
)
->
client
:
ssend
(
Client
,
sdiffstore
,
[
DstKey
|
Keys
]).
smembers
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
smembers
,
[
Key
]).
%% Multiple DB commands
select
(
Client
,
Index
)
->
client
:
ssend
(
Client
,
select
,
[
Index
]).
move
(
Client
,
Key
,
DBIndex
)
->
client
:
ssend
(
Client
,
move
,
[
Key
,
DBIndex
]).
flushdb
(
Client
)
->
client
:
ssend
(
Client
,
flushdb
).
flushall
(
Client
)
->
client
:
ssend
(
Client
,
flushall
).
%% Commands operating on both lists and sets
sort
(
Client
,
Key
)
->
client
:
ssend
(
Client
,
sort
,
[
Key
]).
sort
(
Client
,
Key
,
Extra
)
->
client
:
ssend
(
Client
,
sort
,
[
Key
,
Extra
]).
%% Persistence control commands
save
(
Client
)
->
client
:
ssend
(
Client
,
save
).
bgsave
(
Client
)
->
client
:
ssend
(
Client
,
bgsave
).
lastsave
(
Client
)
->
client
:
ssend
(
Client
,
lastsave
).
shutdown
(
Client
)
->
client
:
asend
(
Client
,
shutdown
).
%% Remote server control commands
info
(
Client
)
->
client
:
ssend
(
Client
,
info
).
slaveof
(
Client
,
Host
,
Port
)
->
client
:
ssend
(
Client
,
slaveof
,
[
Host
,
Port
]).
slaveof
(
Client
)
->
client
:
ssend
(
Client
,
slaveof
,
[
"no one"
]).
client-libraries/erlang/src/proto.erl
deleted
100644 → 0
View file @
5762b7f0
-
module
(
proto
).
-
export
([
parse
/
2
]).
parse
(
empty
,
"+OK"
)
->
ok
;
parse
(
empty
,
"+PONG"
)
->
pong
;
parse
(
empty
,
":0"
)
->
false
;
parse
(
empty
,
":1"
)
->
true
;
parse
(
empty
,
"-"
++
Message
)
->
{
error
,
Message
};
parse
(
empty
,
"$-1"
)
->
{
read
,
nil
};
parse
(
empty
,
"*-1"
)
->
{
hold
,
nil
};
parse
(
empty
,
"$"
++
BulkSize
)
->
{
read
,
list_to_integer
(
BulkSize
)};
parse
(
read
,
"$"
++
BulkSize
)
->
{
read
,
list_to_integer
(
BulkSize
)};
parse
(
empty
,
"*"
++
MultiBulkSize
)
->
{
hold
,
list_to_integer
(
MultiBulkSize
)};
parse
(
empty
,
Message
)
->
convert
(
Message
).
convert
(
":"
++
Message
)
->
list_to_integer
(
Message
);
% in case the message is not OK or PONG it's a
% real value that we don't know how to convert
% to an atom, so just pass it as is and remove
% the +
convert
(
"+"
++
Message
)
->
Message
;
convert
(
Message
)
->
Message
.
client-libraries/erlang/support/include.mk
deleted
100644 → 0
View file @
5762b7f0
## -*- makefile -*-
ERL
:=
erl
ERLC
:=
$(ERL)
c
INCLUDE_DIRS
:=
../include
$(
wildcard
../deps/
*
/include
)
EBIN_DIRS
:=
$(
wildcard
../deps/
*
/ebin
)
ERLC_FLAGS
:=
-W
$
(
INCLUDE_DIRS:../%
=
-I
../%
)
$
(
EBIN_DIRS:%
=
-pa
%
)
ifndef
no_debug_info
ERLC_FLAGS
+=
+debug_info
endif
ifdef
debug
ERLC_FLAGS
+=
-Ddebug
endif
ifdef
test
ERLC_FLAGS
+=
-DTEST
endif
EBIN_DIR
:=
../ebin
DOC_DIR
:=
../doc
EMULATOR
:=
beam
ERL_TEMPLATE
:=
$(
wildcard
*
.et
)
ERL_SOURCES
:=
$(
wildcard
*
.erl
)
ERL_HEADERS
:=
$(
wildcard
*
.hrl
)
$(
wildcard
../include/
*
.hrl
)
ERL_OBJECTS
:=
$
(
ERL_SOURCES:%.erl
=
$(EBIN_DIR)
/%.beam
)
ERL_TEMPLATES
:=
$
(
ERL_TEMPLATE:%.et
=
$(EBIN_DIR)
/%.beam
)
ERL_OBJECTS_LOCAL
:=
$
(
ERL_SOURCES:%.erl
=
./%.
$(EMULATOR)
)
APP_FILES
:=
$(
wildcard
*
.app
)
EBIN_FILES
=
$(ERL_OBJECTS)
$
(
APP_FILES:%.app
=
../ebin/%.app
)
$(ERL_TEMPLATES)
MODULES
=
$(ERL_SOURCES:%.erl=%)
../ebin/%.app
:
%.app
cp
$<
$@
$(EBIN_DIR)/%.$(EMULATOR)
:
%.erl
$(ERLC)
$(ERLC_FLAGS)
-o
$(EBIN_DIR)
$<
$(EBIN_DIR)/%.$(EMULATOR)
:
%.et
$(ERL)
-noshell
-pa
../../elib/erltl/ebin/
-eval
"erltl:compile(atom_to_list('
$<
'), [{outdir,
\"
../ebin
\"
}, report_errors, report_warnings, nowarn_unused_vars])."
-s
init stop
./%.$(EMULATOR)
:
%.erl
$(ERLC)
$(ERLC_FLAGS)
-o
.
$<
$(DOC_DIR)/%.html
:
%.erl
$(ERL)
-noshell
-run
edoc file
$<
-run
init stop
mv
*
.html
$(DOC_DIR)
client-libraries/erlang/test/Makefile
deleted
100644 → 0
View file @
5762b7f0
include
../support/include.mk
all
:
$(EBIN_FILES)
clean
:
rm
-rf
$(EBIN_FILES)
erl_crash.dump
test
:
$(MODULES)
./$(MODULES)
:
@
echo
"Running tests for
$@
"
erl
-pa
../ebin
-run
$@
test
-run
init stop
-noshell
client-libraries/erlang/test/erldis_tests.erl
deleted
100644 → 0
View file @
5762b7f0
-
module
(
erldis_tests
).
-
include_lib
(
"eunit/include/eunit.hrl"
).
-
include
(
"erldis.hrl"
).
quit_test
()
->
{
ok
,
Client
}
=
erldis
:
connect
(
"localhost"
),
ok
=
erldis
:
quit
(
Client
),
false
=
is_process_alive
(
Client
).
utils_test
()
->
?
assertEqual
(
client
:
str
(
1
),
"1"
),
?
assertEqual
(
client
:
str
(
atom
),
"atom"
),
?
assertEqual
(
client
:
format
([[
1
,
2
,
3
]]),
"1 2 3"
),
?
assertEqual
(
client
:
format
([[
1
,
2
,
3
],
[
4
,
5
,
6
]]),
"1 2 3
\r\n
4 5 6"
).
basic_test
()
->
{
ok
,
Client
}
=
erldis
:
connect
(
"localhost"
),
erldis
:
flushall
(
Client
),
erldis
:
get
(
Client
,
"pippo"
),
erldis
:
set
(
Client
,
"hello"
,
"kitty!"
),
erldis
:
setnx
(
Client
,
"foo"
,
"bar"
),
erldis
:
setnx
(
Client
,
"foo"
,
"bar"
),
[
ok
,
nil
,
ok
,
true
,
false
]
=
erldis
:
get_all_results
(
Client
),
erldis
:
exists
(
Client
,
"hello"
),
erldis
:
exists
(
Client
,
"foo"
),
erldis
:
get
(
Client
,
"foo"
),
erldis
:
mget
(
Client
,
[
"hello"
,
"foo"
]),
erldis
:
del
(
Client
,
"hello"
),
erldis
:
del
(
Client
,
"foo"
),
erldis
:
exists
(
Client
,
"hello"
),
erldis
:
exists
(
Client
,
"foo"
),
[
true
,
true
,
"bar"
,
[
"kitty!"
,
"bar"
],
true
,
true
,
false
,
false
]
=
erldis
:
get_all_results
(
Client
),
erldis
:
set
(
Client
,
"pippo"
,
"pluto"
),
erldis
:
sadd
(
Client
,
"pippo"
,
"paperino"
),
% foo doesn't exist, the result will be nil
erldis
:
lrange
(
Client
,
"foo"
,
1
,
2
),
erldis
:
lrange
(
Client
,
"pippo"
,
1
,
2
),
[
ok
,
{
error
,
"ERR Operation against a key holding the wrong kind of value"
},
nil
,
{
error
,
"ERR Operation against a key holding the wrong kind of value"
}
]
=
erldis
:
get_all_results
(
Client
),
erldis
:
del
(
Client
,
"pippo"
),
[
true
]
=
erldis
:
get_all_results
(
Client
),
erldis
:
rpush
(
Client
,
"a_list"
,
"1"
),
erldis
:
rpush
(
Client
,
"a_list"
,
"2"
),
erldis
:
rpush
(
Client
,
"a_list"
,
"3"
),
erldis
:
rpush
(
Client
,
"a_list"
,
"1"
),
erldis
:
lrem
(
Client
,
"a_list"
,
1
,
"1"
),
erldis
:
lrange
(
Client
,
"a_list"
,
0
,
2
),
[
ok
,
ok
,
ok
,
ok
,
true
,
[
"2"
,
"3"
,
"1"
]]
=
erldis
:
get_all_results
(
Client
),
erldis
:
sort
(
Client
,
"a_list"
),
erldis
:
sort
(
Client
,
"a_list"
,
"DESC"
),
erldis
:
lrange
(
Client
,
"a_list"
,
0
,
2
),
erldis
:
sort
(
Client
,
"a_list"
,
"LIMIT 0 2 ASC"
),
[[
"1"
,
"2"
,
"3"
],
[
"3"
,
"2"
,
"1"
],
[
"2"
,
"3"
,
"1"
],
[
"1"
,
"2"
]]
=
erldis
:
get_all_results
(
Client
),
ok
=
erldis
:
quit
(
Client
).
% inline_tests(Client) ->
% [?_assertMatch(ok, erldis:set(Client, "hello", "kitty!")),
% ?_assertMatch(false, erldis:setnx(Client, "hello", "kitty!")),
% ?_assertMatch(true, erldis:exists(Client, "hello")),
% ?_assertMatch(true, erldis:del(Client, "hello")),
% ?_assertMatch(false, erldis:exists(Client, "hello")),
%
% ?_assertMatch(true, erldis:setnx(Client, "hello", "kitty!")),
% ?_assertMatch(true, erldis:exists(Client, "hello")),
% ?_assertMatch("kitty!", erldis:get(Client, "hello")),
% ?_assertMatch(true, erldis:del(Client, "hello")),
%
%
% ?_assertMatch(1, erldis:incr(Client, "pippo"))
% ,?_assertMatch(2, erldis:incr(Client, "pippo"))
% ,?_assertMatch(1, erldis:decr(Client, "pippo"))
% ,?_assertMatch(0, erldis:decr(Client, "pippo"))
% ,?_assertMatch(-1, erldis:decr(Client, "pippo"))
%
% ,?_assertMatch(6, erldis:incrby(Client, "pippo", 7))
% ,?_assertMatch(2, erldis:decrby(Client, "pippo", 4))
% ,?_assertMatch(-2, erldis:decrby(Client, "pippo", 4))
% ,?_assertMatch(true, erldis:del(Client, "pippo"))
% ].
client-libraries/erlang/test/proto_tests.erl
deleted
100644 → 0
View file @
5762b7f0
-
module
(
proto_tests
).
-
include_lib
(
"eunit/include/eunit.hrl"
).
parse_test
()
->
ok
=
proto
:
parse
(
empty
,
"+OK"
),
pong
=
proto
:
parse
(
empty
,
"+PONG"
),
false
=
proto
:
parse
(
empty
,
":0"
),
true
=
proto
:
parse
(
empty
,
":1"
),
{
error
,
"1"
}
=
proto
:
parse
(
empty
,
"-1"
).
client-libraries/lua/LICENSE
deleted
100644 → 0
View file @
5762b7f0
Copyright (c) 2009
Daniele Alessandri
http://www.clorophilla.net/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
client-libraries/lua/README
deleted
100644 → 0
View file @
5762b7f0
redis-lua
-------------------------------------------------------------------------------
A Lua client library for the redis key value storage system.
\ No newline at end of file
client-libraries/lua/redis.lua
deleted
100644 → 0
View file @
5762b7f0
local
_G
=
_G
local
require
,
error
,
type
,
print
=
require
,
error
,
type
,
print
local
table
,
pairs
,
tostring
,
tonumber
=
table
,
pairs
,
tostring
,
tonumber
module
(
'Redis'
)
local
socket
=
require
(
'socket'
)
-- requires LuaSocket as a dependency
local
redis_commands
=
{}
local
network
,
request
,
response
,
utils
=
{},
{},
{},
{},
{}
local
protocol
=
{
newline
=
'
\r\n
'
,
ok
=
'OK'
,
err
=
'ERR'
,
null
=
'nil'
}
local
function
toboolean
(
value
)
return
value
==
1
end
local
function
load_methods
(
proto
,
methods
)
local
redis
=
_G
.
setmetatable
({},
_G
.
getmetatable
(
proto
))
for
i
,
v
in
pairs
(
proto
)
do
redis
[
i
]
=
v
end
for
i
,
v
in
pairs
(
methods
)
do
redis
[
i
]
=
v
end
return
redis
end
-- ############################################################################
function
network
.
write
(
client
,
buffer
)
local
_
,
err
=
client
.
socket
:
send
(
buffer
)
if
err
then
error
(
err
)
end
end
function
network
.
read
(
client
,
len
)
if
len
==
nil
then
len
=
'*l'
end
local
line
,
err
=
client
.
socket
:
receive
(
len
)
if
not
err
then
return
line
else
error
(
'Connection error: '
..
err
)
end
end
-- ############################################################################
function
response
.
read
(
client
)
local
res
=
network
.
read
(
client
)
local
prefix
=
res
:
sub
(
1
,
-#
res
)
local
response_handler
=
protocol
.
prefixes
[
prefix
]
if
not
response_handler
then
error
(
"Unknown response prefix: "
..
prefix
)
else
return
response_handler
(
client
,
res
)
end
end
function
response
.
status
(
client
,
data
)
local
sub
=
data
:
sub
(
2
)
if
sub
==
protocol
.
ok
then
return
true
else
return
sub
end
end
function
response
.
error
(
client
,
data
)
local
err_line
=
data
:
sub
(
2
)
if
err_line
:
sub
(
1
,
3
)
==
protocol
.
err
then
error
(
"Redis error: "
..
err_line
:
sub
(
5
))
else
error
(
"Redis error: "
..
err_line
)
end
end
function
response
.
bulk
(
client
,
data
)
local
str
=
data
:
sub
(
2
)
local
len
=
tonumber
(
str
)
if
not
len
then
error
(
'Cannot parse '
..
str
..
' as data length.'
)
else
if
len
==
-
1
then
return
nil
end
local
next_chunk
=
network
.
read
(
client
,
len
+
2
)
return
next_chunk
:
sub
(
1
,
-
3
);
end
end
function
response
.
multibulk
(
client
,
data
)
local
str
=
data
:
sub
(
2
)
-- TODO: add a check if the returned value is indeed a number
local
list_count
=
tonumber
(
str
)
if
list_count
==
-
1
then
return
nil
else
local
list
=
{}
if
list_count
>
0
then
for
i
=
1
,
list_count
do
table.insert
(
list
,
i
,
response
.
bulk
(
client
,
network
.
read
(
client
)))
end
end
return
list
end
end
function
response
.
integer
(
client
,
data
)
local
res
=
data
:
sub
(
2
)
local
number
=
tonumber
(
res
)
if
not
number
then
if
res
==
protocol
.
null
then
return
nil
else
error
(
'Cannot parse '
..
res
..
' as numeric response.'
)
end
end
return
number
end
protocol
.
prefixes
=
{
[
'+'
]
=
response
.
status
,
[
'-'
]
=
response
.
error
,
[
'$'
]
=
response
.
bulk
,
[
'*'
]
=
response
.
multibulk
,
[
':'
]
=
response
.
integer
,
}
-- ############################################################################
function
request
.
raw
(
client
,
buffer
)
-- TODO: optimize
local
bufferType
=
type
(
buffer
)
if
bufferType
==
'string'
then
network
.
write
(
client
,
buffer
)
elseif
bufferType
==
'table'
then
network
.
write
(
client
,
table.concat
(
buffer
))
else
error
(
'Argument error: '
..
bufferType
)
end
return
response
.
read
(
client
)
end
function
request
.
inline
(
client
,
command
,
...
)
if
arg
.
n
==
0
then
network
.
write
(
client
,
command
..
protocol
.
newline
)
else
local
arguments
=
arg
arguments
.
n
=
nil
if
#
arguments
>
0
then
arguments
=
table.concat
(
arguments
,
' '
)
else
arguments
=
''
end
network
.
write
(
client
,
command
..
' '
..
arguments
..
protocol
.
newline
)
end
return
response
.
read
(
client
)
end
function
request
.
bulk
(
client
,
command
,
...
)
local
arguments
=
arg
local
data
=
tostring
(
table.remove
(
arguments
))
arguments
.
n
=
nil
-- TODO: optimize
if
#
arguments
>
0
then
arguments
=
table.concat
(
arguments
,
' '
)
else
arguments
=
''
end
return
request
.
raw
(
client
,
{
command
,
' '
,
arguments
,
' '
,
#
data
,
protocol
.
newline
,
data
,
protocol
.
newline
})
end
-- ############################################################################
local
function
custom
(
command
,
send
,
parse
)
return
function
(
self
,
...
)
local
reply
=
send
(
self
,
command
,
...
)
if
parse
then
return
parse
(
reply
,
command
,
...
)
else
return
reply
end
end
end
local
function
bulk
(
command
,
reader
)
return
custom
(
command
,
request
.
bulk
,
reader
)
end
local
function
inline
(
command
,
reader
)
return
custom
(
command
,
request
.
inline
,
reader
)
end
-- ############################################################################
function
connect
(
host
,
port
)
local
client_socket
=
socket
.
connect
(
host
,
port
)
if
not
client_socket
then
error
(
'Could not connect to '
..
host
..
':'
..
port
)
end
local
redis_client
=
{
socket
=
client_socket
,
raw_cmd
=
function
(
self
,
buffer
)
return
request
.
raw
(
self
,
buffer
..
protocol
.
newline
)
end
,
}
return
load_methods
(
redis_client
,
redis_commands
)
end
-- ############################################################################
redis_commands
=
{
-- miscellaneous commands
ping
=
inline
(
'PING'
,
function
(
response
)
if
response
==
'PONG'
then
return
true
else
return
false
end
end
),
echo
=
bulk
(
'ECHO'
),
-- TODO: the server returns an empty -ERR on authentication failure
auth
=
inline
(
'AUTH'
),
-- connection handling
quit
=
custom
(
'QUIT'
,
function
(
client
,
command
)
-- let's fire and forget! the connection is closed as soon
-- as the QUIT command is received by the server.
network
.
write
(
client
,
command
..
protocol
.
newline
)
end
),
-- commands operating on string values
set
=
bulk
(
'SET'
),
set_preserve
=
bulk
(
'SETNX'
,
toboolean
),
get
=
inline
(
'GET'
),
get_multiple
=
inline
(
'MGET'
),
get_set
=
bulk
(
'GETSET'
),
increment
=
inline
(
'INCR'
),
increment_by
=
inline
(
'INCRBY'
),
decrement
=
inline
(
'DECR'
),
decrement_by
=
inline
(
'DECRBY'
),
exists
=
inline
(
'EXISTS'
,
toboolean
),
delete
=
inline
(
'DEL'
,
toboolean
),
type
=
inline
(
'TYPE'
),
-- commands operating on the key space
keys
=
inline
(
'KEYS'
,
function
(
response
)
local
keys
=
{}
response
:
gsub
(
'%w+'
,
function
(
key
)
table.insert
(
keys
,
key
)
end
)
return
keys
end
),
random_key
=
inline
(
'RANDOMKEY'
),
rename
=
inline
(
'RENAME'
),
rename_preserve
=
inline
(
'RENAMENX'
),
expire
=
inline
(
'EXPIRE'
,
toboolean
),
database_size
=
inline
(
'DBSIZE'
),
time_to_live
=
inline
(
'TTL'
),
-- commands operating on lists
push_tail
=
bulk
(
'RPUSH'
),
push_head
=
bulk
(
'LPUSH'
),
list_length
=
inline
(
'LLEN'
),
list_range
=
inline
(
'LRANGE'
),
list_trim
=
inline
(
'LTRIM'
),
list_index
=
inline
(
'LINDEX'
),
list_set
=
bulk
(
'LSET'
),
list_remove
=
bulk
(
'LREM'
),
pop_first
=
inline
(
'LPOP'
),
pop_last
=
inline
(
'RPOP'
),
-- commands operating on sets
set_add
=
bulk
(
'SADD'
),
set_remove
=
bulk
(
'SREM'
),
set_move
=
bulk
(
'SMOVE'
),
set_cardinality
=
inline
(
'SCARD'
),
set_is_member
=
inline
(
'SISMEMBER'
),
set_intersection
=
inline
(
'SINTER'
),
set_intersection_store
=
inline
(
'SINTERSTORE'
),
set_union
=
inline
(
'SUNION'
),
set_union_store
=
inline
(
'SUNIONSTORE'
),
set_diff
=
inline
(
'SDIFF'
),
set_diff_store
=
inline
(
'SDIFFSTORE'
),
set_members
=
inline
(
'SMEMBERS'
),
-- multiple databases handling commands
select_database
=
inline
(
'SELECT'
),
move_key
=
inline
(
'MOVE'
),
flush_database
=
inline
(
'FLUSHDB'
),
flush_databases
=
inline
(
'FLUSHALL'
),
-- sorting
--[[
TODO: should we pass sort parameters as a table? e.g:
params = {
by = 'weight_*',
get = 'object_*',
limit = { 0, 10 },
sort = { 'desc', 'alpha' }
}
--]]
sort
=
custom
(
'SORT'
,
function
(
client
,
command
,
params
)
-- TODO: here we will put the logic needed to serialize the params
-- table to be sent as the argument of the SORT command.
return
request
.
inline
(
client
,
command
,
params
)
end
),
-- persistence control commands
save
=
inline
(
'SAVE'
),
background_save
=
inline
(
'BGSAVE'
),
last_save
=
inline
(
'LASTSAVE'
),
shutdown
=
custom
(
'SHUTDOWN'
,
function
(
client
,
command
)
-- let's fire and forget! the connection is closed as soon
-- as the SHUTDOWN command is received by the server.
network
.
write
(
client
,
command
..
protocol
.
newline
)
end
),
-- remote server control commands
info
=
inline
(
'INFO'
,
function
(
response
)
local
info
=
{}
response
:
gsub
(
'
(
[^\r\n]*
)
\
r
\
n
', function(kv)
local k,v = kv:match(('
([
^
:]
*
):([
^
:]
*
)
'):rep(1))
info[k] = v
end)
return info
end
),
slave_of = inline('
SLAVEOF
'),
slave_of_no_one = custom('
SLAVEOF
',
function(client, command)
return request.inline(client, command, '
NO
ONE
')
end
),
}
client-libraries/perl/Changes
deleted
100644 → 0
View file @
5762b7f0
Revision history for Redis
0.01 Sun Mar 22 19:02:17 CET 2009
First version, tracking git://github.com/antirez/redis
0.08 Tue Mar 24 22:38:59 CET 2009
This version supports new protocol introduced in beta 8
Version bump to be in-sync with Redis version
client-libraries/perl/MANIFEST
deleted
100644 → 0
View file @
5762b7f0
Changes
MANIFEST
Makefile.PL
README
lib/Redis.pm
t/00-load.t
t/pod-coverage.t
t/pod.t
client-libraries/perl/Makefile.PL
deleted
100644 → 0
View file @
5762b7f0
use
strict;
use
warnings;
use ExtUtils
::
MakeMaker;
WriteMakefile(
NAME
=>
'Redis'
,
AUTHOR
=>
'Dobrica Pavlinusic <dpavlin@rot13.org>'
,
VERSION_FROM
=>
'lib/Redis.pm'
,
ABSTRACT_FROM
=>
'lib/Redis.pm'
,
PL_FILES
=>
{}
,
PREREQ_PM
=>
{
'Test::More'
=>
0,
'IO::Socket::INET'
=>
0,
'Data::Dump'
=>
0,
'Carp'
=>
0,
},
dist
=>
{
COMPRESS
=>
'gzip -9f'
, SUFFIX
=>
'gz'
,
}
,
clean
=>
{
FILES
=>
'Redis-*'
}
,
);
Prev
1
2
3
4
5
6
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