diff --git a/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.cpp b/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.cpp index 588a94cf..e8dce0f9 100644 --- a/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.cpp +++ b/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.cpp @@ -28,29 +28,38 @@ using datatreestore::DataTreeStore; using parallelaccessdatatreestore::ParallelAccessDataTreeStore; BlobStoreOnBlocks::BlobStoreOnBlocks(unique_ref blockStore, uint32_t blocksizeBytes) -: _dataTreeStore(make_unique_ref(make_unique_ref(make_unique_ref(make_unique_ref(std::move(blockStore)), blocksizeBytes)))) { + : _dataTreeStore(make_unique_ref(make_unique_ref(make_unique_ref(make_unique_ref(std::move(blockStore)), blocksizeBytes)))) { } BlobStoreOnBlocks::~BlobStoreOnBlocks() { } unique_ref BlobStoreOnBlocks::create() { - return make_unique_ref(_dataTreeStore->createNewTree()); + return make_unique_ref(_dataTreeStore->createNewTree()); } optional> BlobStoreOnBlocks::load(const Key &key) { - auto tree = _dataTreeStore->load(key); - if (tree == none) { - return none; - } - return optional>(make_unique_ref(std::move(*tree))); + auto tree = _dataTreeStore->load(key); + if (tree == none) { + return none; + } + return optional>(make_unique_ref(std::move(*tree))); } void BlobStoreOnBlocks::remove(unique_ref blob) { - auto _blob = dynamic_pointer_move(blob); - ASSERT(_blob != none, "Passed Blob in BlobStoreOnBlocks::remove() is not a BlobOnBlocks."); - _dataTreeStore->remove((*_blob)->releaseTree()); + auto _blob = dynamic_pointer_move(blob); + ASSERT(_blob != none, "Passed Blob in BlobStoreOnBlocks::remove() is not a BlobOnBlocks."); + _dataTreeStore->remove((*_blob)->releaseTree()); } +uint64_t BlobStoreOnBlocks::numBlocks() const { + return _dataTreeStore->numNodes(); +} + +uint64_t BlobStoreOnBlocks::estimateSpaceForNumBlocksLeft() const { + return _dataTreeStore->estimateSpaceForNumNodesLeft(); +} + + } } diff --git a/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.h b/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.h index 0dcea458..27e0935b 100644 --- a/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.h +++ b/src/blobstore/implementations/onblocks/BlobStoreOnBlocks.h @@ -3,6 +3,7 @@ #define MESSMER_BLOBSTORE_IMPLEMENTATIONS_BLOCKED_BLOBSTOREONBLOCKS_H_ #include "../../interface/BlobStore.h" +#include "BlobOnBlocks.h" #include namespace blobstore { @@ -23,6 +24,10 @@ public: void remove(cpputils::unique_ref blob) override; + //TODO Test numBlocks/estimateSpaceForNumBlocksLeft + uint64_t numBlocks() const override; + uint64_t estimateSpaceForNumBlocksLeft() const override; + private: cpputils::unique_ref _dataTreeStore; diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp index 6849ead3..9812e2d5 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.cpp @@ -92,6 +92,10 @@ uint64_t DataNodeStore::numNodes() const { return _blockstore->numBlocks(); } +uint64_t DataNodeStore::estimateSpaceForNumNodesLeft() const { + return _blockstore->estimateNumFreeBytes() / _layout.blocksizeBytes(); +} + void DataNodeStore::removeSubtree(unique_ref node) { DataInnerNode *inner = dynamic_cast(node.get()); if (inner != nullptr) { diff --git a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h index dc2bac44..88860ba7 100644 --- a/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h +++ b/src/blobstore/implementations/onblocks/datanodestore/DataNodeStore.h @@ -41,7 +41,9 @@ public: void removeSubtree(cpputils::unique_ref node); + //TODO Test numBlocks/estimateSpaceForNumBlocksLeft uint64_t numNodes() const; + uint64_t estimateSpaceForNumNodesLeft() const; //TODO Test overwriteNodeWith(), createNodeAsCopyFrom(), removeSubtree() private: diff --git a/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.h b/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.h index 1697eab8..ebc5e06d 100644 --- a/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.h +++ b/src/blobstore/implementations/onblocks/datatreestore/DataTreeStore.h @@ -7,12 +7,10 @@ #include #include #include +#include "../datanodestore/DataNodeStore.h" namespace blobstore { namespace onblocks { -namespace datanodestore { -class DataNodeStore; -} namespace datatreestore { class DataTree; @@ -27,12 +25,24 @@ public: void remove(cpputils::unique_ref tree); + //TODO Test numBlocks/estimateSpaceForNumBlocksLeft + uint64_t numNodes() const; + uint64_t estimateSpaceForNumNodesLeft() const; + private: cpputils::unique_ref _nodeStore; DISALLOW_COPY_AND_ASSIGN(DataTreeStore); }; +inline uint64_t DataTreeStore::numNodes() const { + return _nodeStore->numNodes(); +} + +inline uint64_t DataTreeStore::estimateSpaceForNumNodesLeft() const { + return _nodeStore->estimateSpaceForNumNodesLeft(); +} + } } } diff --git a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.cpp b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.cpp index 3061e359..8ec82c09 100644 --- a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.cpp +++ b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.cpp @@ -17,6 +17,8 @@ using datatreestore::DataTreeStore; using datatreestore::DataTree; namespace parallelaccessdatatreestore { +//TODO Here and for other stores (DataTreeStore, ...): Make small functions inline + ParallelAccessDataTreeStore::ParallelAccessDataTreeStore(unique_ref dataTreeStore) : _dataTreeStore(std::move(dataTreeStore)), _parallelAccessStore(make_unique_ref(_dataTreeStore.get())) { } @@ -39,6 +41,8 @@ void ParallelAccessDataTreeStore::remove(unique_ref tree) { return _parallelAccessStore.remove(key, std::move(tree)); } + + } } } diff --git a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.h b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.h index c0499a43..2f65fb67 100644 --- a/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.h +++ b/src/blobstore/implementations/onblocks/parallelaccessdatatreestore/ParallelAccessDataTreeStore.h @@ -6,13 +6,10 @@ #include #include #include +#include "../datatreestore/DataTreeStore.h" namespace blobstore { namespace onblocks { -namespace datatreestore { -class DataTreeStore; -class DataTree; -} namespace parallelaccessdatatreestore { class DataTreeRef; @@ -29,6 +26,10 @@ public: void remove(cpputils::unique_ref tree); + //TODO Test numBlocks/estimateSpaceForNumBlocksLeft + uint64_t numNodes() const; + uint64_t estimateSpaceForNumNodesLeft() const; + private: cpputils::unique_ref _dataTreeStore; parallelaccessstore::ParallelAccessStore _parallelAccessStore; @@ -36,6 +37,14 @@ private: DISALLOW_COPY_AND_ASSIGN(ParallelAccessDataTreeStore); }; +inline uint64_t ParallelAccessDataTreeStore::numNodes() const { + return _dataTreeStore->numNodes(); +} + +inline uint64_t ParallelAccessDataTreeStore::estimateSpaceForNumNodesLeft() const { + return _dataTreeStore->estimateSpaceForNumNodesLeft(); +} + } } } diff --git a/src/blobstore/interface/BlobStore.h b/src/blobstore/interface/BlobStore.h index ad8b0822..5cfe1a29 100644 --- a/src/blobstore/interface/BlobStore.h +++ b/src/blobstore/interface/BlobStore.h @@ -18,6 +18,9 @@ public: virtual cpputils::unique_ref create() = 0; virtual boost::optional> load(const blockstore::Key &key) = 0; virtual void remove(cpputils::unique_ref blob) = 0; + + virtual uint64_t numBlocks() const = 0; + virtual uint64_t estimateSpaceForNumBlocksLeft() const = 0; }; } diff --git a/src/blockstore/implementations/caching/CachingBlockStore.cpp b/src/blockstore/implementations/caching/CachingBlockStore.cpp index b9afd151..8a678e0d 100644 --- a/src/blockstore/implementations/caching/CachingBlockStore.cpp +++ b/src/blockstore/implementations/caching/CachingBlockStore.cpp @@ -67,6 +67,10 @@ uint64_t CachingBlockStore::numBlocks() const { return _baseBlockStore->numBlocks() + _numNewBlocks; } +uint64_t CachingBlockStore::estimateNumFreeBytes() const { + return _baseBlockStore->estimateNumFreeBytes(); +} + void CachingBlockStore::release(unique_ref block) { Key key = block->key(); _cache.push(key, std::move(block)); diff --git a/src/blockstore/implementations/caching/CachingBlockStore.h b/src/blockstore/implementations/caching/CachingBlockStore.h index 7ec02af1..9062b1ec 100644 --- a/src/blockstore/implementations/caching/CachingBlockStore.h +++ b/src/blockstore/implementations/caching/CachingBlockStore.h @@ -18,6 +18,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; void release(cpputils::unique_ref block); diff --git a/src/blockstore/implementations/compressing/CompressingBlockStore.h b/src/blockstore/implementations/compressing/CompressingBlockStore.h index 06b22c66..6d653150 100644 --- a/src/blockstore/implementations/compressing/CompressingBlockStore.h +++ b/src/blockstore/implementations/compressing/CompressingBlockStore.h @@ -19,6 +19,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; private: cpputils::unique_ref _baseBlockStore; @@ -71,6 +72,11 @@ uint64_t CompressingBlockStore::numBlocks() const { return _baseBlockStore->numBlocks(); } +template +uint64_t CompressingBlockStore::estimateNumFreeBytes() const { + return _baseBlockStore->estimateNumFreeBytes(); +} + } } diff --git a/src/blockstore/implementations/encrypted/EncryptedBlockStore.h b/src/blockstore/implementations/encrypted/EncryptedBlockStore.h index acbcc96f..936d3bbc 100644 --- a/src/blockstore/implementations/encrypted/EncryptedBlockStore.h +++ b/src/blockstore/implementations/encrypted/EncryptedBlockStore.h @@ -22,6 +22,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; //This function should only be used by test cases void __setKey(const typename Cipher::EncryptionKey &encKey); @@ -79,6 +80,11 @@ uint64_t EncryptedBlockStore::numBlocks() const { return _baseBlockStore->numBlocks(); } +template +uint64_t EncryptedBlockStore::estimateNumFreeBytes() const { + return _baseBlockStore->estimateNumFreeBytes(); +} + template void EncryptedBlockStore::__setKey(const typename Cipher::EncryptionKey &encKey) { _encKey = encKey; diff --git a/src/blockstore/implementations/inmemory/InMemoryBlockStore.cpp b/src/blockstore/implementations/inmemory/InMemoryBlockStore.cpp index 17124fea..fd6ffba0 100644 --- a/src/blockstore/implementations/inmemory/InMemoryBlockStore.cpp +++ b/src/blockstore/implementations/inmemory/InMemoryBlockStore.cpp @@ -52,5 +52,12 @@ uint64_t InMemoryBlockStore::numBlocks() const { return _blocks.size(); } +uint64_t InMemoryBlockStore::estimateNumFreeBytes() const { + //For windows, see http://stackoverflow.com/a/2513561/829568 + long numRAMPages = sysconf(_SC_PHYS_PAGES); + long pageSize = sysconf(_SC_PAGE_SIZE); + return numRAMPages*pageSize; +} + } } diff --git a/src/blockstore/implementations/inmemory/InMemoryBlockStore.h b/src/blockstore/implementations/inmemory/InMemoryBlockStore.h index 6fbfe7ae..87e11e2d 100644 --- a/src/blockstore/implementations/inmemory/InMemoryBlockStore.h +++ b/src/blockstore/implementations/inmemory/InMemoryBlockStore.h @@ -20,6 +20,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; private: std::map _blocks; diff --git a/src/blockstore/implementations/ondisk/OnDiskBlockStore.cpp b/src/blockstore/implementations/ondisk/OnDiskBlockStore.cpp index 9ef83446..a7cfc3b8 100644 --- a/src/blockstore/implementations/ondisk/OnDiskBlockStore.cpp +++ b/src/blockstore/implementations/ondisk/OnDiskBlockStore.cpp @@ -1,5 +1,6 @@ #include "OnDiskBlock.h" #include "OnDiskBlockStore.h" +#include using std::string; using cpputils::Data; @@ -48,5 +49,11 @@ uint64_t OnDiskBlockStore::numBlocks() const { return std::distance(bf::directory_iterator(_rootdir), bf::directory_iterator()); } +uint64_t OnDiskBlockStore::estimateNumFreeBytes() const { + struct statvfs stat; + ::statvfs(_rootdir.c_str(), &stat); + return stat.f_bsize*stat.f_bavail; +} + } } diff --git a/src/blockstore/implementations/ondisk/OnDiskBlockStore.h b/src/blockstore/implementations/ondisk/OnDiskBlockStore.h index 59bf449d..8e94e09b 100644 --- a/src/blockstore/implementations/ondisk/OnDiskBlockStore.h +++ b/src/blockstore/implementations/ondisk/OnDiskBlockStore.h @@ -18,6 +18,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; private: const boost::filesystem::path _rootdir; diff --git a/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.cpp b/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.cpp index 308352c0..41bf93a7 100644 --- a/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.cpp +++ b/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.cpp @@ -56,5 +56,9 @@ uint64_t ParallelAccessBlockStore::numBlocks() const { return _baseBlockStore->numBlocks(); } +uint64_t ParallelAccessBlockStore::estimateNumFreeBytes() const { + return _baseBlockStore->estimateNumFreeBytes(); +} + } } diff --git a/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h b/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h index b87bd57a..f524e19d 100644 --- a/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h +++ b/src/blockstore/implementations/parallelaccess/ParallelAccessBlockStore.h @@ -20,6 +20,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; private: cpputils::unique_ref _baseBlockStore; diff --git a/src/blockstore/implementations/testfake/FakeBlockStore.cpp b/src/blockstore/implementations/testfake/FakeBlockStore.cpp index 2a0ddfc7..8113000b 100644 --- a/src/blockstore/implementations/testfake/FakeBlockStore.cpp +++ b/src/blockstore/implementations/testfake/FakeBlockStore.cpp @@ -76,5 +76,12 @@ uint64_t FakeBlockStore::numBlocks() const { return _blocks.size(); } +uint64_t FakeBlockStore::estimateNumFreeBytes() const { + //For windows, see http://stackoverflow.com/a/2513561/829568 + long numRAMPages = sysconf(_SC_PHYS_PAGES); + long pageSize = sysconf(_SC_PAGE_SIZE); + return numRAMPages*pageSize; +} + } } diff --git a/src/blockstore/implementations/testfake/FakeBlockStore.h b/src/blockstore/implementations/testfake/FakeBlockStore.h index 38d9da7e..0e6ca8b7 100644 --- a/src/blockstore/implementations/testfake/FakeBlockStore.h +++ b/src/blockstore/implementations/testfake/FakeBlockStore.h @@ -35,6 +35,7 @@ public: boost::optional> load(const Key &key) override; void remove(cpputils::unique_ref block) override; uint64_t numBlocks() const override; + uint64_t estimateNumFreeBytes() const override; void updateData(const Key &key, const cpputils::Data &data); diff --git a/src/blockstore/interface/BlockStore.h b/src/blockstore/interface/BlockStore.h index 4130d4d7..506e7b52 100644 --- a/src/blockstore/interface/BlockStore.h +++ b/src/blockstore/interface/BlockStore.h @@ -22,6 +22,8 @@ public: virtual boost::optional> load(const Key &key) = 0; virtual void remove(cpputils::unique_ref block) = 0; virtual uint64_t numBlocks() const = 0; + //TODO Test estimateNumFreeBytes in all block stores + virtual uint64_t estimateNumFreeBytes() const = 0; cpputils::unique_ref create(const cpputils::Data &data) { while(true) { diff --git a/src/cryfs/filesystem/CryDevice.cpp b/src/cryfs/filesystem/CryDevice.cpp index 7c434853..33edd67c 100644 --- a/src/cryfs/filesystem/CryDevice.cpp +++ b/src/cryfs/filesystem/CryDevice.cpp @@ -138,7 +138,16 @@ unique_ref CryDevice::LoadBlob(const bf::path &path) { void CryDevice::statfs(const bf::path &path, struct statvfs *fsstat) { callFsActionCallbacks(); - // TODO What should we report here? + uint64_t numUsedBlocks = _fsBlobStore->numBlocks(); + uint64_t numFreeBlocks = _fsBlobStore->estimateSpaceForNumBlocksLeft(); + fsstat->f_bsize = BLOCKSIZE_BYTES; + fsstat->f_blocks = numUsedBlocks + numFreeBlocks; + fsstat->f_bfree = numFreeBlocks; + fsstat->f_bavail = numFreeBlocks; + fsstat->f_files = numUsedBlocks + numFreeBlocks; + fsstat->f_ffree = numFreeBlocks; + fsstat->f_namemax = 255; // We theoretically support unlimited file name length, but this is default for many Linux file systems, so probably also makes sense for CryFS. + //f_frsize, f_favail, f_fsid and f_flag are ignored in fuse, see http://fuse.sourcearchive.com/documentation/2.7.0/structfuse__operations_4e765e29122e7b6b533dc99849a52655.html#4e765e29122e7b6b533dc99849a52655 } unique_ref CryDevice::CreateFileBlob() { diff --git a/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h b/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h index 16583e17..ba7f6344 100644 --- a/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h +++ b/src/cryfs/filesystem/cachingfsblobstore/CachingFsBlobStore.h @@ -24,6 +24,8 @@ namespace cryfs { cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); + uint64_t numBlocks() const; + uint64_t estimateSpaceForNumBlocksLeft() const; void releaseForCache(cpputils::unique_ref baseBlob); @@ -78,6 +80,14 @@ namespace cryfs { _cache.push(key, std::move(baseBlob)); } + inline uint64_t CachingFsBlobStore::numBlocks() const { + return _baseBlobStore->numBlocks(); + } + + inline uint64_t CachingFsBlobStore::estimateSpaceForNumBlocksLeft() const { + return _baseBlobStore->estimateSpaceForNumBlocksLeft(); + } + } } diff --git a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h index 37298803..9dd5d589 100644 --- a/src/cryfs/filesystem/fsblobstore/FsBlobStore.h +++ b/src/cryfs/filesystem/fsblobstore/FsBlobStore.h @@ -22,6 +22,8 @@ namespace cryfs { cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); + uint64_t numBlocks() const; + uint64_t estimateSpaceForNumBlocksLeft() const; private: @@ -51,6 +53,14 @@ namespace cryfs { return SymlinkBlob::InitializeSymlink(std::move(blob), target); } + inline uint64_t FsBlobStore::numBlocks() const { + return _baseBlobStore->numBlocks(); + } + + inline uint64_t FsBlobStore::estimateSpaceForNumBlocksLeft() const { + return _baseBlobStore->estimateSpaceForNumBlocksLeft(); + } + inline void FsBlobStore::remove(cpputils::unique_ref blob) { _baseBlobStore->remove(blob->releaseBaseBlob()); } diff --git a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h index c45316b8..384eb2d3 100644 --- a/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h +++ b/src/cryfs/filesystem/parallelaccessfsblobstore/ParallelAccessFsBlobStore.h @@ -26,6 +26,8 @@ namespace cryfs { cpputils::unique_ref createSymlinkBlob(const boost::filesystem::path &target); boost::optional> load(const blockstore::Key &key); void remove(cpputils::unique_ref blob); + uint64_t numBlocks() const; + uint64_t estimateSpaceForNumBlocksLeft() const; private: @@ -42,19 +44,26 @@ namespace cryfs { _parallelAccessStore(cpputils::make_unique_ref(_baseBlobStore.get())) { } - void ParallelAccessFsBlobStore::remove(cpputils::unique_ref blob) { + inline void ParallelAccessFsBlobStore::remove(cpputils::unique_ref blob) { blockstore::Key key = blob->key(); return _parallelAccessStore.remove(key, std::move(blob)); } - std::function ParallelAccessFsBlobStore::_getLstatSize() { + inline std::function ParallelAccessFsBlobStore::_getLstatSize() { return [this] (const blockstore::Key &key) { auto blob = load(key); ASSERT(blob != boost::none, "Blob not found"); return (*blob)->lstat_size(); }; } - + + inline uint64_t ParallelAccessFsBlobStore::numBlocks() const { + return _baseBlobStore->numBlocks(); + } + + inline uint64_t ParallelAccessFsBlobStore::estimateSpaceForNumBlocksLeft() const { + return _baseBlobStore->estimateSpaceForNumBlocksLeft(); + } } }