faststep 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +15 -0
  4. data/bench/standard_benchmark +178 -0
  5. data/ext/faststep/bson.c +687 -0
  6. data/ext/faststep/bson.h +225 -0
  7. data/ext/faststep/bson_ruby_conversion.c +44 -0
  8. data/ext/faststep/bson_ruby_conversion.h +10 -0
  9. data/ext/faststep/collection.c +187 -0
  10. data/ext/faststep/collection.h +24 -0
  11. data/ext/faststep/connection.c +85 -0
  12. data/ext/faststep/connection.h +17 -0
  13. data/ext/faststep/cursor.c +61 -0
  14. data/ext/faststep/cursor.h +10 -0
  15. data/ext/faststep/db.c +56 -0
  16. data/ext/faststep/db.h +8 -0
  17. data/ext/faststep/exceptions.c +7 -0
  18. data/ext/faststep/exceptions.h +5 -0
  19. data/ext/faststep/extconf.rb +3 -0
  20. data/ext/faststep/faststep.c +30 -0
  21. data/ext/faststep/faststep.h +4 -0
  22. data/ext/faststep/faststep_defines.h +11 -0
  23. data/ext/faststep/gridfs.c +799 -0
  24. data/ext/faststep/gridfs.h +278 -0
  25. data/ext/faststep/md5.c +381 -0
  26. data/ext/faststep/md5.h +91 -0
  27. data/ext/faststep/mongo.c +801 -0
  28. data/ext/faststep/mongo.h +188 -0
  29. data/ext/faststep/mongo_except.h +143 -0
  30. data/ext/faststep/numbers.c +127 -0
  31. data/ext/faststep/platform_hacks.h +93 -0
  32. data/ext/faststep/support.c +21 -0
  33. data/ext/faststep/support.h +6 -0
  34. data/faststep.gemspec +26 -0
  35. data/lib/faststep/collection.rb +21 -0
  36. data/lib/faststep/connection.rb +13 -0
  37. data/lib/faststep/cursor.rb +7 -0
  38. data/lib/faststep/db.rb +25 -0
  39. data/lib/faststep/version.rb +3 -0
  40. data/lib/faststep.rb +10 -0
  41. data/spec/collection_spec.rb +116 -0
  42. data/spec/connection_spec.rb +34 -0
  43. data/spec/cursor_spec.rb +24 -0
  44. data/spec/db_spec.rb +28 -0
  45. data/spec/spec_helper.rb +13 -0
  46. data/spec/support_spec.rb +14 -0
  47. metadata +181 -0
