From 6e246ee58c95de72fec2dc336e704eeaa9e273ad Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 25 Sep 2019 14:01:44 +0300 Subject: [PATCH] core(persistence): fix reserveNodeSpace() implementation - avoid data copying after buffer block shrink - resize current block in case of single FileNode --- modules/core/src/persistence.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 9237beaf02..1a0da06f65 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -1307,6 +1307,9 @@ public: // In the case (b) the existing tag and the name are copied automatically. uchar* reserveNodeSpace(FileNode& node, size_t sz) { + bool shrinkBlock = false; + size_t shrinkBlockIdx = 0, shrinkSize = 0; + uchar *ptr = 0, *blockEnd = 0; if( !fs_data_ptrs.empty() ) @@ -1315,19 +1318,32 @@ public: size_t ofs = node.ofs; CV_Assert( blockIdx == fs_data_ptrs.size()-1 ); CV_Assert( ofs <= fs_data_blksz[blockIdx] ); + CV_Assert( freeSpaceOfs <= fs_data_blksz[blockIdx] ); //CV_Assert( freeSpaceOfs <= ofs + sz ); ptr = fs_data_ptrs[blockIdx] + ofs; blockEnd = fs_data_ptrs[blockIdx] + fs_data_blksz[blockIdx]; + CV_Assert(ptr >= fs_data_ptrs[blockIdx] && ptr <= blockEnd); if( ptr + sz <= blockEnd ) { freeSpaceOfs = ofs + sz; return ptr; } - fs_data[blockIdx]->resize(ofs); - fs_data_blksz[blockIdx] = ofs; + if (ofs == 0) // FileNode is a first component of this block. Resize current block instead of allocation of new one. + { + fs_data[blockIdx]->resize(sz); + ptr = &fs_data[blockIdx]->at(0); + fs_data_ptrs[blockIdx] = ptr; + fs_data_blksz[blockIdx] = sz; + freeSpaceOfs = sz; + return ptr; + } + + shrinkBlock = true; + shrinkBlockIdx = blockIdx; + shrinkSize = ofs; } size_t blockSize = std::max((size_t)CV_FS_MAX_LEN*4 - 256, sz) + 256; @@ -1352,6 +1368,12 @@ public: } } + if (shrinkBlock) + { + fs_data[shrinkBlockIdx]->resize(shrinkSize); + fs_data_blksz[shrinkBlockIdx] = shrinkSize; + } + return new_ptr; }