Revert cbson.c, to be revisited for malloc/free reduction.
README.md has API Documentation note at the top to help users match documentation to driver version, DOCS-197. Expanded performance tests, for insert with multiple docs.
This commit is contained in:
parent
ca7bf209dd
commit
50d6902d80
2
Gemfile
2
Gemfile
@ -9,6 +9,8 @@ group :development, :test do
|
|||||||
|
|
||||||
# Deployment
|
# Deployment
|
||||||
gem "git"
|
gem "git"
|
||||||
|
gem "redcarpet"
|
||||||
|
gem "yard"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
gem "mocha"
|
gem "mocha"
|
||||||
|
23
README.md
23
README.md
@ -1,3 +1,17 @@
|
|||||||
|
# Documentation
|
||||||
|
|
||||||
|
This API documentation is available online at [http://api.mongodb.org/ruby](http://api.mongodb.org/ruby)
|
||||||
|
for all releases of the MongoDB Ruby driver. Please reference the exact version of the documentation
|
||||||
|
that matches the release of the Ruby driver that you are using. Note that the
|
||||||
|
[Ruby Language Center for MongoDB](http://www.mongodb.org/display/DOCS/Ruby+Language+Center)
|
||||||
|
has a link to API Documentation for the current release.
|
||||||
|
|
||||||
|
If you have the source, you can generate the matching documentation by typing
|
||||||
|
|
||||||
|
$ rake ydoc
|
||||||
|
|
||||||
|
Then open the file +ydoc/index.html+.
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
This is the 10gen-supported Ruby driver for [MongoDB](http://www.mongodb.org).
|
This is the 10gen-supported Ruby driver for [MongoDB](http://www.mongodb.org).
|
||||||
@ -300,15 +314,6 @@ If you want to test replica set, you can run the following task:
|
|||||||
|
|
||||||
$ rake test:rs
|
$ rake test:rs
|
||||||
|
|
||||||
# Documentation
|
|
||||||
|
|
||||||
This documentation is available online at [http://api.mongodb.org/ruby](http://api.mongodb.org/ruby). You can
|
|
||||||
generate the documentation if you have the source by typing
|
|
||||||
|
|
||||||
$ rake ydoc
|
|
||||||
|
|
||||||
Then open the file +ydoc/index.html+.
|
|
||||||
|
|
||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
See HISTORY.
|
See HISTORY.
|
||||||
|
@ -18,13 +18,18 @@
|
|||||||
width:800px;
|
width:800px;
|
||||||
height:400px;
|
height:400px;
|
||||||
}
|
}
|
||||||
|
div.hidden {
|
||||||
|
//display: none; //visibility: hidden; // to collapse, use display: none
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Exp Series Performance Tests</h1>
|
<h1>Exp Series Performance Tests</h1>
|
||||||
x-axis is power of 2, log base 2 of size<br>
|
x-axis is power of 2, log base 2 of size<br>
|
||||||
y-axis is operations per user-time CPU-second<br>
|
y-axis is "document" operations per second, ex., total document insertions per second<br>
|
||||||
Note that this is not operations per real-time second that include DB real-time<br>
|
<br>
|
||||||
|
For measuring Ruby driver performance, we are interested primarily in the "user" CPU time.<br>
|
||||||
|
The "user" time is the time used by the Ruby driver, typically much less than real time.<br>
|
||||||
<div id="placeholder"></div>
|
<div id="placeholder"></div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -42,7 +47,7 @@
|
|||||||
return $.map(plotSpecs, function(plotSpec, i){
|
return $.map(plotSpecs, function(plotSpec, i){
|
||||||
return {
|
return {
|
||||||
label: labelSpec + ': ' + plotSpec[labelSpec],
|
label: labelSpec + ': ' + plotSpec[labelSpec],
|
||||||
data: genOpXY(expSeries, xMax, plotSpec, 'exp2', 'ops'),
|
data: genOpXY(expSeries, xMax, plotSpec, 'exp2', 'ut_ops'),
|
||||||
lines: { show: true },
|
lines: { show: true },
|
||||||
points: { show: true }
|
points: { show: true }
|
||||||
};
|
};
|
||||||
@ -58,106 +63,108 @@ $(function () {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
function doPlot(title, series) {
|
function doPlot(title, series, classes) {
|
||||||
var id = title.replace(/\W/g,'_');
|
var id = title.replace(/\W/g,'_');
|
||||||
$("#placeholder").append('<h1>' + title + '</h1><div id="' + id + '" class="graph"></div>');
|
$("#placeholder").append('<h3>' + title + '</h3><div id="show_hide_' + id + '" class="show_hide">Show/Hide</div><div id="' + id + '" class="graph"></div>');
|
||||||
$.plot($('#' + id),
|
var e = $('#' + id);
|
||||||
series,
|
$.plot(e, series, {
|
||||||
{
|
xaxis:{ ticks:xExpTicks },
|
||||||
xaxis: { ticks: xExpTicks },
|
yaxes:[
|
||||||
yaxes: [ { min: 0 } ],
|
{ min:0 }
|
||||||
legend: { position: 'ne' },
|
],
|
||||||
grid: { hoverable: true }
|
legend:{ position:'ne' },
|
||||||
});
|
grid:{ hoverable:true }
|
||||||
|
});
|
||||||
|
e.addClass(classes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// comment pending
|
// comment pending
|
||||||
var graph = [
|
var graph = [
|
||||||
[ 'value_string_size insert C versus Ruby', 14, 'mode',
|
[ '#placeholder', 'value_string_size insert C versus Ruby', 'hidden', 14, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'value_string_size', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'value_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'value_string_size', operation:'insert', mode: 'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'value_string_size', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'key_string_size insert C versus Ruby', 14, 'mode',
|
[ '#placeholder', 'key_string_size insert C versus Ruby', 'hidden', 14, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'key_string_size', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'key_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'key_string_size', operation:'insert', mode: 'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'key_string_size', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_size_fixnum insert C versus Ruby', 12, 'mode',
|
[ '#placeholder', 'array_size_fixnum insert C versus Ruby', 'hidden', 12, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'hash_size_fixnum insert C versus Ruby', 12, 'mode',
|
[ '#placeholder', 'hash_size_fixnum insert C versus Ruby', 'hidden', 12, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_nest_fixnum base 2 insert C versus Ruby', 12, 'mode',
|
[ '#placeholder', 'array_nest_fixnum base 2 insert C versus Ruby', 'hidden', 12, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'c', tag: 'array_slow' },
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'hash_nest_fixnum base 2 insert C versus Ruby', 12, 'mode',
|
[ '#placeholder', 'hash_nest_fixnum base 2 insert C versus Ruby', 'hidden', 12, 'mode',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'ruby', tag: 'orig_ruby' }
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'ruby', tag: 'base_ruby' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_nest_fixnum insert C by base', 12, 'base',
|
[ '#placeholder', 'array_nest_fixnum insert C by base', 'hidden', 12, 'base',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:4, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:4, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:8, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:8, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:16, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:16, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:32, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' }
|
{ base:32, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'hash_nest_fixnum insert C by base', 12, 'base',
|
[ '#placeholder', 'hash_nest_fixnum insert C by base', 'hidden', 12, 'base',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:4, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:4, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:8, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:8, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:16, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:16, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' },
|
||||||
{ base:32, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' }
|
{ base:32, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c_nest_full' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_size_fixnum slow versus hash_size_fixnum insert C', 12, 'generator',
|
[ '#placeholder', 'array_size_fixnum slow versus hash_size_fixnum insert C', '', 12, 'generator',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' }
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_size_fixnum slow versus fast insert C', 12, 'tag',
|
[ '#placeholder', 'array_size_fixnum slow versus fast insert C', 'hidden', 12, 'tag',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_size_fixnum fast versus hash_size_fixnum insert C', 12, 'generator',
|
[ '#placeholder', 'array_size_fixnum fast versus hash_size_fixnum insert C', 'hidden', 12, 'generator',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
||||||
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' }
|
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_nest_fixnum slow versus hash_nest_fixnum insert C base 2', 12, 'generator',
|
[ '#placeholder', 'array_nest_fixnum slow versus hash_nest_fixnum insert C base 2', 'hidden', 12, 'generator',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' }
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_nest_fixnum slow versus fast insert C base 2', 12, 'tag',
|
[ '#placeholder', 'array_nest_fixnum slow versus fast insert C base 2', 'hidden', 12, 'tag',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ 'array_nest_fixnum fast versus hash_nest_fixnum insert C base 2', 12, 'generator',
|
[ '#placeholder', 'array_nest_fixnum fast versus hash_nest_fixnum insert C base 2', 'hidden', 12, 'generator',
|
||||||
[
|
[
|
||||||
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' },
|
||||||
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
|
||||||
@ -165,10 +172,11 @@ $(function () {
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
$.each(graph, function(i, e){
|
$.each(graph, function(i, e){
|
||||||
var title, xMax, labelSpec, plotSpecs;
|
var section, title, classes, xMax, labelSpec, plotSpecs;
|
||||||
title = e[0]; xMax = e[1]; labelSpec = e[2]; plotSpecs = e[3]; //[title, xMax, labelSpec, plotSpecs] = e;
|
//[section, title, classes, xMax, labelSpec, plotSpecs] = e;
|
||||||
|
section = e[0], title = e[1]; classes = e[2], xMax = e[3]; labelSpec = e[4]; plotSpecs = e[5];
|
||||||
var series = flotSeries(expSeries, xMax, labelSpec, plotSpecs);
|
var series = flotSeries(expSeries, xMax, labelSpec, plotSpecs);
|
||||||
doPlot(title, series);
|
doPlot(title, series, classes);
|
||||||
});
|
});
|
||||||
|
|
||||||
function showTooltip(x, y, contents) {
|
function showTooltip(x, y, contents) {
|
||||||
@ -206,6 +214,11 @@ $(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.show_hide').bind('click', function(event) {
|
||||||
|
var id = $(this).attr('id').replace(/^show_hide_/, '');
|
||||||
|
$('#' + id).toggleClass('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
1130
bench/exp_series.js
1130
bench/exp_series.js
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@ $calibration_runtime = 0.1
|
|||||||
$target_runtime = 5.0
|
$target_runtime = 5.0
|
||||||
$db_name = 'benchmark'
|
$db_name = 'benchmark'
|
||||||
$collection_name = 'exp_series'
|
$collection_name = 'exp_series'
|
||||||
$mode = set_mode('ruby')
|
$mode = set_mode('c')
|
||||||
$hostname = `uname -n`[/([^.]*)/,1]
|
$hostname = `uname -n`[/([^.]*)/,1]
|
||||||
$osname = `uname -s`.strip
|
$osname = `uname -s`.strip
|
||||||
$tag = `git log -1 --format=oneline`.split[0]
|
$tag = `git log -1 --format=oneline`.split[0]
|
||||||
@ -34,7 +34,7 @@ $date = Time.now.strftime('%Y%m%d-%H%M')
|
|||||||
|
|
||||||
options_with_help = [
|
options_with_help = [
|
||||||
[ '--help', '-h', GetoptLong::NO_ARGUMENT, '', 'show help' ],
|
[ '--help', '-h', GetoptLong::NO_ARGUMENT, '', 'show help' ],
|
||||||
[ '--mode', '-m', GetoptLong::OPTIONAL_ARGUMENT, ' mode', 'set mode to "c" or "ruby" (default)' ],
|
[ '--mode', '-m', GetoptLong::OPTIONAL_ARGUMENT, ' mode', 'set mode to "c" or "ruby" (c)' ],
|
||||||
[ '--tag', '-t', GetoptLong::OPTIONAL_ARGUMENT, ' tag', 'set tag for run, default is git commit key' ]
|
[ '--tag', '-t', GetoptLong::OPTIONAL_ARGUMENT, ' tag', 'set tag for run, default is git commit key' ]
|
||||||
]
|
]
|
||||||
options = options_with_help.collect{|option|option[0...3]}
|
options = options_with_help.collect{|option|option[0...3]}
|
||||||
@ -88,13 +88,6 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
return Array.new(base, array_nest(base, level - 1, obj))
|
return Array.new(base, array_nest(base, level - 1, obj))
|
||||||
end
|
end
|
||||||
|
|
||||||
def hash_nest(base, level, obj)
|
|
||||||
return obj if level == 0
|
|
||||||
h = Hash.new
|
|
||||||
(0...base).each{|i| h[i.to_s] = hash_nest(base, level - 1, obj)}
|
|
||||||
return h
|
|
||||||
end
|
|
||||||
|
|
||||||
def test__array_nest
|
def test__array_nest
|
||||||
assert_equal(1, array_nest(2,0,1))
|
assert_equal(1, array_nest(2,0,1))
|
||||||
assert_equal([1, 1], array_nest(2,1,1))
|
assert_equal([1, 1], array_nest(2,1,1))
|
||||||
@ -107,6 +100,13 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
assert_equal([1, 1, 1, 1, 1, 1, 1, 1], array_nest(8,1,1))
|
assert_equal([1, 1, 1, 1, 1, 1, 1, 1], array_nest(8,1,1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hash_nest(base, level, obj)
|
||||||
|
return obj if level == 0
|
||||||
|
h = Hash.new
|
||||||
|
(0...base).each{|i| h[i.to_s] = hash_nest(base, level - 1, obj)}
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
|
||||||
def test__hash_nest
|
def test__hash_nest
|
||||||
assert_equal(1, hash_nest(2, 0, 1))
|
assert_equal(1, hash_nest(2, 0, 1))
|
||||||
assert_equal({"0"=>1, "1"=>1}, hash_nest(2, 1, 1))
|
assert_equal({"0"=>1, "1"=>1}, hash_nest(2, 1, 1))
|
||||||
@ -123,6 +123,25 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
assert_equal({"0"=>1, "1"=>1, "2"=>1, "3"=>1, "4"=>1, "5"=>1, "6"=>1, "7"=>1}, hash_nest(8,1,1))
|
assert_equal({"0"=>1, "1"=>1, "2"=>1, "3"=>1, "4"=>1, "5"=>1, "6"=>1, "7"=>1}, hash_nest(8,1,1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def multi_doc(multi_power, doc)
|
||||||
|
return doc if multi_power == -1
|
||||||
|
return (2 ** multi_power).times.collect{doc.dup}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_multi_doc
|
||||||
|
doc = {'a' => 1}
|
||||||
|
assert_equal({"a"=>1}, multi_doc(-1, doc))
|
||||||
|
assert_equal([{"a"=>1}], multi_doc(0, doc))
|
||||||
|
assert_equal([{"a"=>1}, {"a"=>1}], multi_doc(1, doc))
|
||||||
|
assert_equal([{"a"=>1}, {"a"=>1}, {"a"=>1}, {"a"=>1}], multi_doc(2, doc))
|
||||||
|
assert_equal(8, multi_doc(3, doc).size)
|
||||||
|
assert_equal(16, multi_doc(4, doc).size)
|
||||||
|
assert_equal(32, multi_doc(5, doc).size)
|
||||||
|
mdoc = multi_doc(2, doc)
|
||||||
|
mdoc[0]['b'] = 2
|
||||||
|
assert_equal([{"a"=>1, "b"=>2}, {"a"=>1}, {"a"=>1}, {"a"=>1}], mdoc, 'non-dup doc will fail for insert many safe')
|
||||||
|
end
|
||||||
|
|
||||||
# Performance Tuning Engineering
|
# Performance Tuning Engineering
|
||||||
## Completed
|
## Completed
|
||||||
### How to measure and compare pure Ruby versus C extension performance
|
### How to measure and compare pure Ruby versus C extension performance
|
||||||
@ -167,7 +186,7 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
# consider inserting the results into a database collection
|
# consider inserting the results into a database collection
|
||||||
# Test::Unit::TestCase pollutes STDOUT, so write to a file
|
# Test::Unit::TestCase pollutes STDOUT, so write to a file
|
||||||
File.open("exp_series-#{$date}-#{$tag}.js", 'w+'){|f|
|
File.open("exp_series-#{$date}-#{$tag}.js", 'w+'){|f|
|
||||||
f.puts("#{@results.to_json.gsub(/\[/, "").gsub(/(}[\],])/, "},\n")}") unless @results.empty?
|
f.puts(@results.to_json.gsub(/\[/, "").gsub(/}[\],]/, "},\n")) unless @results.empty?
|
||||||
}
|
}
|
||||||
@conn.drop_database($db_name)
|
@conn.drop_database($db_name)
|
||||||
end
|
end
|
||||||
@ -206,34 +225,46 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
return [iterations, utime, rtime, etime]
|
return [iterations, utime, rtime, etime]
|
||||||
end
|
end
|
||||||
|
|
||||||
def power_test(base, max_power, db, coll, generator, setup, operation, teardown)
|
def power_test(args)
|
||||||
|
base, max_power, multi, generator, setup, operation, teardown = args
|
||||||
|
generator, setup, operation, teardown = method(generator), method(setup), method(operation), method(teardown)
|
||||||
return (0..max_power).collect do |power|
|
return (0..max_power).collect do |power|
|
||||||
size, doc = generator.call(base, power)
|
multi_start, multi_end = (multi == -1) ? [-1, -1] : [0, multi]
|
||||||
iterations, utime, rtime, etime = valuate(db, coll, doc, setup, teardown) { operation.call(coll, doc) }
|
(multi_start..multi_end).collect do |multi_power|
|
||||||
result = {
|
size, doc = generator.call(base, power)
|
||||||
'base' => base,
|
doc = multi_doc(multi_power, doc)
|
||||||
'power' => power,
|
multi_size = (doc.class == Array) ? doc.size : 1;
|
||||||
'size' => size,
|
iterations, utime, rtime, etime = valuate(@db, @coll, doc, setup, teardown) { operation.call(@coll, doc) }
|
||||||
'exp2' => Math.log2(size).to_i,
|
multi_iterations = multi_size.to_f * iterations.to_f
|
||||||
'generator' => generator.name.to_s,
|
result = {
|
||||||
'operation' => operation.name.to_s,
|
'base' => base,
|
||||||
'iterations' => iterations,
|
'power' => power,
|
||||||
'utime' => utime.round(2),
|
'size' => size,
|
||||||
'etime' => etime.round(2),
|
'exp2' => Math.log2(size).to_i,
|
||||||
'rtime' => rtime.round(2),
|
'multi_power' => multi_power,
|
||||||
'ops' => (iterations.to_f / utime.to_f).round(1),
|
'multi_size' => multi_size,
|
||||||
'usec' => (1000000.0 * utime.to_f / iterations.to_f).round(1),
|
'generator' => generator.name.to_s,
|
||||||
'mode' => $mode,
|
'operation' => operation.name.to_s,
|
||||||
'hostname' => $hostname,
|
'iterations' => iterations,
|
||||||
'osname' => $osname,
|
'utime' => utime.round(2),
|
||||||
'date' => $date,
|
'rtime' => rtime.round(2),
|
||||||
'tag' => $tag,
|
'ut_ops' => (multi_iterations / utime.to_f).round(1),
|
||||||
# 'nbench-int' => nbench.int, # thinking
|
'rt_ops' => (multi_iterations / rtime.to_f).round(1),
|
||||||
}
|
'ut_usec' => (1000000.0 * utime.to_f / multi_iterations).round(1),
|
||||||
STDERR.puts result.inspect
|
'rt_usec' => (1000000.0 * rtime.to_f / multi_iterations).round(1),
|
||||||
STDERR.flush
|
'etime' => etime.round(2),
|
||||||
result
|
'mode' => $mode,
|
||||||
end
|
'hostname' => $hostname,
|
||||||
|
'osname' => $osname,
|
||||||
|
'date' => $date,
|
||||||
|
'tag' => $tag,
|
||||||
|
# 'nbench-int' => nbench.int, # thinking
|
||||||
|
}
|
||||||
|
STDERR.puts result.inspect
|
||||||
|
STDERR.flush
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
def value_string_size(base, power)
|
def value_string_size(base, power)
|
||||||
@ -277,19 +308,27 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cursor_setup(db, coll, doc, iterations)
|
def cursor_setup(db, coll, doc, iterations)
|
||||||
(0...(iterations - coll.size)).each{insert(coll, doc)}
|
(0...(iterations - coll.size)).each{insert(coll, doc)} #TODO - insert many
|
||||||
@cursor = coll.find
|
@cursor = coll.find
|
||||||
@queries = 1
|
@queries = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_ids(doc) # delete :_id to really insert, required for safe
|
||||||
|
if doc.class == Array
|
||||||
|
doc.each{|d|d.delete(:_id)}
|
||||||
|
else
|
||||||
|
doc.delete(:_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def insert(coll, doc)
|
def insert(coll, doc)
|
||||||
doc.delete(:_id) # delete :_id to insert
|
clear_ids(doc)
|
||||||
coll.insert(doc) # note that insert stores :_id in doc and subsequent inserts are updates
|
coll.insert(doc) # note that insert stores :_id in doc and subsequent inserts are updates
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_safe(coll, doc)
|
def insert_safe(coll, doc)
|
||||||
doc.delete(:_id) # delete :_id to insert
|
clear_ids(doc)
|
||||||
coll.insert(doc, :safe => true) # note that insert stores :_id in doc and subsequent inserts are updates
|
coll.insert(doc, :safe => true) # note that insert stores :_id in doc and subsequent inserts with :_id are updates
|
||||||
end
|
end
|
||||||
|
|
||||||
def cursor_next(coll, doc)
|
def cursor_next(coll, doc)
|
||||||
@ -317,123 +356,99 @@ class TestExpPerformance < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_insert
|
def test_insert
|
||||||
tests = [
|
[
|
||||||
[2, 15, :value_string_size, :null_setup, :insert, :default_teardown],
|
[2, 15, -1, :value_string_size, :null_setup, :insert, :default_teardown],
|
||||||
[2, 15, :key_string_size, :null_setup, :insert, :default_teardown],
|
[2, 15, -1, :key_string_size, :null_setup, :insert, :default_teardown],
|
||||||
[2, 14, :array_size_fixnum, :null_setup, :insert, :default_teardown],
|
[2, 14, -1, :array_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[2, 17, :hash_size_fixnum, :null_setup, :insert, :default_teardown],
|
[2, 17, -1, :hash_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[2, 12, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[4, 6, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[8, 4, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
].each{|args| @results += power_test(args)}
|
||||||
[16, 3, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
end
|
||||||
[32, 2, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
|
||||||
[2, 15, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
def test_insert_nest_full
|
||||||
[4, 8, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[
|
||||||
[8, 4, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[16, 4, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[4, 6, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
[32, 3, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
[8, 4, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
]
|
[16, 3, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
[32, 2, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
# consider moving 'method' as permitted by scope
|
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
[4, 8, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
end
|
[8, 4, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[16, 4, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[32, 3, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
].each{|args| @results += power_test(args)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_array_fast
|
||||||
|
[
|
||||||
|
[2, 14, -1, :array_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[2, 17, -1, :hash_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
].each{|args| @results += power_test(args)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_insert_safe
|
def test_insert_safe
|
||||||
tests = [
|
[
|
||||||
[2, 15, :value_string_size, :null_setup, :insert_safe, :default_teardown],
|
[2, 15, -1, :value_string_size, :null_setup, :insert_safe, :default_teardown],
|
||||||
[2, 15, :key_string_size, :null_setup, :insert_safe, :default_teardown],
|
[2, 15, -1, :key_string_size, :null_setup, :insert_safe, :default_teardown],
|
||||||
[2, 14, :array_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
[2, 14, -1, :array_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
[2, 17, :hash_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
[2, 17, -1, :hash_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
[2, 12, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
[4, 6, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
[8, 4, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
].each{|args| @results += power_test(args)}
|
||||||
[16, 3, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[32, 2, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[2, 15, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[4, 8, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[8, 4, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[16, 4, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
[32, 3, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
|
|
||||||
]
|
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
|
||||||
# consider moving 'method' as permitted by scope
|
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def xtest_insert_many
|
def test_insert_many
|
||||||
|
[
|
||||||
|
[2, 2, 10, :value_string_size, :null_setup, :insert, :default_teardown],
|
||||||
|
[2, 14, 10, :hash_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
[2, 14, 10, :array_size_fixnum, :null_setup, :insert, :default_teardown],
|
||||||
|
].each{|args| @results += power_test(args)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def xtest_insert_many_safe
|
def test_insert_many_safe
|
||||||
|
[
|
||||||
|
[2, 2, 10, :value_string_size, :null_setup, :insert_safe, :default_teardown],
|
||||||
|
[2, 14, 10, :hash_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
|
[2, 14, 10, :array_size_fixnum, :null_setup, :insert_safe, :default_teardown],
|
||||||
|
].each{|args| @results += power_test(args)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_find
|
def test_find
|
||||||
tests = [
|
[
|
||||||
[2, 15, :value_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 15, -1, :value_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[2, 15, :key_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 15, -1, :key_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[2, 14, :array_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 14, -1, :array_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[2, 17, :hash_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 17, -1, :hash_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[2, 12, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 12, -1, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[4, 6, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
[2, 15, -1, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
||||||
[8, 4, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
].each{|args| @results += power_test(args)}
|
||||||
[16, 3, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[32, 2, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[2, 15, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[4, 8, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[8, 4, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[16, 4, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
[32, 3, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
|
|
||||||
]
|
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
|
||||||
# consider moving 'method' as permitted by scope
|
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_find_one
|
def test_find_one
|
||||||
tests = [
|
[
|
||||||
[2, 15, :value_string_size, :find_one_setup, :find_one, :default_teardown],
|
[2, 15, -1, :value_string_size, :find_one_setup, :find_one, :default_teardown],
|
||||||
[2, 15, :key_string_size, :find_one_setup, :find_one, :default_teardown],
|
[2, 15, -1, :key_string_size, :find_one_setup, :find_one, :default_teardown],
|
||||||
[2, 14, :array_size_fixnum, :find_one_setup, :find_one, :default_teardown],
|
[2, 14, -1, :array_size_fixnum, :find_one_setup, :find_one, :default_teardown],
|
||||||
[2, 17, :hash_size_fixnum, :find_one_setup, :find_one, :default_teardown],
|
[2, 17, -1, :hash_size_fixnum, :find_one_setup, :find_one, :default_teardown],
|
||||||
[2, 12, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
[2, 12, -1, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
||||||
[4, 6, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
[2, 15, -1, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
||||||
[8, 4, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
].each{|args| @results += power_test(args)}
|
||||||
[16, 3, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[32, 2, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[2, 15, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[4, 8, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[8, 4, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[16, 4, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
[32, 3, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
|
|
||||||
]
|
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
|
||||||
# consider moving 'method' as permitted by scope
|
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def xtest_update
|
def xtest_update
|
||||||
tests = [
|
[
|
||||||
# pending
|
# pending
|
||||||
]
|
].each{|args| @results += power_test(args)}
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
|
||||||
# consider moving 'method' as permitted by scope
|
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def xtest_remove
|
def xtest_remove
|
||||||
tests = [
|
[
|
||||||
# pending
|
# pending
|
||||||
]
|
].each{|args| @results += power_test(args)}
|
||||||
tests.each do |base, max_power, generator, setup, operation, teardown|
|
|
||||||
# consider moving 'method' as permitted by scope
|
|
||||||
@results += power_test(base, max_power, @db, @coll, method(generator), method(setup), method(operation), method(teardown))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# synthesized mix, real-world data pending
|
# synthesized mix, real-world data pending
|
||||||
|
@ -139,14 +139,38 @@ static void write_utf8(bson_buffer_t buffer, VALUE string, char check_null) {
|
|||||||
#define EXTENDED RE_OPTION_EXTENDED
|
#define EXTENDED RE_OPTION_EXTENDED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ARRAY_KEY_BUFFER_SIZE 10
|
/* TODO we ought to check that the malloc or asprintf was successful
|
||||||
// use 8^(ARRAY_KEY_BUFFER_SIZE-1) as CPP safe bounds approximation for limit of 10^(ARRAY_KEY_BUFFER_SIZE-1)-1
|
* and raise an exception if not. */
|
||||||
#define ARRAY_KEY_MAX_CPP (1 << (3 * (ARRAY_KEY_BUFFER_SIZE-1)))
|
/* TODO maybe we can use something more portable like vsnprintf instead
|
||||||
|
* of this hack. And share it with the Python extension ;) */
|
||||||
|
/* If we don't have ASPRINTF, there are two possibilities:
|
||||||
|
* either use _scprintf and _snprintf on for Windows or
|
||||||
|
* use snprintf for solaris. */
|
||||||
|
#ifndef HAVE_ASPRINTF
|
||||||
#ifdef _WIN32 || _MSC_VER
|
#ifdef _WIN32 || _MSC_VER
|
||||||
#define SNPRINTF _snprintf
|
#define INT2STRING(buffer, i) \
|
||||||
|
{ \
|
||||||
|
int vslength = _scprintf("%d", i) + 1; \
|
||||||
|
*buffer = malloc(vslength); \
|
||||||
|
_snprintf(*buffer, vslength, "%d", i); \
|
||||||
|
}
|
||||||
|
#define FREE_INTSTRING(buffer) free(buffer)
|
||||||
#else
|
#else
|
||||||
#define SNPRINTF snprintf
|
#define INT2STRING(buffer, i) \
|
||||||
|
{ \
|
||||||
|
int vslength = snprintf(NULL, 0, "%d", i) + 1; \
|
||||||
|
*buffer = malloc(vslength); \
|
||||||
|
snprintf(*buffer, vslength, "%d", i); \
|
||||||
|
}
|
||||||
|
#define FREE_INTSTRING(buffer) free(buffer)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define INT2STRING(buffer, i) asprintf(buffer, "%d", i);
|
||||||
|
#ifdef USING_SYSTEM_ALLOCATOR_LIBRARY /* Ruby Enterprise Edition with tcmalloc */
|
||||||
|
#define FREE_INTSTRING(buffer) system_free(buffer)
|
||||||
|
#else
|
||||||
|
#define FREE_INTSTRING(buffer) free(buffer)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RREGEXP_SRC
|
#ifndef RREGEXP_SRC
|
||||||
@ -277,7 +301,6 @@ static int write_element(VALUE key, VALUE value, VALUE extra, int allow_id) {
|
|||||||
bson_buffer_position length_location, start_position, obj_length;
|
bson_buffer_position length_location, start_position, obj_length;
|
||||||
int items, i;
|
int items, i;
|
||||||
VALUE* values;
|
VALUE* values;
|
||||||
char name[ARRAY_KEY_BUFFER_SIZE];
|
|
||||||
|
|
||||||
write_name_and_type(buffer, key, 0x04);
|
write_name_and_type(buffer, key, 0x04);
|
||||||
start_position = bson_buffer_get_position(buffer);
|
start_position = bson_buffer_get_position(buffer);
|
||||||
@ -289,14 +312,15 @@ static int write_element(VALUE key, VALUE value, VALUE extra, int allow_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
items = RARRAY_LENINT(value);
|
items = RARRAY_LENINT(value);
|
||||||
if (items > ARRAY_KEY_MAX_CPP)
|
|
||||||
rb_raise(rb_eTypeError, "array size too large");
|
|
||||||
for(i = 0; i < items; i++) {
|
for(i = 0; i < items; i++) {
|
||||||
|
char* name;
|
||||||
VALUE key;
|
VALUE key;
|
||||||
SNPRINTF(name, ARRAY_KEY_BUFFER_SIZE, "%d", i);
|
INT2STRING(&name, i);
|
||||||
key = rb_str_new2(name);
|
key = rb_str_new2(name);
|
||||||
write_element_with_id(key, rb_ary_entry(value, i), pack_extra(buffer, check_keys));
|
write_element_with_id(key, rb_ary_entry(value, i), pack_extra(buffer, check_keys));
|
||||||
|
FREE_INTSTRING(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write null byte and fill in length
|
// write null byte and fill in length
|
||||||
SAFE_WRITE(buffer, &zero, 1);
|
SAFE_WRITE(buffer, &zero, 1);
|
||||||
obj_length = bson_buffer_get_position(buffer) - start_position;
|
obj_length = bson_buffer_get_position(buffer) - start_position;
|
||||||
|
Loading…
Reference in New Issue
Block a user