2015-04-16 15:01:49 +02:00
# include "parallelaccessdatatreestore/DataTreeRef.h"
2015-02-17 00:40:34 +01:00
# include "BlobOnBlocks.h"
2014-12-09 17:45:33 +01:00
2015-02-26 20:19:12 +01:00
# include "datanodestore/DataLeafNode.h"
# include "utils/Math.h"
# include <cmath>
2015-07-22 13:42:44 +02:00
# include <messmer/cpp-utils/assert/assert.h>
2014-12-13 19:17:08 +01:00
2015-02-26 20:19:12 +01:00
using std : : function ;
2015-06-26 15:59:18 +02:00
using cpputils : : unique_ref ;
2015-02-26 20:19:12 +01:00
using blobstore : : onblocks : : datanodestore : : DataLeafNode ;
using blobstore : : onblocks : : datanodestore : : DataNodeLayout ;
2015-02-27 00:18:26 +01:00
using blockstore : : Key ;
2014-12-09 17:56:48 +01:00
2014-12-09 17:45:33 +01:00
namespace blobstore {
namespace onblocks {
2015-04-16 15:01:49 +02:00
using parallelaccessdatatreestore : : DataTreeRef ;
2014-12-09 17:45:33 +01:00
2015-06-26 15:59:18 +02:00
BlobOnBlocks : : BlobOnBlocks ( unique_ref < DataTreeRef > datatree )
2015-02-25 22:48:39 +01:00
: _datatree ( std : : move ( datatree ) ) {
2014-12-09 17:56:48 +01:00
}
2014-12-13 19:17:08 +01:00
BlobOnBlocks : : ~ BlobOnBlocks ( ) {
2014-12-09 17:56:48 +01:00
}
2015-02-26 17:33:47 +01:00
uint64_t BlobOnBlocks : : size ( ) const {
2015-02-25 23:09:48 +01:00
return _datatree - > numStoredBytes ( ) ;
2014-12-09 17:56:48 +01:00
}
2015-02-26 17:33:47 +01:00
void BlobOnBlocks : : resize ( uint64_t numBytes ) {
_datatree - > resizeNumBytes ( numBytes ) ;
}
2015-03-04 20:58:39 +01:00
void BlobOnBlocks : : traverseLeaves ( uint64_t beginByte , uint64_t sizeBytes , function < void ( uint64_t , DataLeafNode * leaf , uint32_t , uint32_t ) > func ) const {
2015-02-26 20:19:12 +01:00
uint64_t endByte = beginByte + sizeBytes ;
uint32_t firstLeaf = beginByte / _datatree - > maxBytesPerLeaf ( ) ;
uint32_t endLeaf = utils : : ceilDivision ( endByte , _datatree - > maxBytesPerLeaf ( ) ) ;
2015-04-10 21:52:30 +02:00
bool traversingOutOfRange = _datatree - > numStoredBytes ( ) < endByte ; //TODO numBytes() inefficient
_datatree - > traverseLeaves ( firstLeaf , endLeaf , [ & func , beginByte , endByte , endLeaf , traversingOutOfRange ] ( DataLeafNode * leaf , uint32_t leafIndex ) {
2015-02-26 20:19:12 +01:00
uint64_t indexOfFirstLeafByte = leafIndex * leaf - > maxStoreableBytes ( ) ;
uint32_t dataBegin = utils : : maxZeroSubtraction ( beginByte , indexOfFirstLeafByte ) ;
2015-03-06 16:08:30 +01:00
uint32_t dataEnd = std : : min ( ( uint64_t ) leaf - > maxStoreableBytes ( ) , endByte - indexOfFirstLeafByte ) ;
2015-04-10 21:52:30 +02:00
if ( leafIndex = = endLeaf - 1 & & traversingOutOfRange ) {
// If we are traversing an area that didn't exist before, then the last leaf was just created with a wrong size. We have to fix it.
leaf - > resize ( dataEnd ) ;
}
2015-03-06 16:08:30 +01:00
func ( indexOfFirstLeafByte , leaf , dataBegin , dataEnd - dataBegin ) ;
2015-02-26 20:19:12 +01:00
} ) ;
}
2015-03-11 01:04:48 +01:00
void BlobOnBlocks : : read ( void * target , uint64_t offset , uint64_t count ) const {
2015-07-22 13:42:44 +02:00
ASSERT ( offset < = _datatree - > numStoredBytes ( ) & & offset + count < = size ( ) , " BlobOnBlocks::read() read outside blob. Use BlobOnBlocks::tryRead() if this should be allowed. " ) ;
2015-03-11 01:04:48 +01:00
uint64_t read = tryRead ( target , offset , count ) ;
2015-07-22 13:42:44 +02:00
ASSERT ( read = = count , " BlobOnBlocks::read() couldn't read all requested bytes. Use BlobOnBlocks::tryRead() if this should be allowed. " ) ;
2015-03-11 01:04:48 +01:00
}
uint64_t BlobOnBlocks : : tryRead ( void * target , uint64_t offset , uint64_t count ) const {
//TODO Quite inefficient to call size() here, because that has to traverse the tree
2015-04-16 16:36:25 +02:00
uint64_t realCount = std : : max ( UINT64_C ( 0 ) , std : : min ( count , size ( ) - offset ) ) ;
2015-03-11 01:04:48 +01:00
traverseLeaves ( offset , realCount , [ target , offset ] ( uint64_t indexOfFirstLeafByte , const DataLeafNode * leaf , uint32_t leafDataOffset , uint32_t leafDataSize ) {
2015-03-06 20:40:23 +01:00
//TODO Simplify formula, make it easier to understand
leaf - > read ( ( uint8_t * ) target + indexOfFirstLeafByte - offset + leafDataOffset , leafDataOffset , leafDataSize ) ;
2015-02-26 20:19:12 +01:00
} ) ;
2015-03-11 01:04:48 +01:00
return realCount ;
2015-02-26 20:19:12 +01:00
}
void BlobOnBlocks : : write ( const void * source , uint64_t offset , uint64_t size ) {
2015-03-06 20:40:23 +01:00
traverseLeaves ( offset , size , [ source , offset ] ( uint64_t indexOfFirstLeafByte , DataLeafNode * leaf , uint32_t leafDataOffset , uint32_t leafDataSize ) {
//TODO Simplify formula, make it easier to understand
leaf - > write ( ( uint8_t * ) source + indexOfFirstLeafByte - offset + leafDataOffset , leafDataOffset , leafDataSize ) ;
2015-02-26 20:19:12 +01:00
} ) ;
}
2015-04-09 23:41:51 +02:00
void BlobOnBlocks : : flush ( ) {
_datatree - > flush ( ) ;
}
2015-03-04 03:29:22 +01:00
void BlobOnBlocks : : resizeIfSmallerThan ( uint64_t neededSize ) {
//TODO This is inefficient, because size() and resizeNumBytes() both traverse the tree. Better: _datatree->ensureMinSize(x)
if ( neededSize > size ( ) ) {
_datatree - > resizeNumBytes ( neededSize ) ;
}
}
2015-02-27 00:18:26 +01:00
Key BlobOnBlocks : : key ( ) const {
return _datatree - > key ( ) ;
}
2015-06-26 15:59:18 +02:00
unique_ref < DataTreeRef > BlobOnBlocks : : releaseTree ( ) {
2015-03-06 02:21:20 +01:00
return std : : move ( _datatree ) ;
}
2014-12-09 17:45:33 +01:00
}
}