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:
Gary Murakami 2012-05-03 16:43:12 -04:00
parent ca7bf209dd
commit 50d6902d80
6 changed files with 980 additions and 639 deletions

View File

@ -9,6 +9,8 @@ group :development, :test do
# Deployment
gem "git"
gem "redcarpet"
gem "yard"
# Testing
gem "mocha"

View File

@ -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
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
# 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
See HISTORY.

View File

@ -18,13 +18,18 @@
width:800px;
height:400px;
}
div.hidden {
//display: none; //visibility: hidden; // to collapse, use display: none
}
</style>
</head>
<body>
<h1>Exp Series Performance Tests</h1>
x-axis is power of 2, log base 2 of size<br>
y-axis is operations per user-time CPU-second<br>
Note that this is not operations per real-time second that include DB real-time<br>
y-axis is "document" operations per second, ex., total document insertions per second<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>
<script type="text/javascript">
@ -42,7 +47,7 @@
return $.map(plotSpecs, function(plotSpec, i){
return {
label: labelSpec + ': ' + plotSpec[labelSpec],
data: genOpXY(expSeries, xMax, plotSpec, 'exp2', 'ops'),
data: genOpXY(expSeries, xMax, plotSpec, 'exp2', 'ut_ops'),
lines: { show: true },
points: { show: true }
};
@ -58,106 +63,108 @@ $(function () {
}
return res;
}
function doPlot(title, series) {
function doPlot(title, series, classes) {
var id = title.replace(/\W/g,'_');
$("#placeholder").append('<h1>' + title + '</h1><div id="' + id + '" class="graph"></div>');
$.plot($('#' + id),
series,
{
$("#placeholder").append('<h3>' + title + '</h3><div id="show_hide_' + id + '" class="show_hide">Show/Hide</div><div id="' + id + '" class="graph"></div>');
var e = $('#' + id);
$.plot(e, series, {
xaxis:{ ticks:xExpTicks },
yaxes: [ { min: 0 } ],
yaxes:[
{ min:0 }
],
legend:{ position:'ne' },
grid:{ hoverable:true }
});
e.addClass(classes);
}
// comment pending
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: 'ruby', tag: 'orig_ruby' }
{ base:2, generator:'value_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
{ 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: 'ruby', tag: 'orig_ruby' }
{ base:2, generator:'key_string_size', operation:'insert', mode: 'c', tag: 'base_c' },
{ 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: 'ruby', tag: 'orig_ruby' }
{ base:2, generator:'array_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
{ 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: 'ruby', tag: 'orig_ruby' }
{ base:2, generator:'hash_size_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
{ 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:'ruby', tag: 'orig_ruby' }
{ base:2, generator:'array_nest_fixnum', operation:'insert', mode:'c', tag: 'base_c' },
{ 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: 'ruby', tag: 'orig_ruby' }
{ base:2, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'base_c' },
{ 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:4, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:8, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:16, generator:'array_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:32, 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: 'base_c_nest_full' },
{ 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: 'base_c_nest_full' },
{ 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:4, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:8, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:16, generator:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_slow' },
{ base:32, 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: 'base_c_nest_full' },
{ 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: 'base_c_nest_full' },
{ 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:'hash_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: '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' }
]
],
[ '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:'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:'hash_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: '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' }
]
],
[ '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:'hash_nest_fixnum', operation:'insert', mode: 'c', tag: 'array_fast' }
@ -165,10 +172,11 @@ $(function () {
],
];
$.each(graph, function(i, e){
var title, xMax, labelSpec, plotSpecs;
title = e[0]; xMax = e[1]; labelSpec = e[2]; plotSpecs = e[3]; //[title, xMax, labelSpec, plotSpecs] = e;
var section, title, classes, xMax, labelSpec, plotSpecs;
//[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);
doPlot(title, series);
doPlot(title, series, classes);
});
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>
</body>

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@ $calibration_runtime = 0.1
$target_runtime = 5.0
$db_name = 'benchmark'
$collection_name = 'exp_series'
$mode = set_mode('ruby')
$mode = set_mode('c')
$hostname = `uname -n`[/([^.]*)/,1]
$osname = `uname -s`.strip
$tag = `git log -1 --format=oneline`.split[0]
@ -34,7 +34,7 @@ $date = Time.now.strftime('%Y%m%d-%H%M')
options_with_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' ]
]
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))
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
assert_equal(1, array_nest(2,0,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))
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
assert_equal(1, hash_nest(2, 0, 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))
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
## Completed
### 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
# Test::Unit::TestCase pollutes STDOUT, so write to a file
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)
end
@ -206,23 +225,34 @@ class TestExpPerformance < Test::Unit::TestCase
return [iterations, utime, rtime, etime]
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|
multi_start, multi_end = (multi == -1) ? [-1, -1] : [0, multi]
(multi_start..multi_end).collect do |multi_power|
size, doc = generator.call(base, power)
iterations, utime, rtime, etime = valuate(db, coll, doc, setup, teardown) { operation.call(coll, doc) }
doc = multi_doc(multi_power, doc)
multi_size = (doc.class == Array) ? doc.size : 1;
iterations, utime, rtime, etime = valuate(@db, @coll, doc, setup, teardown) { operation.call(@coll, doc) }
multi_iterations = multi_size.to_f * iterations.to_f
result = {
'base' => base,
'power' => power,
'size' => size,
'exp2' => Math.log2(size).to_i,
'multi_power' => multi_power,
'multi_size' => multi_size,
'generator' => generator.name.to_s,
'operation' => operation.name.to_s,
'iterations' => iterations,
'utime' => utime.round(2),
'etime' => etime.round(2),
'rtime' => rtime.round(2),
'ops' => (iterations.to_f / utime.to_f).round(1),
'usec' => (1000000.0 * utime.to_f / iterations.to_f).round(1),
'ut_ops' => (multi_iterations / utime.to_f).round(1),
'rt_ops' => (multi_iterations / rtime.to_f).round(1),
'ut_usec' => (1000000.0 * utime.to_f / multi_iterations).round(1),
'rt_usec' => (1000000.0 * rtime.to_f / multi_iterations).round(1),
'etime' => etime.round(2),
'mode' => $mode,
'hostname' => $hostname,
'osname' => $osname,
@ -234,6 +264,7 @@ class TestExpPerformance < Test::Unit::TestCase
STDERR.flush
result
end
end.flatten
end
def value_string_size(base, power)
@ -277,19 +308,27 @@ class TestExpPerformance < Test::Unit::TestCase
end
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
@queries = 1
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)
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
end
def insert_safe(coll, doc)
doc.delete(:_id) # delete :_id to insert
coll.insert(doc, :safe => true) # note that insert stores :_id in doc and subsequent inserts are updates
clear_ids(doc)
coll.insert(doc, :safe => true) # note that insert stores :_id in doc and subsequent inserts with :_id are updates
end
def cursor_next(coll, doc)
@ -317,123 +356,99 @@ class TestExpPerformance < Test::Unit::TestCase
end
def test_insert
tests = [
[2, 15, :value_string_size, :null_setup, :insert, :default_teardown],
[2, 15, :key_string_size, :null_setup, :insert, :default_teardown],
[2, 14, :array_size_fixnum, :null_setup, :insert, :default_teardown],
[2, 17, :hash_size_fixnum, :null_setup, :insert, :default_teardown],
[2, 12, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[4, 6, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[8, 4, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[16, 3, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[32, 2, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[2, 15, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[4, 8, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[8, 4, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[16, 4, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[32, 3, :hash_nest_fixnum, :null_setup, :insert, :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))
[
[2, 15, -1, :value_string_size, :null_setup, :insert, :default_teardown],
[2, 15, -1, :key_string_size, :null_setup, :insert, :default_teardown],
[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
def test_insert_nest_full
[
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[4, 6, -1, :array_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],
[32, 2, -1, :array_nest_fixnum, :null_setup, :insert, :default_teardown],
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[4, 8, -1, :hash_nest_fixnum, :null_setup, :insert, :default_teardown],
[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
def test_insert_safe
tests = [
[2, 15, :value_string_size, :null_setup, :insert_safe, :default_teardown],
[2, 15, :key_string_size, :null_setup, :insert_safe, :default_teardown],
[2, 14, :array_size_fixnum, :null_setup, :insert_safe, :default_teardown],
[2, 17, :hash_size_fixnum, :null_setup, :insert_safe, :default_teardown],
[2, 12, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
[4, 6, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
[8, 4, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
[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
[
[2, 15, -1, :value_string_size, :null_setup, :insert_safe, :default_teardown],
[2, 15, -1, :key_string_size, :null_setup, :insert_safe, :default_teardown],
[2, 14, -1, :array_size_fixnum, :null_setup, :insert_safe, :default_teardown],
[2, 17, -1, :hash_size_fixnum, :null_setup, :insert_safe, :default_teardown],
[2, 12, -1, :array_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
[2, 15, -1, :hash_nest_fixnum, :null_setup, :insert_safe, :default_teardown],
].each{|args| @results += power_test(args)}
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
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
def test_find
tests = [
[2, 15, :value_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 15, :key_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 14, :array_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 17, :hash_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 12, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[4, 6, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[8, 4, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[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
[
[2, 15, -1, :value_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 15, -1, :key_string_size, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 14, -1, :array_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 17, -1, :hash_size_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 12, -1, :array_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
[2, 15, -1, :hash_nest_fixnum, :cursor_setup, :cursor_next, :cursor_teardown],
].each{|args| @results += power_test(args)}
end
def test_find_one
tests = [
[2, 15, :value_string_size, :find_one_setup, :find_one, :default_teardown],
[2, 15, :key_string_size, :find_one_setup, :find_one, :default_teardown],
[2, 14, :array_size_fixnum, :find_one_setup, :find_one, :default_teardown],
[2, 17, :hash_size_fixnum, :find_one_setup, :find_one, :default_teardown],
[2, 12, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
[4, 6, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
[8, 4, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
[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
[
[2, 15, -1, :value_string_size, :find_one_setup, :find_one, :default_teardown],
[2, 15, -1, :key_string_size, :find_one_setup, :find_one, :default_teardown],
[2, 14, -1, :array_size_fixnum, :find_one_setup, :find_one, :default_teardown],
[2, 17, -1, :hash_size_fixnum, :find_one_setup, :find_one, :default_teardown],
[2, 12, -1, :array_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
[2, 15, -1, :hash_nest_fixnum, :find_one_setup, :find_one, :default_teardown],
].each{|args| @results += power_test(args)}
end
def xtest_update
tests = [
[
# pending
]
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
].each{|args| @results += power_test(args)}
end
def xtest_remove
tests = [
[
# pending
]
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
].each{|args| @results += power_test(args)}
end
# synthesized mix, real-world data pending

View File

@ -139,14 +139,38 @@ static void write_utf8(bson_buffer_t buffer, VALUE string, char check_null) {
#define EXTENDED RE_OPTION_EXTENDED
#endif
#define ARRAY_KEY_BUFFER_SIZE 10
// use 8^(ARRAY_KEY_BUFFER_SIZE-1) as CPP safe bounds approximation for limit of 10^(ARRAY_KEY_BUFFER_SIZE-1)-1
#define ARRAY_KEY_MAX_CPP (1 << (3 * (ARRAY_KEY_BUFFER_SIZE-1)))
/* TODO we ought to check that the malloc or asprintf was successful
* and raise an exception if not. */
/* 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
#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
#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
#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;
int items, i;
VALUE* values;
char name[ARRAY_KEY_BUFFER_SIZE];
write_name_and_type(buffer, key, 0x04);
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);
if (items > ARRAY_KEY_MAX_CPP)
rb_raise(rb_eTypeError, "array size too large");
for(i = 0; i < items; i++) {
char* name;
VALUE key;
SNPRINTF(name, ARRAY_KEY_BUFFER_SIZE, "%d", i);
INT2STRING(&name, i);
key = rb_str_new2(name);
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
SAFE_WRITE(buffer, &zero, 1);
obj_length = bson_buffer_get_position(buffer) - start_position;