Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 50d6902d80c65d592d75f5cb0c4019de36319efc 1 parent ca7bf20
@gjmurakami-10gen gjmurakami-10gen authored
View
2  Gemfile
@@ -9,6 +9,8 @@ group :development, :test do
# Deployment
gem "git"
+ gem "redcarpet"
+ gem "yard"
# Testing
gem "mocha"
View
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
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
131 bench/exp_series.html
@@ -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 @@
}
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,
- {
- xaxis: { ticks: xExpTicks },
- yaxes: [ { min: 0 } ],
- legend: { position: 'ne' },
- grid: { hoverable: true }
- });
+ $("#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 }
+ ],
+ 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 @@
],
];
$.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 @@
}
});
+ $('.show_hide').bind('click', function(event) {
+ var id = $(this).attr('id').replace(/^show_hide_/, '');
+ $('#' + id).toggleClass('hidden');
+ });
+
});
</script>
</body>
View
1,130 bench/exp_series.js
706 additions, 424 deletions not shown
View
289 bench/exp_series.rb
@@ -26,7 +26,7 @@ def set_mode(mode)
$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 @@ def set_mode(mode)
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 @@ def array_nest(base, level, obj)
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 @@ def test__array_nest
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 @@ def test__hash_nest
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 @@ def teardown_test_set
# 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,34 +225,46 @@ def valuate(db, coll, doc, setup, teardown)
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|
- size, doc = generator.call(base, power)
- iterations, utime, rtime, etime = valuate(db, coll, doc, setup, teardown) { operation.call(coll, doc) }
- result = {
- 'base' => base,
- 'power' => power,
- 'size' => size,
- 'exp2' => Math.log2(size).to_i,
- '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),
- 'mode' => $mode,
- 'hostname' => $hostname,
- 'osname' => $osname,
- 'date' => $date,
- 'tag' => $tag,
- # 'nbench-int' => nbench.int, # thinking
- }
- STDERR.puts result.inspect
- STDERR.flush
- result
- end
+ multi_start, multi_end = (multi == -1) ? [-1, -1] : [0, multi]
+ (multi_start..multi_end).collect do |multi_power|
+ size, doc = generator.call(base, power)
+ 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),
+ 'rtime' => rtime.round(2),
+ '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,
+ 'date' => $date,
+ 'tag' => $tag,
+ # 'nbench-int' => nbench.int, # thinking
+ }
+ STDERR.puts result.inspect
+ STDERR.flush
+ result
+ end
+ end.flatten
end
def value_string_size(base, power)
@@ -277,19 +308,27 @@ def find_one_setup(db, coll, doc, iterations)
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 @@ def cursor_teardown(db, coll)
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))
- end
+ [
+ [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
44 ext/cbson/cbson.c
@@ -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 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 SNPRINTF snprintf
+#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;
Please sign in to comment.
Something went wrong with that request. Please try again.