|
17 | 17 |
|
18 | 18 | #include "mongo/client/gridfs.h" |
19 | 19 |
|
| 20 | +#include <algorithm> |
20 | 21 | #include <boost/smart_ptr.hpp> |
21 | 22 | #include <fcntl.h> |
22 | 23 | #include <fstream> |
|
35 | 36 |
|
36 | 37 | namespace mongo { |
37 | 38 |
|
| 39 | + using std::min; |
38 | 40 | using std::auto_ptr; |
39 | 41 | using std::cout; |
40 | 42 | using std::ios; |
@@ -209,6 +211,10 @@ namespace mongo { |
209 | 211 | return _client.query( _filesNS.c_str() , o ); |
210 | 212 | } |
211 | 213 |
|
| 214 | + void GridFS::_insertChunk( const GridFSChunk& chunk ) { |
| 215 | + _client.insert( _chunksNS.c_str() , chunk._data ); |
| 216 | + } |
| 217 | + |
212 | 218 | BSONObj GridFile::getMetadata() const { |
213 | 219 | BSONElement meta_element = _obj["metadata"]; |
214 | 220 | if( meta_element.eoo() ) { |
@@ -259,5 +265,86 @@ namespace mongo { |
259 | 265 | void GridFile::_exists() const { |
260 | 266 | uassert( 10015 , "doesn't exists" , exists() ); |
261 | 267 | } |
262 | | - |
| 268 | + |
| 269 | + GridFileBuilder::GridFileBuilder( GridFS* const grid ) : |
| 270 | + _grid( grid ), |
| 271 | + _chunkSize( grid->getChunkSize() ), |
| 272 | + _currentChunk( 0 ), |
| 273 | + _pendingData( new char[_chunkSize] ), |
| 274 | + _pendingDataSize( 0 ), |
| 275 | + _fileLength( 0 ) { |
| 276 | + _fileId.init(); |
| 277 | + _fileIdObj = BSON( "_id" << _fileId ); |
| 278 | + } |
| 279 | + |
| 280 | + const char* GridFileBuilder::_appendChunk( const char* data, |
| 281 | + size_t length, |
| 282 | + bool forcePendingInsert ) { |
| 283 | + const char* const end = data + length; |
| 284 | + while (data < end) { |
| 285 | + size_t chunkLen = min( _chunkSize, static_cast<size_t>(end-data) ); |
| 286 | + // the last chunk needs to be stored as pendingData, break while if |
| 287 | + // necessary |
| 288 | + if ((chunkLen < _chunkSize) && (!forcePendingInsert)) |
| 289 | + break; |
| 290 | + GridFSChunk chunk( _fileIdObj, _currentChunk, data, chunkLen ); |
| 291 | + _grid->_insertChunk( chunk ); |
| 292 | + ++_currentChunk; |
| 293 | + data += chunkLen; |
| 294 | + _fileLength += chunkLen; |
| 295 | + } |
| 296 | + return data; |
| 297 | + } |
| 298 | + |
| 299 | + void GridFileBuilder::_appendPendingData() { |
| 300 | + if (_pendingDataSize > 0) { |
| 301 | + _appendChunk( _pendingData.get(), _pendingDataSize, true ); |
| 302 | + _pendingDataSize = 0; |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + void GridFileBuilder::appendChunk( const char* data, size_t length ) { |
| 307 | + if (length == 0) |
| 308 | + return; |
| 309 | + |
| 310 | + // check if there is pending data |
| 311 | + if (_pendingDataSize > 0) { |
| 312 | + size_t totalSize = _pendingDataSize + length; |
| 313 | + size_t size = min( _chunkSize, totalSize ) - _pendingDataSize; |
| 314 | + memcpy( _pendingData.get() + _pendingDataSize, data, size ); |
| 315 | + _pendingDataSize += size; |
| 316 | + invariant( _pendingDataSize <= _chunkSize ); |
| 317 | + if (_pendingDataSize == _chunkSize) { |
| 318 | + _appendPendingData(); |
| 319 | + _appendChunk( data + size, length - size, false ); |
| 320 | + } |
| 321 | + } |
| 322 | + else { |
| 323 | + const char* const end = data + length; |
| 324 | + // split data in _chunkSize blocks, and store as pending the last block if |
| 325 | + // necessary |
| 326 | + data = _appendChunk( data, length, false ); |
| 327 | + // process pending data if necessary |
| 328 | + if (data != end) { |
| 329 | + size_t size = static_cast<size_t>(end-data); |
| 330 | + memcpy( _pendingData.get() + _pendingDataSize, data, size ); |
| 331 | + _pendingDataSize += size; |
| 332 | + } |
| 333 | + } |
| 334 | + } |
| 335 | + |
| 336 | + BSONObj GridFileBuilder::buildFile( const string& remoteName, |
| 337 | + const string& contentType ) { |
| 338 | + _appendPendingData(); |
| 339 | + BSONObj ret = _grid->insertFile( remoteName, _fileId, _fileLength, |
| 340 | + contentType ); |
| 341 | + // resets the object to allow more data append for a GridFile |
| 342 | + _currentChunk = 0; |
| 343 | + _pendingDataSize = 0; |
| 344 | + _fileLength = 0; |
| 345 | + _fileId.init(); |
| 346 | + _fileIdObj = BSON( "_id" << _fileId ); |
| 347 | + return ret; |
| 348 | + } |
| 349 | + |
263 | 350 | } |
0 commit comments