@@ -0,0 +1,799 @@
1
+ /*--------------------------------------------------------------------*/
2
+ /* gridfs.c */
3
+ /* Author: Christopher Triolo */
4
+ /*--------------------------------------------------------------------*/
5
+
6
+ #include "gridfs.h"
7
+ #include "mongo.h"
8
+ #include "bson.h"
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+ #include <assert.h>
13
+ #define TRUE 1
14
+ #define FALSE 0
15
+
16
+
17
+ /*--------------------------------------------------------------------*/
18
+
19
+ static bson * chunk_new(bson_oid_t id, int chunkNumber,
20
+ const char * data, int len)
21
+
22
+ {
23
+ bson * b;
24
+ bson_buffer buf;
25
+
26
+ b = (bson *)bson_malloc(sizeof(bson));
27
+ if (b == NULL) return NULL;
28
+
29
+ bson_buffer_init(&buf);
30
+ bson_append_oid(&buf, "files_id", &id);
31
+ bson_append_int(&buf, "n", chunkNumber);
32
+ bson_append_binary(&buf, "data", 2, data, len);
33
+ bson_from_buffer(b, &buf);
34
+ return b;
35
+ }
36
+
37
+ /*--------------------------------------------------------------------*/
38
+
39
+ static void chunk_free(bson * oChunk)
40
+
41
+ {
42
+ bson_destroy(oChunk);
43
+ free(oChunk);
44
+ }
45
+
46
+ /*--------------------------------------------------------------------*/
47
+
48
+ int gridfs_init(mongo_connection * client, const char * dbname,
49
+ const char * prefix, gridfs* gfs)
50
+ {
51
+ int options;
52
+ bson_buffer bb;
53
+ bson b;
54
+ bson out;
55
+ bson_bool_t success;
56
+
57
+ gfs->client = client;
58
+
59
+ /* Allocate space to own the dbname */
60
+ gfs->dbname = (const char *)bson_malloc(strlen(dbname)+1);
61
+ if (gfs->dbname == NULL) {
62
+ return FALSE;
63
+ }
64
+ strcpy((char*)gfs->dbname, dbname);
65
+
66
+ /* Allocate space to own the prefix */
67
+ if (prefix == NULL) prefix = "fs";
68
+ gfs->prefix = (const char *)bson_malloc(strlen(prefix)+1);
69
+ if (gfs->prefix == NULL) {
70
+ free((char*)gfs->dbname);
71
+ return FALSE;
72
+ }
73
+ strcpy((char *)gfs->prefix, prefix);
74
+
75
+ /* Allocate space to own files_ns */
76
+ gfs->files_ns =
77
+ (const char *) bson_malloc (strlen(prefix)+strlen(dbname)+strlen(".files")+2);
78
+ if (gfs->files_ns == NULL) {
79
+ free((char*)gfs->dbname);
80
+ free((char*)gfs->prefix);
81
+ return FALSE;
82
+ }
83
+ strcpy((char*)gfs->files_ns, dbname);
84
+ strcat((char*)gfs->files_ns, ".");
85
+ strcat((char*)gfs->files_ns, prefix);
86
+ strcat((char*)gfs->files_ns, ".files");
87
+
88
+ /* Allocate space to own chunks_ns */
89
+ gfs->chunks_ns = (const char *) bson_malloc(strlen(prefix) + strlen(dbname)
90
+ + strlen(".chunks") + 2);
91
+ if (gfs->chunks_ns == NULL) {
92
+ free((char*)gfs->dbname);
93
+ free((char*)gfs->prefix);
94
+ free((char*)gfs->files_ns);
95
+ return FALSE;
96
+ }
97
+ strcpy((char*)gfs->chunks_ns, dbname);
98
+ strcat((char*)gfs->chunks_ns, ".");
99
+ strcat((char*)gfs->chunks_ns, prefix);
100
+ strcat((char*)gfs->chunks_ns, ".chunks");
101
+
102
+ bson_buffer_init(&bb);
103
+ bson_append_int(&bb, "filename", 1);
104
+ bson_from_buffer(&b, &bb);
105
+ options = 0;
106
+ success = mongo_create_index(gfs->client, gfs->files_ns, &b, options, &out);
107
+ bson_destroy(&b);
108
+ if (!success) {
109
+ free((char*)gfs->dbname);
110
+ free((char*)gfs->prefix);
111
+ free((char*)gfs->files_ns);
112
+ free((char*)gfs->chunks_ns);
113
+ return FALSE;
114
+ }
115
+
116
+ bson_buffer_init(&bb);
117
+ bson_append_int(&bb, "files_id", 1);
118
+ bson_append_int(&bb, "n", 1);
119
+ bson_from_buffer(&b, &bb);
120
+ options = MONGO_INDEX_UNIQUE;
121
+ success = mongo_create_index(gfs->client, gfs->chunks_ns, &b, options, &out);
122
+ bson_destroy(&b);
123
+ if (!success) {
124
+ free((char*)gfs->dbname);
125
+ free((char*)gfs->prefix);
126
+ free((char*)gfs->files_ns);
127
+ free((char*)gfs->chunks_ns);
128
+ return FALSE;
129
+ }
130
+
131
+ return TRUE;
132
+ }
133
+
134
+ /*--------------------------------------------------------------------*/
135
+
136
+ void gridfs_destroy(gridfs* gfs)
137
+
138
+ {
139
+ if (gfs == NULL) return;
140
+ if (gfs->dbname) free((char*)gfs->dbname);
141
+ if (gfs->prefix) free((char*)gfs->prefix);
142
+ if (gfs->files_ns) free((char*)gfs->files_ns);
143
+ if (gfs->chunks_ns) free((char*)gfs->chunks_ns);
144
+ }
145
+
146
+ /*--------------------------------------------------------------------*/
147
+
148
+ static bson gridfs_insert_file( gridfs* gfs, const char* name,
149
+ const bson_oid_t id, gridfs_offset length,
150
+ const char* contenttype)
151
+ {
152
+ bson command;
153
+ bson res;
154
+ bson ret;
155
+ bson_buffer buf;
156
+ bson_iterator it;
157
+
158
+ /* Check run md5 */
159
+ bson_buffer_init(&buf);
160
+ bson_append_oid(&buf, "filemd5", &id);
161
+ bson_append_string(&buf, "root", gfs->prefix);
162
+ bson_from_buffer(&command, &buf);
163
+ assert(mongo_run_command(gfs->client, gfs->dbname,
164
+ &command, &res));
165
+ bson_destroy(&command);
166
+
167
+ /* Create and insert BSON for file metadata */
168
+ bson_buffer_init(&buf);
169
+ bson_append_oid(&buf, "_id", &id);
170
+ if (name != NULL && *name != '\0') {
171
+ bson_append_string(&buf, "filename", name);
172
+ }
173
+ bson_append_long(&buf, "length", length);
174
+ bson_append_int(&buf, "chunkSize", DEFAULT_CHUNK_SIZE);
175
+ bson_append_date(&buf, "uploadDate", (bson_date_t)1000*time(NULL));
176
+ bson_find(&it, &res, "md5");
177
+ bson_append_string(&buf, "md5", bson_iterator_string(&it));
178
+ bson_destroy(&res);
179
+ if (contenttype != NULL && *contenttype != '\0') {
180
+ bson_append_string(&buf, "contentType", contenttype);
181
+ }
182
+ bson_from_buffer(&ret, &buf);
183
+ mongo_insert(gfs->client, gfs->files_ns, &ret);
184
+
185
+ return ret;
186
+ }
187
+
188
+ /*--------------------------------------------------------------------*/
189
+
190
+ bson gridfs_store_buffer( gridfs* gfs, const char* data,
191
+ gridfs_offset length, const char* remotename,
192
+ const char * contenttype)
193
+
194
+ {
195
+ char const * const end = data + length;
196
+ bson_oid_t id;
197
+ int chunkNumber = 0;
198
+ int chunkLen;
199
+ bson * oChunk;
200
+
201
+ /* Large files Assertion */
202
+ assert(length <= 0xffffffff);
203
+
204
+ /* Generate and append an oid*/
205
+ bson_oid_gen(&id);
206
+
207
+ /* Insert the file's data chunk by chunk */
208
+ while (data < end) {
209
+ chunkLen = DEFAULT_CHUNK_SIZE < (unsigned int)(end - data) ?
210
+ DEFAULT_CHUNK_SIZE : (unsigned int)(end - data);
211
+ oChunk = chunk_new( id, chunkNumber, data, chunkLen );
212
+ mongo_insert(gfs->client, gfs->chunks_ns, oChunk);
213
+ chunk_free(oChunk);
214
+ chunkNumber++;
215
+ data += chunkLen;
216
+ }
217
+
218
+ /* Inserts file's metadata */
219
+ return gridfs_insert_file(gfs, remotename, id, length, contenttype);
220
+ }
221
+
222
+ /*--------------------------------------------------------------------*/
223
+
224
+ void gridfile_writer_init( gridfile* gfile, gridfs* gfs,
225
+ const char* remote_name, const char* content_type )
226
+ {
227
+ gfile->gfs = gfs;
228
+
229
+ bson_oid_gen( &(gfile->id) );
230
+ gfile->chunk_num = 0;
231
+ gfile->length = 0;
232
+ gfile->pending_len = 0;
233
+ gfile->pending_data = NULL;
234
+
235
+ gfile->remote_name = (const char *)bson_malloc( strlen( remote_name ) + 1 );
236
+ strcpy( (char *)gfile->remote_name, remote_name );
237
+
238
+ gfile->content_type = (const char *)bson_malloc( strlen( content_type ) );
239
+ strcpy( (char *)gfile->content_type, content_type );
240
+ }
241
+
242
+ /*--------------------------------------------------------------------*/
243
+
244
+ void gridfile_write_buffer( gridfile* gfile, const char* data, gridfs_offset length )
245
+ {
246
+
247
+ int bytes_left = 0;
248
+ int data_partial_len = 0;
249
+ int chunks_to_write = 0;
250
+ char* buffer;
251
+ bson* oChunk;
252
+ gridfs_offset to_write = length + gfile->pending_len;
253
+
254
+ if ( to_write < DEFAULT_CHUNK_SIZE ) { /* Less than one chunk to write */
255
+ if( gfile->pending_data ) {
256
+ gfile->pending_data = (char *)bson_realloc((void *)gfile->pending_data, gfile->pending_len + to_write);
257
+ memcpy( gfile->pending_data + gfile->pending_len, data, length );
258
+ } else if (to_write > 0) {
259
+ gfile->pending_data = (char *)bson_malloc(to_write);
260
+ memcpy( gfile->pending_data, data, length );
261
+ }
262
+ gfile->pending_len += length;
263
+
264
+ } else { /* At least one chunk of data to write */
265
+
266
+ /* If there's a pending chunk to be written, we need to combine
267
+ * the buffer provided up to DEFAULT_CHUNK_SIZE.
268
+ */
269
+ if ( gfile->pending_len > 0 ) {
270
+ chunks_to_write = to_write / DEFAULT_CHUNK_SIZE;
271
+ bytes_left = to_write % DEFAULT_CHUNK_SIZE;
272
+
273
+ data_partial_len = DEFAULT_CHUNK_SIZE - gfile->pending_len;
274
+ buffer = (char *)bson_malloc( DEFAULT_CHUNK_SIZE );
275
+ memcpy(buffer, gfile->pending_data, gfile->pending_len);
276
+ memcpy(buffer + gfile->pending_len, data, data_partial_len);
277
+
278
+ oChunk = chunk_new(gfile->id, gfile->chunk_num, buffer, DEFAULT_CHUNK_SIZE);
279
+ mongo_insert(gfile->gfs->client, gfile->gfs->chunks_ns, oChunk);
280
+ chunk_free(oChunk);
281
+ gfile->chunk_num++;
282
+ gfile->length += DEFAULT_CHUNK_SIZE;
283
+ data += data_partial_len;
284
+
285
+ chunks_to_write--;
286
+
287
+ free(buffer);
288
+ }
289
+
290
+ while( chunks_to_write > 0 ) {
291
+ oChunk = chunk_new(gfile->id, gfile->chunk_num, data, DEFAULT_CHUNK_SIZE);
292
+ mongo_insert(gfile->gfs->client, gfile->gfs->chunks_ns, oChunk);
293
+ chunk_free(oChunk);
294
+ gfile->chunk_num++;
295
+ chunks_to_write--;
296
+ gfile->length += DEFAULT_CHUNK_SIZE;
297
+ data += DEFAULT_CHUNK_SIZE;
298
+ }
299
+
300
+ free(gfile->pending_data);
301
+
302
+ /* If there are any leftover bytes, store them as pending data. */
303
+ if( bytes_left == 0 )
304
+ gfile->pending_data = NULL;
305
+ else {
306
+ gfile->pending_data = (char *)bson_malloc( bytes_left );
307
+ memcpy( gfile->pending_data, data, bytes_left );
308
+ }
309
+
310
+ gfile->pending_len = bytes_left;
311
+ }
312
+ }
313
+
314
+ /*--------------------------------------------------------------------*/
315
+
316
+ bson gridfile_writer_done( gridfile* gfile )
317
+ {
318
+
319
+ /* write any remaining pending chunk data.
320
+ * pending data will always take up less than one chunk
321
+ */
322
+ bson* oChunk;
323
+ if( gfile->pending_data )
324
+ {
325
+ oChunk = chunk_new(gfile->id, gfile->chunk_num, gfile->pending_data, gfile->pending_len);
326
+ mongo_insert(gfile->gfs->client, gfile->gfs->chunks_ns, oChunk);
327
+ chunk_free(oChunk);
328
+ gfile->length += gfile->pending_len;
329
+ }
330
+
331
+ /* insert into files collection */
332
+ return gridfs_insert_file(gfile->gfs, gfile->remote_name, gfile->id,
333
+ gfile->length, gfile->content_type);
334
+ }
335
+
336
+ /*--------------------------------------------------------------------*/
337
+
338
+ bson gridfs_store_file(gridfs* gfs, const char* filename,
339
+ const char* remotename, const char* contenttype)
340
+ {
341
+ char buffer[DEFAULT_CHUNK_SIZE];
342
+ FILE * fd;
343
+ bson_oid_t id;
344
+ int chunkNumber = 0;
345
+ gridfs_offset length = 0;
346
+ gridfs_offset chunkLen = 0;
347
+ bson* oChunk;
348
+
349
+ /* Open the file and the correct stream */
350
+ if (strcmp(filename, "-") == 0) fd = stdin;
351
+ else fd = fopen(filename, "rb");
352
+ assert(fd != NULL); /* No such file */
353
+
354
+ /* Generate and append an oid*/
355
+ bson_oid_gen(&id);
356
+
357
+ /* Insert the file chunk by chunk */
358
+ chunkLen = fread(buffer, 1, DEFAULT_CHUNK_SIZE, fd);
359
+ do {
360
+ oChunk = chunk_new( id, chunkNumber, buffer, chunkLen );
361
+ mongo_insert(gfs->client, gfs->chunks_ns, oChunk);
362
+ chunk_free(oChunk);
363
+ length += chunkLen;
364
+ chunkNumber++;
365
+ chunkLen = fread(buffer, 1, DEFAULT_CHUNK_SIZE, fd);
366
+ } while (chunkLen != 0);
367
+
368
+ /* Close the file stream */
369
+ if (fd != stdin) fclose(fd);
370
+
371
+ /* Large files Assertion */
372
+ /* assert(length <= 0xffffffff); */
373
+
374
+ /* Optional Remote Name */
375
+ if (remotename == NULL || *remotename == '\0') {
376
+ remotename = filename; }
377
+
378
+ /* Inserts file's metadata */
379
+ return gridfs_insert_file(gfs, remotename, id, length, contenttype);
380
+ }
381
+
382
+ /*--------------------------------------------------------------------*/
383
+
384
+ void gridfs_remove_filename(gridfs* gfs, const char* filename )
385
+
386
+ {
387
+ bson query;
388
+ bson_buffer buf;
389
+ mongo_cursor* files;
390
+ bson file;
391
+ bson_iterator it;
392
+ bson_oid_t id;
393
+ bson b;
394
+
395
+ bson_buffer_init(&buf);
396
+ bson_append_string(&buf, "filename", filename);
397
+ bson_from_buffer(&query, &buf);
398
+ files = mongo_find(gfs->client, gfs->files_ns, &query, NULL, 0, 0, 0);
399
+ bson_destroy(&query);
400
+
401
+ /* Remove each file and it's chunks from files named filename */
402
+ while (mongo_cursor_next(files)) {
403
+ file = files->current;
404
+ bson_find(&it, &file, "_id");
405
+ id = *bson_iterator_oid(&it);
406
+
407
+ /* Remove the file with the specified id */
408
+ bson_buffer_init(&buf);
409
+ bson_append_oid(&buf, "_id", &id);
410
+ bson_from_buffer(&b, &buf);
411
+ mongo_remove( gfs->client, gfs->files_ns, &b);
412
+ bson_destroy(&b);
413
+
414
+ /* Remove all chunks from the file with the specified id */
415
+ bson_buffer_init(&buf);
416
+ bson_append_oid(&buf, "files_id", &id);
417
+ bson_from_buffer(&b, &buf);
418
+ mongo_remove( gfs->client, gfs->chunks_ns, &b);
419
+ bson_destroy(&b);
420
+ }
421
+
422
+ }
423
+
424
+ /*--------------------------------------------------------------------*/
425
+
426
+ int gridfs_find_query(gridfs* gfs, bson* query,
427
+ gridfile* gfile )
428
+
429
+ {
430
+ bson_buffer date_buffer;
431
+ bson uploadDate;
432
+ bson_buffer buf;
433
+ bson finalQuery;
434
+ bson out;
435
+ int i;
436
+
437
+ bson_buffer_init(&date_buffer);
438
+ bson_append_int(&date_buffer, "uploadDate", -1);
439
+ bson_from_buffer(&uploadDate, &date_buffer);
440
+ bson_buffer_init(&buf);
441
+ bson_append_bson(&buf, "query", query);
442
+ bson_append_bson(&buf, "orderby", &uploadDate);
443
+ bson_from_buffer(&finalQuery, &buf);
444
+
445
+
446
+ i = (mongo_find_one(gfs->client, gfs->files_ns,
447
+ &finalQuery, NULL, &out));
448
+ bson_destroy(&uploadDate);
449
+ bson_destroy(&finalQuery);
450
+ if (!i)
451
+ return FALSE;
452
+ else {
453
+ gridfile_init(gfs, &out, gfile);
454
+ bson_destroy(&out);
455
+ return TRUE;
456
+ }
457
+ }
458
+
459
+ /*--------------------------------------------------------------------*/
460
+
461
+ int gridfs_find_filename(gridfs* gfs, const char* filename,
462
+ gridfile* gfile)
463
+
464
+ {
465
+ bson query;
466
+ bson_buffer buf;
467
+ int i;
468
+
469
+ bson_buffer_init(&buf);
470
+ bson_append_string(&buf, "filename", filename);
471
+ bson_from_buffer(&query, &buf) ;
472
+ i = gridfs_find_query(gfs, &query, gfile);
473
+ bson_destroy(&query);
474
+ return i;
475
+ }
476
+
477
+ /*--------------------------------------------------------------------*/
478
+
479
+ int gridfile_init(gridfs* gfs, bson* meta, gridfile* gfile)
480
+
481
+ {
482
+ gfile->gfs = gfs;
483
+ gfile->pos = 0;
484
+ gfile->meta = (bson*)bson_malloc(sizeof(bson));
485
+ if (gfile->meta == NULL) return FALSE;
486
+ bson_copy(gfile->meta, meta);
487
+ return TRUE;
488
+ }
489
+
490
+ /*--------------------------------------------------------------------*/
491
+
492
+ void gridfile_destroy(gridfile* gfile)
493
+
494
+ {
495
+ bson_destroy(gfile->meta);
496
+ free(gfile->meta);
497
+ }
498
+
499
+ /*--------------------------------------------------------------------*/
500
+
501
+ bson_bool_t gridfile_exists(gridfile* gfile)
502
+
503
+ {
504
+ return (bson_bool_t)(gfile != NULL || gfile->meta == NULL);
505
+ }
506
+
507
+ /*--------------------------------------------------------------------*/
508
+
509
+ const char* gridfile_get_filename(gridfile* gfile)
510
+
511
+ {
512
+ bson_iterator it;
513
+
514
+ bson_find(&it, gfile->meta, "filename");
515
+ return bson_iterator_string(&it);
516
+ }
517
+
518
+ /*--------------------------------------------------------------------*/
519
+
520
+ int gridfile_get_chunksize(gridfile* gfile)
521
+
522
+ {
523
+ bson_iterator it;
524
+
525
+ bson_find(&it, gfile->meta, "chunkSize");
526
+ return bson_iterator_int(&it);
527
+ }
528
+
529
+ /*--------------------------------------------------------------------*/
530
+
531
+ gridfs_offset gridfile_get_contentlength(gridfile* gfile)
532
+
533
+ {
534
+ bson_iterator it;
535
+
536
+ bson_find(&it, gfile->meta, "length");
537
+
538
+ if( bson_iterator_type( &it ) == bson_int )
539
+ return (gridfs_offset)bson_iterator_int( &it );
540
+ else
541
+ return (gridfs_offset)bson_iterator_long( &it );
542
+ }
543
+
544
+ /*--------------------------------------------------------------------*/
545
+
546
+ const char *gridfile_get_contenttype(gridfile* gfile)
547
+
548
+ {
549
+ bson_iterator it;
550
+
551
+ if (bson_find(&it, gfile->meta, "contentType"))
552
+ return bson_iterator_string( &it );
553
+ else return NULL;
554
+ }
555
+
556
+ /*--------------------------------------------------------------------*/
557
+
558
+ bson_date_t gridfile_get_uploaddate(gridfile* gfile)
559
+
560
+ {
561
+ bson_iterator it;
562
+
563
+ bson_find(&it, gfile->meta, "uploadDate");
564
+ return bson_iterator_date( &it );
565
+ }
566
+
567
+ /*--------------------------------------------------------------------*/
568
+
569
+ const char* gridfile_get_md5(gridfile* gfile)
570
+
571
+ {
572
+ bson_iterator it;
573
+
574
+ bson_find(&it, gfile->meta, "md5");
575
+ return bson_iterator_string( &it );
576
+ }
577
+
578
+ /*--------------------------------------------------------------------*/
579
+
580
+ const char* gridfile_get_field(gridfile* gfile, const char* name)
581
+
582
+ {
583
+ bson_iterator it;
584
+
585
+ bson_find(&it, gfile->meta, name);
586
+ return bson_iterator_value( &it );
587
+ }
588
+
589
+ /*--------------------------------------------------------------------*/
590
+
591
+ bson_bool_t gridfile_get_boolean(gridfile* gfile, const char* name)
592
+ {
593
+ bson_iterator it;
594
+
595
+ bson_find(&it, gfile->meta, name);
596
+ return bson_iterator_bool( &it );
597
+ }
598
+
599
+ /*--------------------------------------------------------------------*/
600
+ bson gridfile_get_metadata(gridfile* gfile)
601
+
602
+ {
603
+ bson sub;
604
+ bson_iterator it;
605
+
606
+ if (bson_find(&it, gfile->meta, "metadata")) {
607
+ bson_iterator_subobject( &it, &sub );
608
+ return sub;
609
+ }
610
+ else {
611
+ bson_empty(&sub);
612
+ return sub;
613
+ }
614
+ }
615
+
616
+ /*--------------------------------------------------------------------*/
617
+
618
+ int gridfile_get_numchunks(gridfile* gfile)
619
+
620
+ {
621
+ bson_iterator it;
622
+ gridfs_offset length;
623
+ gridfs_offset chunkSize;
624
+ double numchunks;
625
+
626
+ bson_find(&it, gfile->meta, "length");
627
+
628
+ if( bson_iterator_type( &it ) == bson_int )
629
+ length = (gridfs_offset)bson_iterator_int( &it );
630
+ else
631
+ length = (gridfs_offset)bson_iterator_long( &it );
632
+
633
+ bson_find(&it, gfile->meta, "chunkSize");
634
+ chunkSize = bson_iterator_int(&it);
635
+ numchunks = ((double)length/(double)chunkSize);
636
+ return (numchunks - (int)numchunks > 0)
637
+ ? (int)(numchunks+1)
638
+ : (int)(numchunks);
639
+ }
640
+
641
+ /*--------------------------------------------------------------------*/
642
+
643
+ bson gridfile_get_chunk(gridfile* gfile, int n)
644
+
645
+ {
646
+ bson query;
647
+ bson out;
648
+ bson_buffer buf;
649
+ bson_iterator it;
650
+ bson_oid_t id;
651
+
652
+ bson_buffer_init(&buf);
653
+ bson_find(&it, gfile->meta, "_id");
654
+ id = *bson_iterator_oid(&it);
655
+ bson_append_oid(&buf, "files_id", &id);
656
+ bson_append_int(&buf, "n", n);
657
+ bson_from_buffer(&query, &buf);
658
+
659
+ assert(mongo_find_one(gfile->gfs->client,
660
+ gfile->gfs->chunks_ns,
661
+ &query, NULL, &out));
662
+ return out;
663
+ }
664
+
665
+ /*--------------------------------------------------------------------*/
666
+
667
+ mongo_cursor* gridfile_get_chunks(gridfile* gfile, int start, int size)
668
+
669
+ {
670
+ bson_iterator it;
671
+ bson_oid_t id;
672
+ bson_buffer gte_buf;
673
+ bson gte_bson;
674
+ bson_buffer query_buf;
675
+ bson query_bson;
676
+ bson_buffer orderby_buf;
677
+ bson orderby_bson;
678
+ bson_buffer command_buf;
679
+ bson command_bson;
680
+
681
+ bson_find(&it, gfile->meta, "_id");
682
+ id = *bson_iterator_oid(&it);
683
+
684
+ bson_buffer_init(&query_buf);
685
+ bson_append_oid(&query_buf, "files_id", &id);
686
+ if (size == 1) {
687
+ bson_append_int(&query_buf, "n", start);
688
+ } else {
689
+ bson_buffer_init(&gte_buf);
690
+ bson_append_int(&gte_buf, "$gte", start);
691
+ bson_from_buffer(&gte_bson, &gte_buf);
692
+ bson_append_bson(&query_buf, "n", &gte_bson);
693
+ }
694
+ bson_from_buffer(&query_bson, &query_buf);
695
+
696
+ bson_buffer_init(&orderby_buf);
697
+ bson_append_int(&orderby_buf, "n", 1);
698
+ bson_from_buffer(&orderby_bson, &orderby_buf);
699
+
700
+ bson_buffer_init(&command_buf);
701
+ bson_append_bson(&command_buf, "query", &query_bson);
702
+ bson_append_bson(&command_buf, "orderby", &orderby_bson);
703
+ bson_from_buffer(&command_bson, &command_buf);
704
+
705
+ return mongo_find(gfile->gfs->client, gfile->gfs->chunks_ns,
706
+ &command_bson, NULL, size, 0, 0);
707
+ }
708
+
709
+ /*--------------------------------------------------------------------*/
710
+
711
+ gridfs_offset gridfile_write_file(gridfile* gfile, FILE *stream)
712
+
713
+ {
714
+ int i;
715
+ size_t len;
716
+ bson chunk;
717
+ bson_iterator it;
718
+ const char* data;
719
+ const int num = gridfile_get_numchunks( gfile );
720
+
721
+ for ( i=0; i<num; i++ ){
722
+ printf("N: %d", i);
723
+ chunk = gridfile_get_chunk( gfile, i );
724
+ bson_find( &it, &chunk, "data" );
725
+ len = bson_iterator_bin_len( &it );
726
+ data = bson_iterator_bin_data( &it );
727
+ fwrite( data , sizeof(char), len, stream );
728
+ }
729
+
730
+ return gridfile_get_contentlength(gfile);
731
+ }
732
+
733
+ /*--------------------------------------------------------------------*/
734
+
735
+ gridfs_offset gridfile_read(gridfile* gfile, gridfs_offset size, char* buf)
736
+
737
+ {
738
+ mongo_cursor* chunks;
739
+ bson chunk;
740
+
741
+ int first_chunk;
742
+ int last_chunk;
743
+ int total_chunks;
744
+ gridfs_offset chunksize;
745
+ gridfs_offset contentlength;
746
+ gridfs_offset bytes_left;
747
+ int i;
748
+ bson_iterator it;
749
+ gridfs_offset chunk_len;
750
+ const char * chunk_data;
751
+
752
+ contentlength = gridfile_get_contentlength(gfile);
753
+ chunksize = gridfile_get_chunksize(gfile);
754
+ size = (contentlength - gfile->pos < size)
755
+ ? contentlength - gfile->pos
756
+ : size;
757
+ bytes_left = size;
758
+
759
+ first_chunk = (gfile->pos)/chunksize;
760
+ last_chunk = (gfile->pos+size-1)/chunksize;
761
+ total_chunks = last_chunk - first_chunk + 1;
762
+ chunks = gridfile_get_chunks(gfile, first_chunk, total_chunks);
763
+
764
+ for (i = 0; i < total_chunks; i++) {
765
+ mongo_cursor_next(chunks);
766
+ chunk = chunks->current;
767
+ bson_find(&it, &chunk, "data");
768
+ chunk_len = bson_iterator_bin_len( &it );
769
+ chunk_data = bson_iterator_bin_data( &it );
770
+ if (i == 0) {
771
+ chunk_data += (gfile->pos)%chunksize;
772
+ chunk_len -= (gfile->pos)%chunksize;
773
+ }
774
+ if (bytes_left > chunk_len) {
775
+ memcpy(buf, chunk_data, chunk_len);
776
+ bytes_left -= chunk_len;
777
+ buf += chunk_len;
778
+ } else {
779
+ memcpy(buf, chunk_data, bytes_left);
780
+ }
781
+ }
782
+
783
+ mongo_cursor_destroy(chunks);
784
+ gfile->pos = gfile->pos + size;
785
+
786
+ return size;
787
+ }
788
+
789
+ /*--------------------------------------------------------------------*/
790
+
791
+ gridfs_offset gridfile_seek(gridfile* gfile, gridfs_offset offset)
792
+
793
+ {
794
+ gridfs_offset length;
795
+
796
+ length = gridfile_get_contentlength(gfile);
797
+ gfile->pos = length < offset ? length : offset;
798
+ return gfile->pos;
799
+ }