rusty_redic 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.appveyor.yml +79 -0
- data/.gitignore +10 -0
- data/.travis.yml +75 -0
- data/Cargo.toml +22 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/Rakefile +13 -0
- data/lib/rusty_redic.rb +6 -0
- data/rusty_redic.gemspec +22 -0
- data/src/lib.rs +217 -0
- data/test/test_rusty_redic.rb +29 -0
- data/throughput.rb +76 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc86989c5716583f7009fc180288d3d7968634a2
|
4
|
+
data.tar.gz: eec8c481510b5603f9d969831010c8c1d3c46184
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8d1267d475534ff066f775370167fbbdeb28e6374a10bf29716b4fd91f0f82e9791a775eecce70970e2d4b39c3590e03bee40b59bae7691831caa9622c7cc59f
|
7
|
+
data.tar.gz: bc7dcb5a9713272616db3798a703268e95acedbb1e399bdbaa88a7ca0b71a052f6e84399645da9338f2d2a1aa3f416b0dd26b4b127c6c2bd3bf6cc16bb05cf18
|
data/.appveyor.yml
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
platform:
|
2
|
+
- x86
|
3
|
+
- x64
|
4
|
+
environment:
|
5
|
+
matrix:
|
6
|
+
- RUST_VERSION: stable
|
7
|
+
BUILD_TARGET: gnu
|
8
|
+
RUBY_VERSION: 23
|
9
|
+
cache:
|
10
|
+
- target\debug\build
|
11
|
+
- target\debug\deps
|
12
|
+
- '%USERPROFILE%\.cargo'
|
13
|
+
install:
|
14
|
+
- ps: |
|
15
|
+
$env:PATH += ";C:\rust\bin";
|
16
|
+
if ($env:platform -eq 'x86') {
|
17
|
+
$env:RUBY_DIR = "Ruby${env:RUBY_VERSION}"
|
18
|
+
$arch_expanded = "i686-pc-windows-${env:BUILD_TARGET}";
|
19
|
+
$env:ARCH = "x86";
|
20
|
+
$env:bits = "32";
|
21
|
+
} else {
|
22
|
+
$env:RUBY_DIR = "Ruby${env:RUBY_VERSION}-x64"
|
23
|
+
$arch_expanded = "x86_64-pc-windows-${env:BUILD_TARGET}";
|
24
|
+
$env:ARCH = "amd64";
|
25
|
+
$env:bits ="64";
|
26
|
+
}
|
27
|
+
$env:WIN_RUBY_BIN = "C:\${env:RUBY_DIR}\bin";
|
28
|
+
$env:PATH = "${env:WIN_RUBY_BIN};${env:PATH}";
|
29
|
+
if ($env:BUILD_TARGET -eq 'gnu') {
|
30
|
+
$env:PATH += ";C:\msys64\mingw${env:bits}\bin";
|
31
|
+
gcc --version;
|
32
|
+
}
|
33
|
+
if ($env:RUST_VERSION -eq 'stable') {
|
34
|
+
echo "Downloading $channel channel manifest";
|
35
|
+
Start-FileDownload "https://static.rust-lang.org/dist/channel-rust-stable";
|
36
|
+
|
37
|
+
$env:RUST_VERSION = Get-Content channel-rust-stable | Select -first 1 | %{$_.split('-')[1]}
|
38
|
+
}
|
39
|
+
$env:rust_installer = "rust-${env:RUST_VERSION}-${arch_expanded}.exe";
|
40
|
+
$tag_suffix = echo "${env:APPVEYOR_REPO_TAG_NAME}" | Select-String -pattern "-rust$"
|
41
|
+
if ($tag_suffix) {
|
42
|
+
$env:RUST_TAG = "1";
|
43
|
+
}
|
44
|
+
- curl --show-error --location --retry 5 --output rust-installer.exe https://static.rust-lang.org/dist/%rust_installer%
|
45
|
+
- .\rust-installer.exe /VERYSILENT /NORESTART /DIR="C:\rust"
|
46
|
+
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH%
|
47
|
+
- rustc -vV
|
48
|
+
- cargo -vV
|
49
|
+
- ruby --version
|
50
|
+
- gem --version
|
51
|
+
- rake --version
|
52
|
+
- bundle --version
|
53
|
+
- bundle config --local path vendor/bundle
|
54
|
+
- bundle install
|
55
|
+
build_script:
|
56
|
+
- bundle exec rake --trace thermite:tarball
|
57
|
+
test_script:
|
58
|
+
- bundle exec rake --trace test
|
59
|
+
- ps: |
|
60
|
+
if ($env:RUST_TAG -ne '1') {
|
61
|
+
bundle exec rake --trace install;
|
62
|
+
gem uninstall rusty_blank;
|
63
|
+
gem install minitest;
|
64
|
+
del "${env:WIN_RUBY_BIN}\rake"
|
65
|
+
gem install "pkg\*.gem";
|
66
|
+
ruby "test\test_rusty_blank.rb";
|
67
|
+
}
|
68
|
+
artifacts:
|
69
|
+
- path: rusty_blank-*.tar.gz
|
70
|
+
deploy:
|
71
|
+
- provider: GitHub
|
72
|
+
artifact: /rusty_blank-.*\.tar\.gz/
|
73
|
+
draft: false
|
74
|
+
prerelease: false
|
75
|
+
auth_token:
|
76
|
+
secure: VUF+Nfn07Dym0IlQHG3NO6SdHMa1uG8IVzRY+beMUPR49b6M5mTvpPTm3OWO40G7
|
77
|
+
on:
|
78
|
+
appveyor_repo_tag: true
|
79
|
+
RUST_TAG: 1
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
sudo: false
|
2
|
+
dist: trusty
|
3
|
+
language: rust
|
4
|
+
services:
|
5
|
+
- redis-server
|
6
|
+
os:
|
7
|
+
- linux
|
8
|
+
- osx
|
9
|
+
dist: trusty
|
10
|
+
osx_image: xcode8
|
11
|
+
rust: stable
|
12
|
+
env:
|
13
|
+
global:
|
14
|
+
- THERMITE_DEBUG_FILENAME: /tmp/thermite-debug.log
|
15
|
+
matrix:
|
16
|
+
- R_RUBY_VERSION: 2.3.3
|
17
|
+
- R_RUBY_VERSION: 2.4.0
|
18
|
+
|
19
|
+
cache:
|
20
|
+
cargo: true
|
21
|
+
directories:
|
22
|
+
- $TRAVIS_BUILD_DIR/vendor/bundle
|
23
|
+
- $HOME/.cache/pip
|
24
|
+
|
25
|
+
before_install:
|
26
|
+
- |
|
27
|
+
rvm install "$R_RUBY_VERSION"
|
28
|
+
rvm use "$R_RUBY_VERSION"
|
29
|
+
ruby --version
|
30
|
+
if [[ "$TRAVIS_OS_NAME" == "osx" ]] && ! which bundle > /dev/null; then
|
31
|
+
gem install bundler
|
32
|
+
fi
|
33
|
+
- bundle install --jobs=3 --retry=3 --path=$TRAVIS_BUILD_DIR/vendor/bundle
|
34
|
+
|
35
|
+
before_script:
|
36
|
+
- |
|
37
|
+
export PATH=$HOME/Library/Python/2.7/bin:$HOME/.local/bin:$PATH
|
38
|
+
if [[ "$TRAVIS_OS_NAME" == "osx" ]] && ! which pip > /dev/null; then
|
39
|
+
wget https://bootstrap.pypa.io/get-pip.py
|
40
|
+
python get-pip.py --user
|
41
|
+
fi
|
42
|
+
pip install 'travis-cargo<0.2' --user
|
43
|
+
|
44
|
+
script:
|
45
|
+
- travis-cargo build
|
46
|
+
- bundle exec rake test
|
47
|
+
- bundle exec rake thermite:tarball
|
48
|
+
- bundle exec rake install
|
49
|
+
- |
|
50
|
+
if [[ -z "$TRAVIS_TAG" ]]; then
|
51
|
+
gem uninstall rusty_redic
|
52
|
+
CARGO=fake bundle exec rake install
|
53
|
+
fi
|
54
|
+
- |
|
55
|
+
if [[ -z "$TRAVIS_TAG" ]]; then
|
56
|
+
gem uninstall rusty_redic
|
57
|
+
gem install minitest
|
58
|
+
CARGO=fake gem install pkg/*.gem
|
59
|
+
ruby test/test_rusty_redic.rb
|
60
|
+
fi
|
61
|
+
- if [[ -f "$THERMITE_DEBUG_FILENAME" ]]; then cat $THERMITE_DEBUG_FILENAME; fi
|
62
|
+
|
63
|
+
deploy:
|
64
|
+
provider: releases
|
65
|
+
api_key:
|
66
|
+
secure: kPF5xzVgW42igOf3AIqY1CGEn3Q4Dc9QEfdxkPlcSWsnHDSqDfdSqZn4yHsb8BFLtrR4Hd1QxerWVIKtitG5Mz/PX9i7vXzyXVNjX29vfWVvV4x9dqN4ZCcTHaU5MGMOqQ646fIdJZfzgMEaXztD3wFXOPxd1eBl3eBz1tDvOib9SnQF+qclbtdCJw8Q+LShOXQzzjplhfsGSJ7W1r8wtFiEHZILG88UCbJUneOo5YnL4lPQcF8m0/5N2aAO+Y1bcdK/zjygQdMQhqKPWVLrosnpY+2Y/Hs/6nzCi2PKuU0PPqEb7Ak8j9ikYKaNrlQCFBAsDZbPzfFdC9OlIQiURMsu2OIoUMb0F3sPGeTUAx4hvbI96XmCTsLb/+sySuRKQXwsN5D6gggnKZm/AhqA0mzKjjyUCPxLsLjittbQMCoRwdAIipkgfifrjqwnhzyjgf6FqYEJ/nFwkFP79GWk08mYzAsyqFlR0cdVn/LdJwazTu4DPbL2z+N0+C3rQeiysgvCOqrNv86inD36o9qMRPJq4dl08Add6Rd5qlNMHtoGNhKZJADawAR0o7fKhKOYHj5M6VWJPkY6TXE4g9QjfJ39qqWWZBrjbwZG5Z0zGYA2VZ/az4Avh8Uytfnc9Fjk+H+vy8xuXX6bACnUj/VVXy0H4+xS2+KZj157HFdD1mk=
|
67
|
+
file: rusty_redic-*.tar.gz
|
68
|
+
file_glob: true
|
69
|
+
skip_cleanup: true
|
70
|
+
on:
|
71
|
+
condition: ${TRAVIS_TAG} =~ '-rust'
|
72
|
+
repo: badboy/rusty_redic
|
73
|
+
tags: true
|
74
|
+
notifications:
|
75
|
+
email: false
|
data/Cargo.toml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
[package]
|
2
|
+
name = "rusty-redic"
|
3
|
+
version = "0.2.0"
|
4
|
+
authors = ["Jan-Erik Rediger <janerik@fnordig.de>"]
|
5
|
+
repository = "https://github.com/badboy/rusty_redic"
|
6
|
+
publish = false
|
7
|
+
|
8
|
+
[package.metadata.thermite]
|
9
|
+
|
10
|
+
github_releases = true
|
11
|
+
github_release_type = "latest"
|
12
|
+
# Only for github_release_type = "cargo"
|
13
|
+
# git_tag_format = "v%s-rust"
|
14
|
+
git_tag_regex = "^v(\\d+\\.\\d+\\.\\d+)-rust$"
|
15
|
+
|
16
|
+
[lib]
|
17
|
+
crate-type = ["dylib"]
|
18
|
+
|
19
|
+
[dependencies]
|
20
|
+
ruru = "0.9"
|
21
|
+
redis = "0.8.0"
|
22
|
+
lazy_static = "0.2.1"
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Jan-Erik Rediger
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'thermite/tasks'
|
3
|
+
|
4
|
+
thermite = Thermite::Tasks.new
|
5
|
+
|
6
|
+
task default: %w(thermite:build)
|
7
|
+
|
8
|
+
desc 'Run testsuite'
|
9
|
+
task test: %w(thermite:build thermite:test) do
|
10
|
+
test_file = File.join(File.dirname(__FILE__), 'test', 'test_rusty_redic.rb')
|
11
|
+
ruby "#{test_file} #{thermite.config.ruby_extension_path}"
|
12
|
+
ruby test_file
|
13
|
+
end
|
data/lib/rusty_redic.rb
ADDED
data/rusty_redic.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'English'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'rusty_redic'
|
6
|
+
s.version = '0.2.0'
|
7
|
+
s.summary = 'Lightweight Redis Client, in Rust'
|
8
|
+
s.description = 'A lightweight Redis Client, written in Rust, as minimal as Redic'
|
9
|
+
|
10
|
+
s.authors = ['Jan-Erik Rediger']
|
11
|
+
s.email = 'janerik@fnordig.de'
|
12
|
+
s.homepage = 'https://github.com/badboy/rusty_redic'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.extensions = %w(Rakefile)
|
16
|
+
s.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
17
|
+
s.require_paths = %w(lib)
|
18
|
+
s.test_files = %w(test/test_rusty_redic.rb)
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'thermite', '~> 0'
|
21
|
+
s.add_development_dependency 'minitest', '~> 5.8'
|
22
|
+
end
|
data/src/lib.rs
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
#[macro_use]
|
2
|
+
extern crate ruru;
|
3
|
+
#[macro_use]
|
4
|
+
extern crate lazy_static;
|
5
|
+
|
6
|
+
extern crate redis;
|
7
|
+
|
8
|
+
use std::str;
|
9
|
+
use std::error::Error;
|
10
|
+
use ruru::{Class, Object, RString, Array, AnyObject, NilClass, VM, Fixnum};
|
11
|
+
|
12
|
+
pub struct Redic {
|
13
|
+
client: redis::Client,
|
14
|
+
conn: Option<redis::Connection>,
|
15
|
+
queue: Vec<Vec<String>>,
|
16
|
+
}
|
17
|
+
|
18
|
+
impl Redic {
|
19
|
+
pub fn new(client: redis::Client) -> Redic {
|
20
|
+
Redic {
|
21
|
+
client: client,
|
22
|
+
conn: None,
|
23
|
+
queue: vec![],
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
pub fn client(&self) -> &redis::Client {
|
28
|
+
&self.client
|
29
|
+
}
|
30
|
+
|
31
|
+
pub fn queue(&mut self) -> &mut Vec<Vec<String>> {
|
32
|
+
&mut self.queue
|
33
|
+
}
|
34
|
+
|
35
|
+
pub fn connection(&mut self) -> &redis::Connection {
|
36
|
+
if self.conn.is_some() {
|
37
|
+
return self.conn.as_ref().unwrap();
|
38
|
+
}
|
39
|
+
|
40
|
+
let con = match self.client.get_connection() {
|
41
|
+
Ok(con) => con,
|
42
|
+
Err(_) => {
|
43
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't create connection");
|
44
|
+
unreachable!();
|
45
|
+
}
|
46
|
+
};
|
47
|
+
self.conn = Some(con);
|
48
|
+
self.conn.as_ref().unwrap()
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
wrappable_struct!(Redic, RedicWrapper, REDIC_WRAPPER);
|
53
|
+
|
54
|
+
class!(RustyRedic);
|
55
|
+
|
56
|
+
fn redis_value_to_any_object(val: redis::Value) -> AnyObject {
|
57
|
+
match val {
|
58
|
+
redis::Value::Nil => NilClass::new().to_any_object(),
|
59
|
+
redis::Value::Int(i) => Fixnum::new(i).to_any_object(),
|
60
|
+
redis::Value::Data(vec) => {
|
61
|
+
unsafe {
|
62
|
+
let s = str::from_utf8_unchecked(&vec);
|
63
|
+
RString::new(s).to_any_object()
|
64
|
+
}
|
65
|
+
}
|
66
|
+
redis::Value::Bulk(vec) => {
|
67
|
+
let mut v = Array::new();
|
68
|
+
for elem in vec {
|
69
|
+
v.push(redis_value_to_any_object(elem));
|
70
|
+
}
|
71
|
+
v.to_any_object()
|
72
|
+
}
|
73
|
+
redis::Value::Status(s) => RString::new(&s).to_any_object(),
|
74
|
+
redis::Value::Okay => RString::new("OK").to_any_object()
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
methods!(
|
79
|
+
RustyRedic,
|
80
|
+
itself,
|
81
|
+
|
82
|
+
fn redic_new(url: RString) -> AnyObject {
|
83
|
+
let default_url = "redis://localhost:6379";
|
84
|
+
let url = url
|
85
|
+
.map(|url| url.to_string())
|
86
|
+
.unwrap_or_else(|_| default_url.to_string());
|
87
|
+
let client = match redis::Client::open(&*url) {
|
88
|
+
Ok(client) => client,
|
89
|
+
Err(_) => {
|
90
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't create RustyRedic");
|
91
|
+
unreachable!();
|
92
|
+
}
|
93
|
+
};
|
94
|
+
let redic = Redic::new(client);
|
95
|
+
|
96
|
+
Class::from_existing("RustyRedic")
|
97
|
+
.wrap_data(redic, &*REDIC_WRAPPER)
|
98
|
+
}
|
99
|
+
|
100
|
+
fn redic_call(args: Array) -> AnyObject {
|
101
|
+
let args = match args {
|
102
|
+
Err(error) => {
|
103
|
+
VM::raise(error.to_exception(), error.description());
|
104
|
+
unreachable!();
|
105
|
+
}
|
106
|
+
Ok(args) => args
|
107
|
+
};
|
108
|
+
if args.length() == 0 {
|
109
|
+
VM::raise(Class::from_existing("ArgumentError"), "Need atleast 1 argument");
|
110
|
+
unreachable!();
|
111
|
+
}
|
112
|
+
|
113
|
+
let con = itself.get_data(&*REDIC_WRAPPER).connection();
|
114
|
+
|
115
|
+
let mut args = args.into_iter()
|
116
|
+
.map(|obj| {
|
117
|
+
let obj = match obj.try_convert_to::<RString>() {
|
118
|
+
Ok(obj) => obj,
|
119
|
+
Err(_) => {
|
120
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't coerce to String");
|
121
|
+
unreachable!();
|
122
|
+
}
|
123
|
+
};
|
124
|
+
obj.to_string()
|
125
|
+
});
|
126
|
+
|
127
|
+
let cmd = args.next().unwrap();
|
128
|
+
let mut cmd = redis::cmd(&cmd);
|
129
|
+
for arg in args {
|
130
|
+
cmd.arg(&arg);
|
131
|
+
}
|
132
|
+
|
133
|
+
let res : redis::RedisResult<redis::Value> = cmd.query(con);
|
134
|
+
|
135
|
+
match res {
|
136
|
+
Err(_) => {
|
137
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't execute command");
|
138
|
+
unreachable!();
|
139
|
+
}
|
140
|
+
Ok(val) => redis_value_to_any_object(val)
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
fn redic_queue(args: Array) -> NilClass {
|
145
|
+
let args = match args {
|
146
|
+
Err(error) => {
|
147
|
+
VM::raise(error.to_exception(), error.description());
|
148
|
+
unreachable!();
|
149
|
+
}
|
150
|
+
Ok(args) => args
|
151
|
+
};
|
152
|
+
if args.length() == 0 {
|
153
|
+
VM::raise(Class::from_existing("ArgumentError"), "Need atleast 1 argument");
|
154
|
+
unreachable!();
|
155
|
+
}
|
156
|
+
|
157
|
+
let args = args.into_iter()
|
158
|
+
.map(|obj| {
|
159
|
+
let obj = match obj.try_convert_to::<RString>() {
|
160
|
+
Ok(obj) => obj,
|
161
|
+
Err(_) => {
|
162
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't coerce to String");
|
163
|
+
unreachable!();
|
164
|
+
}
|
165
|
+
};
|
166
|
+
obj.to_string()
|
167
|
+
}).collect::<Vec<String>>();
|
168
|
+
|
169
|
+
let mut queue = itself.get_data(&*REDIC_WRAPPER).queue();
|
170
|
+
queue.push(args);
|
171
|
+
|
172
|
+
NilClass::new()
|
173
|
+
|
174
|
+
}
|
175
|
+
|
176
|
+
fn redic_commit() -> AnyObject {
|
177
|
+
let mut queue = itself.get_data(&*REDIC_WRAPPER).queue();
|
178
|
+
if queue.is_empty() {
|
179
|
+
return NilClass::new().to_any_object();
|
180
|
+
}
|
181
|
+
|
182
|
+
let con = itself.get_data(&*REDIC_WRAPPER).connection();
|
183
|
+
|
184
|
+
let mut pipe = redis::pipe();
|
185
|
+
for cmd in queue.drain(..) {
|
186
|
+
let mut args = cmd.iter();
|
187
|
+
let first = args.next().unwrap();
|
188
|
+
pipe.cmd(first);
|
189
|
+
for arg in args {
|
190
|
+
pipe.arg(arg);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
let res : redis::RedisResult<redis::Value> = pipe.query(con);
|
195
|
+
|
196
|
+
match res {
|
197
|
+
Err(_) => {
|
198
|
+
VM::raise(Class::from_existing("ArgumentError"), "Can't execute command");
|
199
|
+
unreachable!();
|
200
|
+
}
|
201
|
+
Ok(val) => redis_value_to_any_object(val)
|
202
|
+
}
|
203
|
+
}
|
204
|
+
);
|
205
|
+
|
206
|
+
#[no_mangle]
|
207
|
+
pub extern fn init_rusty_redic() {
|
208
|
+
let data_class = Class::from_existing("Data");
|
209
|
+
|
210
|
+
Class::new("RustyRedic", Some(&data_class)).define(|itself| {
|
211
|
+
itself.def_self("new", redic_new);
|
212
|
+
|
213
|
+
itself.def("call", redic_call);
|
214
|
+
itself.def("queue", redic_queue);
|
215
|
+
itself.def("commit", redic_commit);
|
216
|
+
});
|
217
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'rusty_redic'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Extremely basic unit test for rusty_redic
|
8
|
+
#
|
9
|
+
class TestRustyRedic < MiniTest::Test
|
10
|
+
def test_new
|
11
|
+
assert RustyRedic.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_call
|
15
|
+
redic = RustyRedic.new
|
16
|
+
|
17
|
+
assert_equal "OK", redic.call(["SET", "foo", "bar"])
|
18
|
+
assert_equal "bar", redic.call(["GET", "foo"])
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_pipeline
|
22
|
+
redic = RustyRedic.new
|
23
|
+
|
24
|
+
redic.queue(["SET", "foo", "bar"])
|
25
|
+
redic.queue(["GET", "foo"])
|
26
|
+
|
27
|
+
assert_equal ["OK", "bar"], redic.commit
|
28
|
+
end
|
29
|
+
end
|
data/throughput.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Compare performance of redic with rusty_redic
|
2
|
+
#
|
3
|
+
# Run with
|
4
|
+
#
|
5
|
+
# $ bundle exec rake thermite:build
|
6
|
+
# $ bundle exec throughput.rb
|
7
|
+
#
|
8
|
+
|
9
|
+
require "rubygems"
|
10
|
+
require "benchmark"
|
11
|
+
require "rusty_redic"
|
12
|
+
require "redic"
|
13
|
+
|
14
|
+
$redic = Redic.new
|
15
|
+
$rusty_redic = RustyRedic.new
|
16
|
+
|
17
|
+
# make sure both are connected
|
18
|
+
$redic.call("PING")
|
19
|
+
$rusty_redic.call(["PING"])
|
20
|
+
|
21
|
+
$redic.call(:flushdb)
|
22
|
+
|
23
|
+
def without_gc
|
24
|
+
GC.start
|
25
|
+
GC.disable
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
GC.enable
|
29
|
+
end
|
30
|
+
|
31
|
+
def pipeline(b,num,size,title,cmd)
|
32
|
+
commands = size.times.map { cmd }
|
33
|
+
|
34
|
+
x = without_gc {
|
35
|
+
b.report("redic: %2dx #{title} pipeline, #{num} times" % size) {
|
36
|
+
num.times {
|
37
|
+
commands.each { |cmd| $redic.queue(*cmd) }
|
38
|
+
$redic.commit
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
y = without_gc {
|
44
|
+
b.report("rusty_redic: %2dx #{title} pipeline, #{num} times" % size) {
|
45
|
+
num.times {
|
46
|
+
commands.each { |cmd| $rusty_redic.queue(cmd) }
|
47
|
+
$rusty_redic.commit
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
puts "%.1fx" % [1 / (y.real / x.real)]
|
53
|
+
end
|
54
|
+
|
55
|
+
Benchmark.bm(50) do |b|
|
56
|
+
pipeline(b,10000, 1, "SET", %w(set foo bar))
|
57
|
+
pipeline(b,10000,10, "SET", %w(set foo bar))
|
58
|
+
puts
|
59
|
+
|
60
|
+
pipeline(b,10000, 1, "GET", %w(get foo))
|
61
|
+
pipeline(b,10000,10, "GET", %w(get foo))
|
62
|
+
puts
|
63
|
+
|
64
|
+
pipeline(b,10000, 1, "LPUSH", %w(lpush list fooz))
|
65
|
+
pipeline(b,10000,10, "LPUSH", %w(lpush list fooz))
|
66
|
+
puts
|
67
|
+
|
68
|
+
pipeline(b,1000, 1, "LRANGE(100)", %w(lrange list 0 99))
|
69
|
+
puts
|
70
|
+
|
71
|
+
pipeline(b,1000, 1, "LRANGE(1000)", %w(lrange list 0 999))
|
72
|
+
puts
|
73
|
+
|
74
|
+
# Clean up...
|
75
|
+
redic.call(:flushdb)
|
76
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rusty_redic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan-Erik Rediger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thermite
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.8'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.8'
|
41
|
+
description: A lightweight Redis Client, written in Rust, as minimal as Redic
|
42
|
+
email: janerik@fnordig.de
|
43
|
+
executables: []
|
44
|
+
extensions:
|
45
|
+
- Rakefile
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".appveyor.yml"
|
49
|
+
- ".gitignore"
|
50
|
+
- ".travis.yml"
|
51
|
+
- Cargo.toml
|
52
|
+
- Gemfile
|
53
|
+
- LICENSE
|
54
|
+
- Rakefile
|
55
|
+
- lib/rusty_redic.rb
|
56
|
+
- rusty_redic.gemspec
|
57
|
+
- src/lib.rs
|
58
|
+
- test/test_rusty_redic.rb
|
59
|
+
- throughput.rb
|
60
|
+
homepage: https://github.com/badboy/rusty_redic
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.6.8
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Lightweight Redis Client, in Rust
|
84
|
+
test_files:
|
85
|
+
- test/test_rusty_redic.rb
|