mongodb-mongo_ext 0.1.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +10 -5
- data/ext/cbson/cbson.c +93 -44
- data/ext/cbson/extconf.rb +2 -0
- data/mongo-extensions.gemspec +1 -1
- metadata +2 -2
data/Rakefile
CHANGED
@@ -11,6 +11,9 @@ end
|
|
11
11
|
require 'rbconfig'
|
12
12
|
include Config
|
13
13
|
|
14
|
+
gem_command = "gem"
|
15
|
+
gem_command = "gem1.9" if CONFIG["MAJOR"] == "1" && CONFIG["MINOR"] == "9"
|
16
|
+
|
14
17
|
# NOTE: some of the tests assume Mongo is running
|
15
18
|
Rake::TestTask.new do |t|
|
16
19
|
t.test_files = FileList['tests/test*.rb']
|
@@ -18,8 +21,10 @@ end
|
|
18
21
|
|
19
22
|
desc "Generate documentation"
|
20
23
|
task :rdoc do
|
24
|
+
version = eval(File.read("mongo-ruby-driver.gemspec")).version
|
25
|
+
out = File.join('html', version.to_s)
|
21
26
|
FileUtils.rm_rf('html')
|
22
|
-
system "rdoc --main README.rdoc --op
|
27
|
+
system "rdoc --main README.rdoc --op #{out} --inline-source --quiet README.rdoc `find lib -name '*.rb'`"
|
23
28
|
end
|
24
29
|
|
25
30
|
desc "Publish documentation to mongo.rubyforge.org"
|
@@ -33,8 +38,8 @@ namespace :gem do
|
|
33
38
|
desc "Install the gem locally"
|
34
39
|
task :install do
|
35
40
|
sh <<EOS
|
36
|
-
|
37
|
-
sudo
|
41
|
+
#{gem_command} build mongo-ruby-driver.gemspec &&
|
42
|
+
sudo #{gem_command} install mongo-*.gem &&
|
38
43
|
rm mongo-*.gem
|
39
44
|
EOS
|
40
45
|
end
|
@@ -42,8 +47,8 @@ EOS
|
|
42
47
|
desc "Install the optional c extensions"
|
43
48
|
task :install_extensions do
|
44
49
|
sh <<EOS
|
45
|
-
|
46
|
-
sudo
|
50
|
+
#{gem_command} build mongo-extensions.gemspec &&
|
51
|
+
sudo #{gem_command} install mongo_ext-*.gem &&
|
47
52
|
rm mongo_ext-*.gem
|
48
53
|
EOS
|
49
54
|
end
|
data/ext/cbson/cbson.c
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
#include "st.h"
|
25
25
|
#include "regex.h"
|
26
26
|
#include <assert.h>
|
27
|
+
#include <math.h>
|
27
28
|
|
28
29
|
#define INITIAL_BUFFER_SIZE 256
|
29
30
|
|
@@ -36,6 +37,23 @@ static VALUE Code;
|
|
36
37
|
static VALUE RegexpOfHolding;
|
37
38
|
static VALUE OrderedHash;
|
38
39
|
|
40
|
+
// this sucks. but for some reason these moved around between 1.8 and 1.9
|
41
|
+
#ifdef ONIGURUMA_H
|
42
|
+
#define IGNORECASE ONIG_OPTION_IGNORECASE
|
43
|
+
#define MULTILINE ONIG_OPTION_MULTILINE
|
44
|
+
#define EXTENDED ONIG_OPTION_EXTEND
|
45
|
+
#else
|
46
|
+
#define IGNORECASE RE_OPTION_IGNORECASE
|
47
|
+
#define MULTILINE RE_OPTION_MULTILINE
|
48
|
+
#define EXTENDED RE_OPTION_EXTENDED
|
49
|
+
#endif
|
50
|
+
|
51
|
+
// this sucks too.
|
52
|
+
#ifndef RREGEXP_SRC_PTR
|
53
|
+
#define RREGEXP_SRC_PTR(r) RREGEXP(r)->str
|
54
|
+
#define RREGEXP_SRC_LEN(r) RREGEXP(r)->len
|
55
|
+
#endif
|
56
|
+
|
39
57
|
typedef struct {
|
40
58
|
char* buffer;
|
41
59
|
int size;
|
@@ -49,7 +67,7 @@ static int cmp_char(const void* a, const void* b) {
|
|
49
67
|
return *(char*)a - *(char*)b;
|
50
68
|
}
|
51
69
|
|
52
|
-
static void write_doc(bson_buffer* buffer, VALUE hash);
|
70
|
+
static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys);
|
53
71
|
static int write_element(VALUE key, VALUE value, VALUE extra);
|
54
72
|
static VALUE elements_to_hash(const char* buffer, int max);
|
55
73
|
|
@@ -109,14 +127,19 @@ static void buffer_write_bytes(bson_buffer* buffer, const char* bytes, int size)
|
|
109
127
|
buffer->position += size;
|
110
128
|
}
|
111
129
|
|
130
|
+
static VALUE pack_extra(bson_buffer* buffer, VALUE check_keys) {
|
131
|
+
return rb_ary_new3(2, INT2NUM((int)buffer), check_keys);
|
132
|
+
}
|
133
|
+
|
112
134
|
static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) {
|
113
135
|
buffer_write_bytes(buffer, &type, 1);
|
114
|
-
buffer_write_bytes(buffer,
|
136
|
+
buffer_write_bytes(buffer, RSTRING_PTR(name), RSTRING_LEN(name));
|
115
137
|
buffer_write_bytes(buffer, &zero, 1);
|
116
138
|
}
|
117
139
|
|
118
140
|
static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow_id) {
|
119
|
-
bson_buffer* buffer = (bson_buffer*)extra;
|
141
|
+
bson_buffer* buffer = (bson_buffer*)NUM2INT(rb_ary_entry(extra, 0));
|
142
|
+
VALUE check_keys = rb_ary_entry(extra, 1);
|
120
143
|
|
121
144
|
if (TYPE(key) == T_SYMBOL) {
|
122
145
|
// TODO better way to do this... ?
|
@@ -127,13 +150,29 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
127
150
|
rb_raise(rb_eTypeError, "keys must be strings or symbols");
|
128
151
|
}
|
129
152
|
|
130
|
-
if (!allow_id && strcmp("_id",
|
153
|
+
if (!allow_id && strcmp("_id", RSTRING_PTR(key)) == 0) {
|
131
154
|
return ST_CONTINUE;
|
132
155
|
}
|
133
156
|
|
157
|
+
if (check_keys == Qtrue) {
|
158
|
+
if (RSTRING_LEN(key) > 0 && RSTRING_PTR(key)[0] == '$') {
|
159
|
+
rb_raise(rb_eRuntimeError, "key must not start with '$'");
|
160
|
+
}
|
161
|
+
int i;
|
162
|
+
for (i = 0; i < RSTRING_LEN(key); i++) {
|
163
|
+
if (RSTRING_PTR(key)[i] == '.') {
|
164
|
+
rb_raise(rb_eRuntimeError, "key must not contain '.'");
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
134
169
|
switch(TYPE(value)) {
|
135
170
|
case T_BIGNUM:
|
136
171
|
{
|
172
|
+
if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647)) == Qtrue ||
|
173
|
+
rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648)) == Qtrue) {
|
174
|
+
rb_raise(rb_eRangeError, "MongoDB can only handle 4-byte ints - try converting to a double before saving");
|
175
|
+
}
|
137
176
|
write_name_and_type(buffer, key, 0x10);
|
138
177
|
VALUE as_f = rb_funcall(value, rb_intern("to_f"), 0);
|
139
178
|
int int_value = NUM2LL(as_f);
|
@@ -174,7 +213,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
174
213
|
case T_HASH:
|
175
214
|
{
|
176
215
|
write_name_and_type(buffer, key, 0x03);
|
177
|
-
write_doc(buffer, value);
|
216
|
+
write_doc(buffer, value, check_keys);
|
178
217
|
break;
|
179
218
|
}
|
180
219
|
case T_ARRAY:
|
@@ -192,7 +231,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
192
231
|
char* name;
|
193
232
|
asprintf(&name, "%d", i);
|
194
233
|
VALUE key = rb_str_new2(name);
|
195
|
-
write_element(key, values[i], (
|
234
|
+
write_element(key, values[i], pack_extra(buffer, check_keys));
|
196
235
|
free(name);
|
197
236
|
}
|
198
237
|
|
@@ -211,11 +250,11 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
211
250
|
int start_position = buffer->position;
|
212
251
|
int length_location = buffer_save_bytes(buffer, 4);
|
213
252
|
|
214
|
-
int length =
|
253
|
+
int length = RSTRING_LEN(value) + 1;
|
215
254
|
buffer_write_bytes(buffer, (char*)&length, 4);
|
216
|
-
buffer_write_bytes(buffer,
|
255
|
+
buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
|
217
256
|
buffer_write_bytes(buffer, &zero, 1);
|
218
|
-
write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0));
|
257
|
+
write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0), Qfalse);
|
219
258
|
|
220
259
|
int total_length = buffer->position - start_position;
|
221
260
|
memcpy(buffer->buffer + length_location, &total_length, 4);
|
@@ -223,9 +262,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
223
262
|
break;
|
224
263
|
} else {
|
225
264
|
write_name_and_type(buffer, key, 0x02);
|
226
|
-
int length =
|
265
|
+
int length = RSTRING_LEN(value) + 1;
|
227
266
|
buffer_write_bytes(buffer, (char*)&length, 4);
|
228
|
-
buffer_write_bytes(buffer,
|
267
|
+
buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1);
|
229
268
|
buffer_write_bytes(buffer, &zero, 1);
|
230
269
|
break;
|
231
270
|
}
|
@@ -249,7 +288,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
249
288
|
const char subtype = strcmp(cls, "ByteBuffer") ?
|
250
289
|
(const char)FIX2INT(rb_funcall(value, rb_intern("subtype"), 0)) : 2;
|
251
290
|
VALUE string_data = rb_funcall(value, rb_intern("to_s"), 0);
|
252
|
-
int length =
|
291
|
+
int length = RSTRING_LEN(string_data);
|
253
292
|
if (subtype == 2) {
|
254
293
|
const int other_length = length + 4;
|
255
294
|
buffer_write_bytes(buffer, (const char*)&other_length, 4);
|
@@ -259,7 +298,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
259
298
|
if (subtype != 2) {
|
260
299
|
buffer_write_bytes(buffer, &subtype, 1);
|
261
300
|
}
|
262
|
-
buffer_write_bytes(buffer,
|
301
|
+
buffer_write_bytes(buffer, RSTRING_PTR(string_data), length);
|
263
302
|
break;
|
264
303
|
}
|
265
304
|
if (strcmp(cls, "XGen::Mongo::Driver::ObjectID") == 0) {
|
@@ -267,7 +306,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
267
306
|
VALUE as_array = rb_funcall(value, rb_intern("to_a"), 0);
|
268
307
|
int i;
|
269
308
|
for (i = 0; i < 12; i++) {
|
270
|
-
char byte = (char)FIX2INT(
|
309
|
+
char byte = (char)FIX2INT(RARRAY_PTR(as_array)[i]);
|
271
310
|
buffer_write_bytes(buffer, &byte, 1);
|
272
311
|
}
|
273
312
|
break;
|
@@ -281,9 +320,9 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
281
320
|
int length_location = buffer_save_bytes(buffer, 4);
|
282
321
|
|
283
322
|
VALUE ns = rb_funcall(value, rb_intern("namespace"), 0);
|
284
|
-
write_element(rb_str_new2("$ref"), ns, (
|
323
|
+
write_element(rb_str_new2("$ref"), ns, pack_extra(buffer, Qfalse));
|
285
324
|
VALUE oid = rb_funcall(value, rb_intern("object_id"), 0);
|
286
|
-
write_element(rb_str_new2("$id"), oid, (
|
325
|
+
write_element(rb_str_new2("$id"), oid, pack_extra(buffer, Qfalse));
|
287
326
|
|
288
327
|
// write null byte and fill in length
|
289
328
|
buffer_write_bytes(buffer, &zero, 1);
|
@@ -303,7 +342,7 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
303
342
|
if (strcmp(cls, "Time") == 0) {
|
304
343
|
write_name_and_type(buffer, key, 0x09);
|
305
344
|
double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0));
|
306
|
-
long long time_since_epoch = (long long)(t * 1000);
|
345
|
+
long long time_since_epoch = (long long)round(t * 1000);
|
307
346
|
buffer_write_bytes(buffer, (const char*)&time_since_epoch, 8);
|
308
347
|
break;
|
309
348
|
}
|
@@ -312,21 +351,21 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
312
351
|
{
|
313
352
|
write_name_and_type(buffer, key, 0x0B);
|
314
353
|
|
315
|
-
int length =
|
316
|
-
char* pattern =
|
354
|
+
int length = RREGEXP_SRC_LEN(value);
|
355
|
+
char* pattern = (char*)RREGEXP_SRC_PTR(value);
|
317
356
|
buffer_write_bytes(buffer, pattern, length);
|
318
357
|
buffer_write_bytes(buffer, &zero, 1);
|
319
358
|
|
320
359
|
long flags = RREGEXP(value)->ptr->options;
|
321
|
-
if (flags &
|
360
|
+
if (flags & IGNORECASE) {
|
322
361
|
char ignorecase = 'i';
|
323
362
|
buffer_write_bytes(buffer, &ignorecase, 1);
|
324
363
|
}
|
325
|
-
if (flags &
|
364
|
+
if (flags & MULTILINE) {
|
326
365
|
char multiline = 'm';
|
327
366
|
buffer_write_bytes(buffer, &multiline, 1);
|
328
367
|
}
|
329
|
-
if (flags &
|
368
|
+
if (flags & EXTENDED) {
|
330
369
|
char extended = 'x';
|
331
370
|
buffer_write_bytes(buffer, &extended, 1);
|
332
371
|
}
|
@@ -335,8 +374,8 @@ static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow
|
|
335
374
|
if (TYPE(has_extra) == T_TRUE) {
|
336
375
|
VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0);
|
337
376
|
int old_position = buffer->position;
|
338
|
-
buffer_write_bytes(buffer,
|
339
|
-
qsort(buffer->buffer + old_position,
|
377
|
+
buffer_write_bytes(buffer, RSTRING_PTR(extra), RSTRING_LEN(extra));
|
378
|
+
qsort(buffer->buffer + old_position, RSTRING_LEN(extra), sizeof(char), cmp_char);
|
340
379
|
}
|
341
380
|
buffer_write_bytes(buffer, &zero, 1);
|
342
381
|
|
@@ -355,33 +394,33 @@ static int write_element(VALUE key, VALUE value, VALUE extra) {
|
|
355
394
|
return write_element_allow_id(key, value, extra, 0);
|
356
395
|
}
|
357
396
|
|
358
|
-
static void write_doc(bson_buffer* buffer, VALUE hash) {
|
397
|
+
static void write_doc(bson_buffer* buffer, VALUE hash, VALUE check_keys) {
|
359
398
|
int start_position = buffer->position;
|
360
399
|
int length_location = buffer_save_bytes(buffer, 4);
|
361
400
|
|
362
401
|
VALUE key = rb_str_new2("_id");
|
363
|
-
|
364
|
-
|
365
|
-
write_element_allow_id(key, id, (
|
402
|
+
if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
|
403
|
+
VALUE id = rb_hash_aref(hash, key);
|
404
|
+
write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
|
366
405
|
}
|
367
406
|
key = ID2SYM(rb_intern("_id"));
|
368
|
-
|
369
|
-
|
370
|
-
write_element_allow_id(key, id, (
|
407
|
+
if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue) {
|
408
|
+
VALUE id = rb_hash_aref(hash, key);
|
409
|
+
write_element_allow_id(key, id, pack_extra(buffer, check_keys), 1);
|
371
410
|
}
|
372
411
|
|
373
|
-
|
374
412
|
// we have to check for an OrderedHash and handle that specially
|
375
413
|
if (strcmp(rb_class2name(RBASIC(hash)->klass), "OrderedHash") == 0) {
|
376
414
|
VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
|
377
415
|
int i;
|
378
|
-
for(i = 0; i <
|
379
|
-
VALUE key =
|
416
|
+
for(i = 0; i < RARRAY_LEN(keys); i++) {
|
417
|
+
VALUE key = RARRAY_PTR(keys)[i];
|
380
418
|
VALUE value = rb_hash_aref(hash, key);
|
381
|
-
|
419
|
+
|
420
|
+
write_element(key, value, pack_extra(buffer, check_keys));
|
382
421
|
}
|
383
422
|
} else {
|
384
|
-
rb_hash_foreach(hash, write_element, (
|
423
|
+
rb_hash_foreach(hash, write_element, pack_extra(buffer, check_keys));
|
385
424
|
}
|
386
425
|
|
387
426
|
// write null byte and fill in length
|
@@ -390,11 +429,11 @@ static void write_doc(bson_buffer* buffer, VALUE hash) {
|
|
390
429
|
memcpy(buffer->buffer + length_location, &length, 4);
|
391
430
|
}
|
392
431
|
|
393
|
-
static VALUE method_serialize(VALUE self, VALUE doc) {
|
432
|
+
static VALUE method_serialize(VALUE self, VALUE doc, VALUE check_keys) {
|
394
433
|
bson_buffer* buffer = buffer_new();
|
395
434
|
assert(buffer);
|
396
435
|
|
397
|
-
write_doc(buffer, doc);
|
436
|
+
write_doc(buffer, doc, check_keys);
|
398
437
|
|
399
438
|
VALUE result = rb_str_new(buffer->buffer, buffer->position);
|
400
439
|
buffer_free(buffer);
|
@@ -525,13 +564,13 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|
525
564
|
for (i = 0; i < flags_length; i++) {
|
526
565
|
char flag = buffer[*position + i];
|
527
566
|
if (flag == 'i') {
|
528
|
-
flags |=
|
567
|
+
flags |= IGNORECASE;
|
529
568
|
}
|
530
569
|
else if (flag == 'm') {
|
531
|
-
flags |=
|
570
|
+
flags |= MULTILINE;
|
532
571
|
}
|
533
572
|
else if (flag == 'x') {
|
534
|
-
flags |=
|
573
|
+
flags |= EXTENDED;
|
535
574
|
}
|
536
575
|
else if (strlen(extra) < 9) {
|
537
576
|
strncat(extra, &flag, 1);
|
@@ -594,6 +633,16 @@ static VALUE get_value(const char* buffer, int* position, int type) {
|
|
594
633
|
*position += 4;
|
595
634
|
break;
|
596
635
|
}
|
636
|
+
case 17:
|
637
|
+
{
|
638
|
+
int i;
|
639
|
+
int j;
|
640
|
+
memcpy(&i, buffer + *position, 4);
|
641
|
+
memcpy(&j, buffer + *position + 4, 4);
|
642
|
+
value = rb_ary_new3(2, LL2NUM(i), LL2NUM(j));
|
643
|
+
*position += 8;
|
644
|
+
break;
|
645
|
+
}
|
597
646
|
default:
|
598
647
|
{
|
599
648
|
rb_raise(rb_eTypeError, "no c decoder for this type yet (%d)", type);
|
@@ -618,8 +667,8 @@ static VALUE elements_to_hash(const char* buffer, int max) {
|
|
618
667
|
}
|
619
668
|
|
620
669
|
static VALUE method_deserialize(VALUE self, VALUE bson) {
|
621
|
-
const char* buffer =
|
622
|
-
int remaining =
|
670
|
+
const char* buffer = RSTRING_PTR(bson);
|
671
|
+
int remaining = RSTRING_LEN(bson);
|
623
672
|
|
624
673
|
// NOTE we just swallow the size and end byte here
|
625
674
|
buffer += 4;
|
@@ -651,6 +700,6 @@ void Init_cbson() {
|
|
651
700
|
OrderedHash = rb_const_get(rb_cObject, rb_intern("OrderedHash"));
|
652
701
|
|
653
702
|
VALUE CBson = rb_define_module("CBson");
|
654
|
-
rb_define_module_function(CBson, "serialize", method_serialize,
|
703
|
+
rb_define_module_function(CBson, "serialize", method_serialize, 2);
|
655
704
|
rb_define_module_function(CBson, "deserialize", method_deserialize, 1);
|
656
705
|
}
|
data/ext/cbson/extconf.rb
CHANGED
data/mongo-extensions.gemspec
CHANGED
@@ -7,7 +7,7 @@ TEST_FILES = []
|
|
7
7
|
|
8
8
|
Gem::Specification.new do |s|
|
9
9
|
s.name = 'mongo_ext'
|
10
|
-
s.version = '0.
|
10
|
+
s.version = '0.3'
|
11
11
|
s.platform = Gem::Platform::RUBY
|
12
12
|
s.summary = 'C extensions for the MongoDB Ruby driver'
|
13
13
|
s.description = 'C extensions to accelerate the MondoDB Ruby driver. For more information about Mongo, see http://www.mongodb.org.'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongodb-mongo_ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Dirolf
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|