faststep 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Rakefile +15 -0
- data/bench/standard_benchmark +178 -0
- data/ext/faststep/bson.c +687 -0
- data/ext/faststep/bson.h +225 -0
- data/ext/faststep/bson_ruby_conversion.c +44 -0
- data/ext/faststep/bson_ruby_conversion.h +10 -0
- data/ext/faststep/collection.c +187 -0
- data/ext/faststep/collection.h +24 -0
- data/ext/faststep/connection.c +85 -0
- data/ext/faststep/connection.h +17 -0
- data/ext/faststep/cursor.c +61 -0
- data/ext/faststep/cursor.h +10 -0
- data/ext/faststep/db.c +56 -0
- data/ext/faststep/db.h +8 -0
- data/ext/faststep/exceptions.c +7 -0
- data/ext/faststep/exceptions.h +5 -0
- data/ext/faststep/extconf.rb +3 -0
- data/ext/faststep/faststep.c +30 -0
- data/ext/faststep/faststep.h +4 -0
- data/ext/faststep/faststep_defines.h +11 -0
- data/ext/faststep/gridfs.c +799 -0
- data/ext/faststep/gridfs.h +278 -0
- data/ext/faststep/md5.c +381 -0
- data/ext/faststep/md5.h +91 -0
- data/ext/faststep/mongo.c +801 -0
- data/ext/faststep/mongo.h +188 -0
- data/ext/faststep/mongo_except.h +143 -0
- data/ext/faststep/numbers.c +127 -0
- data/ext/faststep/platform_hacks.h +93 -0
- data/ext/faststep/support.c +21 -0
- data/ext/faststep/support.h +6 -0
- data/faststep.gemspec +26 -0
- data/lib/faststep/collection.rb +21 -0
- data/lib/faststep/connection.rb +13 -0
- data/lib/faststep/cursor.rb +7 -0
- data/lib/faststep/db.rb +25 -0
- data/lib/faststep/version.rb +3 -0
- data/lib/faststep.rb +10 -0
- data/spec/collection_spec.rb +116 -0
- data/spec/connection_spec.rb +34 -0
- data/spec/cursor_spec.rb +24 -0
- data/spec/db_spec.rb +28 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support_spec.rb +14 -0
- 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(>e_buf);
|
690
|
+
bson_append_int(>e_buf, "$gte", start);
|
691
|
+
bson_from_buffer(>e_bson, >e_buf);
|
692
|
+
bson_append_bson(&query_buf, "n", >e_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
|
+
}
|