diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 4d649aba30..310e1ba069 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -99,10 +99,7 @@ jobs: shell: powershell run: | cd $Env:THIRDPARTY_HOME - curl https://zlib.net/zlib13.zip -o zlib13.zip - Expand-Archive -Path zlib13.zip -DestinationPath zlib-tmp - mv .\zlib-tmp\zlib-1.3\ . - rmdir zlib-tmp + git clone https://github.com/madler/zlib.git -b v1.3 zlib-1.3 cd zlib-1.3\contrib\vstudio\vc14 devenv zlibvc.sln /upgrade cp ../../../zlib.h . diff --git a/.github/workflows/check_license_and_history.yml b/.github/workflows/check_license_and_history.yml index 6f67c82415..5fef42e087 100644 --- a/.github/workflows/check_license_and_history.yml +++ b/.github/workflows/check_license_and_history.yml @@ -3,8 +3,9 @@ name: Check License and History on: # this workflow is planned to be called by the ci_pipeline and it will compare the PR files with the main workflow_call: workflow_dispatch: - #pull_request_review: - # types: [submitted] + push: + pull_request_target: + jobs: changedfiles: diff --git a/.github/workflows/ci_pipeline.yml b/.github/workflows/ci_pipeline.yml index 886393e3f5..263c0df69b 100644 --- a/.github/workflows/ci_pipeline.yml +++ b/.github/workflows/ci_pipeline.yml @@ -201,10 +201,7 @@ jobs: shell: powershell run: | cd $Env:THIRDPARTY_HOME - curl https://zlib.net/zlib13.zip -o zlib13.zip - Expand-Archive -Path zlib13.zip -DestinationPath zlib-tmp - mv .\zlib-tmp\zlib-1.3\ . - rmdir zlib-tmp + git clone https://github.com/madler/zlib.git -b v1.3 zlib-1.3 cd zlib-1.3\contrib\vstudio\vc14 devenv zlibvc.sln /upgrade cp ../../../zlib.h . diff --git a/.github/workflows/qa-tests.yml b/.github/workflows/qa-tests.yml index 0756b5b49b..a1782f50fa 100644 --- a/.github/workflows/qa-tests.yml +++ b/.github/workflows/qa-tests.yml @@ -54,3 +54,19 @@ jobs: make clean && ${{ matrix.short_test }} ;; esac + + - name: Save the DB if the test failed + if: ${{ failure() }} + id: savedb + run: | + ls -l /tmp/rocksdb_crashtest_* + tar -zcvf /tmp/db4debug.tar.gz /tmp/rocksdb_crashtest_* + ls -l /tmp/db4debug.tar.gz + + - name: Upload the DB + uses: actions/upload-artifact@v3 + if: ${{ always() && steps.savedb.outcome != 'skipped' && steps.savedb.outcome != 'failure' }} + with: + name: testdb + retention-days: 3 + path: /tmp/db4debug.tar.gz diff --git a/CMakeLists.txt b/CMakeLists.txt index 60ee127a88..a57979265c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,17 @@ +# Copyright (C) 2023 Speedb Ltd. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Prerequisites for Windows: # This cmake build is for Windows 64-bit only. # @@ -573,6 +587,10 @@ if(HAVE_AUXV_GETAUXVAL) add_definitions(-DROCKSDB_AUXV_GETAUXVAL_PRESENT) endif() +if(MEMORY_REPORTING AND HAVE_MALLOC_USABLE_SIZE) + add_definitions(-DMEMORY_REPORTING) +endif() + set(FSYNC_MODE AUTO CACHE STRING "Enable RTTI in builds") set_property(CACHE FSYNC_MODE PROPERTY STRINGS AUTO FULL BARRIER OFF) if(NOT FSYNC_MODE STREQUAL "OFF") diff --git a/HISTORY.md b/HISTORY.md index 0dc5e0448b..c70734a61b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,19 @@ # Speedb Change Log ## Unreleased + +### New Features + +### Enhancements + +### Bug Fixes +* LOG Consistency:Display the pinning policy options same as block cache options / metadata cache options (#804). + +### Miscellaneous +* WriteController logging: Remove redundant reports when WC is not shared between dbs + + +## Incaberry 2.8.0 (31/1/2024) Based on RocksDB 8.6.7 ### New Features @@ -8,13 +21,19 @@ Based on RocksDB 8.6.7 * Rebase on RocksDB 8.6.7 ### Enhancements +* Added memory reporting to the logs to be able to monitor which component in the Arena is using the memory and CacheAllocation overall memory usage, print some statistics. This feature requires compiling with MEMORY_REPORTING flag (#481) * Added a kUseBaseAddress flag and GetBaseOffset flag to OptionTypeInfo. If this flag is set and a function is used for processing options, the function is passed the base address of the struct rather than the specific field (#397) * Export GetFlushReasonString/GetCompactionReasonString in listener.h (#785). * Enabled speedb features in C and Java (#722) * stress test: Add the ability to trace write operations. Controlled by flag trace_ops (on by default). Trace files will be written to the expected values dir. - +* LOG Enhancement: Have a separate LOG entry per CF Stats. This ensures that no CF stats data is lost in case the size of the combined CF stats text exceeds the LOG's threshold (#534). ### Bug Fixes +* Fix a bug in db_stress where non existence parameters have checked with enable_speedb_features. +* Added IsRefreshIterSupported() to memtable_rep, to publish if the memtable support Refresh() of the iterator. +Refresh() will return status NotSupported for memtables that do not support Refresh(). +IsAllowRefresh() has been added. +db_stress has been updated as well to take into account that some memtables do not support Refresh() * fix conflicts between db_bench flags and enable speedb features flag(#743). * Proactive Flushes: Fix a race in the ShouldInitiateAnotherFlushMemOnly that may cause the method to return an incorrect answer (#758). * Stall deadlock consists small cfs (#637). @@ -22,15 +41,18 @@ Based on RocksDB 8.6.7 * Compaction: Restore SetupForCompaction functionality. Specifically, hint POSIX_FADV_NORMAL for compaction input files.See https://github.com/speedb-io/speedb/issues/787 for full details. * stress test: Fix TestIterateAgainstExpected not supporting 0 iterations. TestIterateAgainstExpected was not designed to support value of 0 in FLAGS_num_iterations. RocksDB has a value of 10 by default and we've added the option to randomize the values from 0 to 100 in https://github.com/speedb-io/speedb/commit/434692a63318036a3995a53001337f18bf467903 -* LOG Consistency:Display the pinning policy options same as block cache options / metadata cache options (#804). +* Add more checks for using db_stress with --enable_speedb_features=true +* Proactive Flushes: Have the initiator return a correct answer when it was requested to initate a flush (#812). +* stress test: Adding a trace file by default in PR https://github.com/speedb-io/speedb/pull/797 has revealed some incompatibilities between the trace file and several configurations (more details in https://github.com/speedb-io/speedb/issues/813). Keep the trace file and remove the IsDone assertion. + ### Miscellaneous * Remove leftover references to ROCKSDB_LITE (#755). * Options: Set compaction_readahead_size default to 0. The current default of 2Mb is not optimal for most of our use cases. Having a value of 0 means that the FS will use its default size for prefetching (true only with https://github.com/speedb-io/speedb/pull/788). * Options: Set level_compaction_dynamic_level_bytes as false by default. This flag is not working properly with Speedb. see https://github.com/speedb-io/speedb/issues/786 for more details. -* stress test: Disable hash speedb memtable and enable_speedb_features from testing until issues are solved. +* zlib: Update links to zlib 1.3 in CI and Makefile since the link in zlib.net is dead. -## Hazlenut 2.7.0 (27/10/2023) +## Hazelnut 2.7.0 (27/10/2023) Based on RocksDB 8.1.1 ### New Features diff --git a/Makefile b/Makefile index 081c11a75d..58fc949248 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,17 @@ +# Copyright (C) 2023 Speedb Ltd. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Copyright (c) 2011 The LevelDB Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. See the AUTHORS file for names of contributors. @@ -2003,7 +2017,7 @@ SHA256_CMD = sha256sum ZLIB_VER ?= 1.3 ZLIB_SHA256 ?= ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e -ZLIB_DOWNLOAD_BASE ?= http://zlib.net +ZLIB_DOWNLOAD_BASE ?= https://github.com/madler/zlib/releases/download/v1.3 BZIP2_VER ?= 1.0.8 BZIP2_SHA256 ?= ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269 BZIP2_DOWNLOAD_BASE ?= http://sourceware.org/pub/bzip2 diff --git a/build_tools/build_detect_platform b/build_tools/build_detect_platform index 46d0637fcd..f2d3889edb 100755 --- a/build_tools/build_detect_platform +++ b/build_tools/build_detect_platform @@ -1,5 +1,19 @@ #!/usr/bin/env bash + +# Copyright (C) 2023 Speedb Ltd. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Detects OS we're compiling on and outputs a file specified by the first # argument, which in turn gets read while processing Makefile. # @@ -456,7 +470,11 @@ EOF EOF if [ "$?" = 0 ]; then COMMON_FLAGS="$COMMON_FLAGS -DROCKSDB_MALLOC_USABLE_SIZE" + if test $MEMORY_REPORTING; then + COMMON_FLAGS="$COMMON_FLAGS -DMEMORY_REPORTING" + fi fi + fi if ! test $ROCKSDB_DISABLE_MEMKIND; then diff --git a/db/arena_wrapped_db_iter.cc b/db/arena_wrapped_db_iter.cc index b101fbbc75..8a8f79c1c5 100644 --- a/db/arena_wrapped_db_iter.cc +++ b/db/arena_wrapped_db_iter.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -37,7 +55,8 @@ void ArenaWrappedDBIter::Init( const SequenceNumber& sequence, uint64_t max_sequential_skip_in_iteration, uint64_t version_number, ReadCallback* read_callback, DBImpl* db_impl, ColumnFamilyData* cfd, bool expose_blob_index, bool allow_refresh) { - auto mem = arena_.AllocateAligned(sizeof(DBIter)); + auto mem = arena_.AllocateAligned( + sizeof(DBIter), ArenaTracker::ArenaStats::ArenaWrappedDBIter); db_iter_ = new (mem) DBIter(env, read_options, ioptions, mutable_cf_options, ioptions.user_comparator, /* iter */ nullptr, version, @@ -154,7 +173,10 @@ ArenaWrappedDBIter* NewArenaWrappedDbIterator( ArenaWrappedDBIter* iter = new ArenaWrappedDBIter(); iter->Init(env, read_options, ioptions, mutable_cf_options, version, sequence, max_sequential_skip_in_iterations, version_number, read_callback, - db_impl, cfd, expose_blob_index, allow_refresh); + db_impl, cfd, expose_blob_index, + !ioptions.memtable_factory->IsRefreshIterSupported() + ? false + : allow_refresh); if (db_impl != nullptr && cfd != nullptr && allow_refresh) { iter->StoreRefreshInfo(db_impl, cfd, read_callback, expose_blob_index); } diff --git a/db/arena_wrapped_db_iter.h b/db/arena_wrapped_db_iter.h index f15be306d2..f0dd706157 100644 --- a/db/arena_wrapped_db_iter.h +++ b/db/arena_wrapped_db_iter.h @@ -1,3 +1,17 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -76,6 +90,7 @@ class ArenaWrappedDBIter : public Iterator { Status status() const override { return db_iter_->status(); } Slice timestamp() const override { return db_iter_->timestamp(); } bool IsBlob() const { return db_iter_->IsBlob(); } + bool IsAllowRefresh() override { return allow_refresh_; } Status GetProperty(std::string prop_name, std::string* prop) override; diff --git a/db/column_family.cc b/db/column_family.cc index 7be55f5569..1d8e7499e7 100644 --- a/db/column_family.cc +++ b/db/column_family.cc @@ -1123,8 +1123,8 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions( ROCKS_LOG_WARN( ioptions_.logger, "[%s] Stalling writes because we have %d immutable memtables " - "(waiting for flush), max_write_buffer_number is set to %d " - "rate %" PRIu64, + "(waiting for flush), max_write_buffer_number is set to %d. " + "delayed write rate: %" PRIu64, name_.c_str(), imm()->NumNotFlushed(), mutable_cf_options.max_write_buffer_number, write_controller->delayed_write_rate()); @@ -1146,8 +1146,8 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions( 1); } ROCKS_LOG_WARN(ioptions_.logger, - "[%s] Stalling writes because we have %d level-0 files " - "rate %" PRIu64, + "[%s] Stalling writes because we have %d level-0 files. " + "delayed write rate: %" PRIu64, name_.c_str(), vstorage->l0_delay_trigger_count(), write_controller->delayed_write_rate()); } else if (write_stall_condition == WriteStallCondition::kDelayed && @@ -1175,7 +1175,7 @@ WriteStallCondition ColumnFamilyData::RecalculateWriteStallConditions( ROCKS_LOG_WARN( ioptions_.logger, "[%s] Stalling writes because of estimated pending compaction " - "bytes %" PRIu64 " rate %" PRIu64, + "bytes %" PRIu64 ". delayed write rate: %" PRIu64, name_.c_str(), vstorage->estimated_compaction_needed_bytes(), write_controller->delayed_write_rate()); } else { diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc index 3dac6ae881..c5a118ba92 100644 --- a/db/db_impl/db_impl.cc +++ b/db/db_impl/db_impl.cc @@ -1103,11 +1103,13 @@ Status DBImpl::GetStatsHistory( void DBImpl::DumpStats() { TEST_SYNC_POINT("DBImpl::DumpStats:1"); - std::string stats; if (shutdown_initiated_) { return; } + std::string db_stats; + std::vector cfs_stats; + // Also probe block cache(s) for problems, dump to info log UnorderedSet probed_caches; TEST_SYNC_POINT("DBImpl::DumpStats:StartRunning"); @@ -1141,7 +1143,7 @@ void DBImpl::DumpStats() { assert(property_info != nullptr); assert(!property_info->need_out_of_mutex); default_cf_internal_stats_->GetStringProperty(*property_info, *property, - &stats); + &db_stats); property = &InternalStats::kPeriodicCFStats; property_info = GetPropertyInfo(*property); @@ -1149,23 +1151,76 @@ void DBImpl::DumpStats() { assert(!property_info->need_out_of_mutex); for (auto cfd : *versions_->GetColumnFamilySet()) { if (cfd->initialized()) { + std::string cf_stats_str{std::string("CF Stats [") + cfd->GetName() + + "]"}; + auto cf_stats_hdr_len = cf_stats_str.size(); cfd->internal_stats()->GetStringProperty(*property_info, *property, - &stats); + &cf_stats_str); + + // Avoid displaying any information for CF-s with no stats information + if (cf_stats_str.size() > cf_stats_hdr_len) { + cfs_stats.push_back(cf_stats_str); + } } } } TEST_SYNC_POINT("DBImpl::DumpStats:2"); ROCKS_LOG_INFO(immutable_db_options_.info_log, "------- DUMPING STATS -------"); - ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", stats.c_str()); + ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", db_stats.c_str()); + for (const auto& cf_stats_str : cfs_stats) { + ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", cf_stats_str.c_str()); + } + if (immutable_db_options_.dump_malloc_stats) { - stats.clear(); - DumpMallocStats(&stats); - if (!stats.empty()) { + std::string malloc_stats; + DumpMallocStats(&malloc_stats); + if (!malloc_stats.empty()) { ROCKS_LOG_INFO(immutable_db_options_.info_log, "------- Malloc STATS -------"); - ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", stats.c_str()); + ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", + malloc_stats.c_str()); + } +#ifdef MEMORY_REPORTING + std::ostringstream oss; + oss << std::endl << "** Memory Reporting **" << std::endl; + oss << "Arena Stats:" << std::endl + << "Total: " << NumberToHumanString(Arena::arena_tracker_.total.load()) + << std::endl; + for (const auto& it : Arena::arena_tracker_.arena_stats) { + oss << it.first << ": " << NumberToHumanString(it.second.load()) + << std::endl; + } + oss << "CF Stats: " << std::endl; + uint64_t cfs_total_memory = 0; + std::ostringstream cf_oss; + for (auto cfd : *versions_->GetColumnFamilySet()) { + if (cfd->initialized()) { + std::string cf_name = cfd->GetName(); + uint64_t allocated_cf = cfd->mem()->ApproximateMemoryUsageFast() + + cfd->imm()->ApproximateMemoryUsage(); + cfs_total_memory += allocated_cf; + cf_oss << "[" << cf_name.c_str() + << "]: " << NumberToHumanString(allocated_cf) << std::endl; + } } + oss << "Total: " << NumberToHumanString(cfs_total_memory) << std::endl + << cf_oss.str(); + size_t out; + this->GetIntProperty("rocksdb.block-cache-usage", &out); + oss << "rocksdb.block-cache-usage: " << NumberToHumanString(out) + << std::endl; + this->GetIntProperty("rocksdb.estimate-table-readers-mem", &out); + oss << "rocksdb.estimate-table-readers-mem: " << NumberToHumanString(out) + << std::endl; + this->GetIntProperty("rocksdb.block-cache-pinned-usage", &out); + oss << "rocksdb.block-cache-pinned-usage: " << NumberToHumanString(out) + << std::endl; + oss << "Total CacheAllocationUsage: " + << NumberToHumanString(ROCKSDB_NAMESPACE::blockfetchermem::mem.load()) + << std::endl; + ROCKS_LOG_INFO(immutable_db_options_.info_log, "%s", oss.str().c_str()); +#endif } PrintStatistics(); diff --git a/db/db_impl/db_impl.h b/db/db_impl/db_impl.h index b041844c60..36be4d2906 100644 --- a/db/db_impl/db_impl.h +++ b/db/db_impl/db_impl.h @@ -462,9 +462,9 @@ class DBImpl : public DB { // flush initiated by the write buffer manager to free some space bool InitiateMemoryManagerFlushRequest(size_t min_size_to_flush); - bool InitiateMemoryManagerFlushRequestAtomicFlush( + size_t InitiateMemoryManagerFlushRequestAtomicFlush( size_t min_size_to_flush, const FlushOptions& flush_options); - bool InitiateMemoryManagerFlushRequestNonAtomicFlush( + size_t InitiateMemoryManagerFlushRequestNonAtomicFlush( size_t min_size_to_flush, const FlushOptions& flush_options); virtual SequenceNumber GetLatestSequenceNumber() const override; @@ -1995,7 +1995,8 @@ class DBImpl : public DB { // Force current memtable contents to be flushed. Status FlushMemTable(ColumnFamilyData* cfd, const FlushOptions& options, FlushReason flush_reason, - bool entered_write_thread = false); + bool entered_write_thread = false, + size_t* num_flushes_initiated = nullptr); // Atomic-flush memtables from quanlified CFs among `provided_candidate_cfds` // (if non-empty) or amomg all column families and atomically record the @@ -2003,7 +2004,8 @@ class DBImpl : public DB { Status AtomicFlushMemTables( const FlushOptions& options, FlushReason flush_reason, const autovector& provided_candidate_cfds = {}, - bool entered_write_thread = false); + bool entered_write_thread = false, + size_t* num_flushes_initiated = nullptr); // Wait until flushing this column family won't stall writes Status WaitUntilFlushWouldNotStallWrites(ColumnFamilyData* cfd, @@ -2156,7 +2158,7 @@ class DBImpl : public DB { void GenerateFlushRequest(const autovector& cfds, FlushReason flush_reason, FlushRequest* req); - void SchedulePendingFlush(const FlushRequest& req); + bool SchedulePendingFlush(const FlushRequest& req); void SchedulePendingCompaction(ColumnFamilyData* cfd); void SchedulePendingPurge(std::string fname, std::string dir_to_sync, diff --git a/db/db_impl/db_impl_compaction_flush.cc b/db/db_impl/db_impl_compaction_flush.cc index 8baf079565..514b4ab5ab 100644 --- a/db/db_impl/db_impl_compaction_flush.cc +++ b/db/db_impl/db_impl_compaction_flush.cc @@ -2333,7 +2333,12 @@ void DBImpl::GenerateFlushRequest(const autovector& cfds, Status DBImpl::FlushMemTable(ColumnFamilyData* cfd, const FlushOptions& flush_options, FlushReason flush_reason, - bool entered_write_thread) { + bool entered_write_thread, + size_t* num_flushes_initiated) { + if (num_flushes_initiated != nullptr) { + *num_flushes_initiated = 0U; + } + // This method should not be called if atomic_flush is true. assert(!immutable_db_options_.atomic_flush); if (!flush_options.wait && write_controller_->IsStopped()) { @@ -2447,7 +2452,10 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd, } } for (const auto& req : flush_reqs) { - SchedulePendingFlush(req); + bool pushed_req = SchedulePendingFlush(req); + if (pushed_req && (num_flushes_initiated != nullptr)) { + ++(*num_flushes_initiated); + } } MaybeScheduleFlushOrCompaction(); } @@ -2486,8 +2494,13 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd, Status DBImpl::AtomicFlushMemTables( const FlushOptions& flush_options, FlushReason flush_reason, const autovector& provided_candidate_cfds, - bool entered_write_thread) { + bool entered_write_thread, size_t* num_flushes_initiated) { assert(immutable_db_options_.atomic_flush); + + if (num_flushes_initiated != nullptr) { + *num_flushes_initiated = 0U; + } + if (!flush_options.wait && write_controller_->IsStopped()) { std::ostringstream oss; oss << "Writes have been stopped, thus unable to perform manual flush. " @@ -2598,7 +2611,10 @@ Status DBImpl::AtomicFlushMemTables( } } GenerateFlushRequest(cfds, flush_reason, &flush_req); - SchedulePendingFlush(flush_req); + bool pushed_req = SchedulePendingFlush(flush_req); + if (pushed_req && (num_flushes_initiated != nullptr)) { + ++(*num_flushes_initiated); + } MaybeScheduleFlushOrCompaction(); } @@ -3014,14 +3030,17 @@ ColumnFamilyData* DBImpl::PickCompactionFromQueue( return cfd; } -void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req) { +bool DBImpl::SchedulePendingFlush(const FlushRequest& flush_req) { mutex_.AssertHeld(); if (reject_new_background_jobs_) { - return; + return false; } if (flush_req.cfd_to_max_mem_id_to_persist.empty()) { - return; + return false; } + + bool pushed_req = false; + if (!immutable_db_options_.atomic_flush) { // For the non-atomic flush case, we never schedule multiple column // families in the same flush request. @@ -3035,6 +3054,7 @@ void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req) { cfd->set_queued_for_flush(true); ++unscheduled_flushes_; flush_queue_.push_back(flush_req); + pushed_req = true; } } else { for (auto& iter : flush_req.cfd_to_max_mem_id_to_persist) { @@ -3043,7 +3063,10 @@ void DBImpl::SchedulePendingFlush(const FlushRequest& flush_req) { } ++unscheduled_flushes_; flush_queue_.push_back(flush_req); + pushed_req = true; } + + return pushed_req; } void DBImpl::SchedulePendingCompaction(ColumnFamilyData* cfd) { @@ -3273,11 +3296,6 @@ Status DBImpl::BackgroundFlush(bool* made_progress, JobContext* job_context, bg_job_limits.max_compactions, bg_flush_scheduled_, bg_compaction_scheduled_); } - *reason = bg_flush_args[0].flush_reason_; - if (write_buffer_manager_) { - write_buffer_manager_->FlushStarted( - *reason == FlushReason::kWriteBufferManagerInitiated); - } status = FlushMemTablesToOutputFiles(bg_flush_args, made_progress, job_context, log_buffer, thread_pri); @@ -3325,6 +3343,12 @@ void DBImpl::BackgroundCallFlush(Env::Priority thread_pri) { Status s = BackgroundFlush(&made_progress, &job_context, &log_buffer, &reason, &flush_rescheduled_to_retain_udt, thread_pri); + + if (write_buffer_manager_) { + write_buffer_manager_->FlushStarted( + reason == FlushReason::kWriteBufferManagerInitiated); + } + if (s.IsTryAgain() && flush_rescheduled_to_retain_udt) { bg_cv_.SignalAll(); // In case a waiter can proceed despite the error mutex_.Unlock(); @@ -4351,16 +4375,20 @@ bool DBImpl::InitiateMemoryManagerFlushRequest(size_t min_size_to_flush) { flush_options.allow_write_stall = true; flush_options.wait = false; + size_t num_flushes_initiated = 0U; if (immutable_db_options_.atomic_flush) { - return InitiateMemoryManagerFlushRequestAtomicFlush(min_size_to_flush, - flush_options); + num_flushes_initiated = InitiateMemoryManagerFlushRequestAtomicFlush( + min_size_to_flush, flush_options); } else { - return InitiateMemoryManagerFlushRequestNonAtomicFlush(min_size_to_flush, - flush_options); + num_flushes_initiated = InitiateMemoryManagerFlushRequestNonAtomicFlush( + min_size_to_flush, flush_options); } + + // TODO - Have Proactive Flushes handle num_flushes_initiated > 1 + return (num_flushes_initiated > 0U); } -bool DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush( +size_t DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush( size_t min_size_to_flush, const FlushOptions& flush_options) { assert(immutable_db_options_.atomic_flush); @@ -4370,7 +4398,7 @@ bool DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush( SelectColumnFamiliesForAtomicFlush(&cfds); if (cfds.empty()) { - return false; + return 0U; } // min_size_to_flush may be 0. @@ -4391,7 +4419,7 @@ bool DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush( } } if (total_size_to_flush < min_size_to_flush) { - return false; + return 0U; } } } @@ -4404,17 +4432,21 @@ bool DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush( TEST_SYNC_POINT( "DBImpl::InitiateMemoryManagerFlushRequestAtomicFlush::BeforeFlush"); + size_t num_flushes_initiated = 0U; auto s = AtomicFlushMemTables( - flush_options, FlushReason::kWriteBufferManagerInitiated, cfds); + flush_options, FlushReason::kWriteBufferManagerInitiated, cfds, + false /* entered_write_thread */, &num_flushes_initiated); ROCKS_LOG_INFO( immutable_db_options_.info_log, "write buffer manager initiated Atomic flush finished, status: %s", s.ToString().c_str()); - return s.ok(); + + assert(s.ok() || (num_flushes_initiated == 0)); + return num_flushes_initiated; } -bool DBImpl::InitiateMemoryManagerFlushRequestNonAtomicFlush( +size_t DBImpl::InitiateMemoryManagerFlushRequestNonAtomicFlush( size_t min_size_to_flush, const FlushOptions& flush_options) { assert(immutable_db_options_.atomic_flush == false); @@ -4456,7 +4488,7 @@ bool DBImpl::InitiateMemoryManagerFlushRequestNonAtomicFlush( } if (cfd_to_flush == nullptr) { - return false; + return 0U; } orig_cfd_to_flush = cfd_to_flush; @@ -4503,15 +4535,19 @@ bool DBImpl::InitiateMemoryManagerFlushRequestNonAtomicFlush( TEST_SYNC_POINT( "DBImpl::InitiateMemoryManagerFlushRequestNonAtomicFlush::BeforeFlush"); - auto s = FlushMemTable(cfd_to_flush, flush_options, - FlushReason::kWriteBufferManagerInitiated); + size_t num_flushes_initiated = 0U; + + auto s = FlushMemTable( + cfd_to_flush, flush_options, FlushReason::kWriteBufferManagerInitiated, + false /* entered_write_thread */, &num_flushes_initiated); ROCKS_LOG_INFO( immutable_db_options_.info_log, "[%s] write buffer manager initialize flush finished, status: %s\n", cfd_to_flush->GetName().c_str(), s.ToString().c_str()); - return s.ok(); + assert(s.ok() || (num_flushes_initiated == 0)); + return num_flushes_initiated; } } // namespace ROCKSDB_NAMESPACE diff --git a/db/db_iterator_test.cc b/db/db_iterator_test.cc index 862377b6db..2a3967d6ad 100644 --- a/db/db_iterator_test.cc +++ b/db/db_iterator_test.cc @@ -1,3 +1,17 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -3295,6 +3309,40 @@ TEST_F(DBIteratorTest, IteratorRefreshReturnSV) { Close(); } +TEST_F(DBIteratorTest, HashSpdbRefreshStatus) { + Options options = CurrentOptions(); + options.memtable_factory.reset(NewHashSpdbRepFactory()); + DestroyAndReopen(options); + Iterator* iter = db_->NewIterator(ReadOptions()); + Status s = iter->Refresh(); + ASSERT_TRUE(s.IsNotSupported()); + ASSERT_FALSE(iter->IsAllowRefresh()); + delete iter; +} + +TEST_F(DBIteratorTest, VectorRefreshStatus) { + Options options = CurrentOptions(); + options.allow_concurrent_memtable_write = false; + options.memtable_factory.reset(new VectorRepFactory()); + DestroyAndReopen(options); + Iterator* iter = db_->NewIterator(ReadOptions()); + Status s = iter->Refresh(); + ASSERT_TRUE(s.IsNotSupported()); + ASSERT_FALSE(iter->IsAllowRefresh()); + delete iter; +} + +TEST_F(DBIteratorTest, SkipListRefreshStatus) { + Options options = CurrentOptions(); + options.memtable_factory.reset(new SkipListFactory()); + DestroyAndReopen(options); + Iterator* iter = db_->NewIterator(ReadOptions()); + Status s = iter->Refresh(); + ASSERT_OK(s); + ASSERT_TRUE(iter->IsAllowRefresh()); + delete iter; +} + } // namespace ROCKSDB_NAMESPACE int main(int argc, char** argv) { diff --git a/db/file_indexer.cc b/db/file_indexer.cc index ee6cfdc03f..440d224fab 100644 --- a/db/file_indexer.cc +++ b/db/file_indexer.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -86,7 +104,9 @@ void FileIndexer::UpdateIndex(Arena* arena, const size_t num_levels, num_levels_ = num_levels; next_level_index_.resize(num_levels); - char* mem = arena->AllocateAligned(num_levels_ * sizeof(int32_t)); + char* mem = + arena->AllocateAligned(num_levels_ * sizeof(int32_t), + ArenaTracker::ArenaStats::FileIndexerUpdateIndex); level_rb_ = new (mem) int32_t[num_levels_]; for (size_t i = 0; i < num_levels_; i++) { level_rb_[i] = -1; @@ -103,7 +123,9 @@ void FileIndexer::UpdateIndex(Arena* arena, const size_t num_levels, } IndexLevel& index_level = next_level_index_[level]; index_level.num_index = upper_size; - mem = arena->AllocateAligned(upper_size * sizeof(IndexUnit)); + mem = arena->AllocateAligned( + upper_size * sizeof(IndexUnit), + ArenaTracker::ArenaStats::FileIndexerUpdateIndex); index_level.index_units = new (mem) IndexUnit[upper_size]; CalculateLB( diff --git a/db/memtable.cc b/db/memtable.cc index 6734f03773..295bd6d743 100644 --- a/db/memtable.cc +++ b/db/memtable.cc @@ -359,7 +359,8 @@ Slice MemTableRep::UserKey(const char* key) const { } KeyHandle MemTableRep::Allocate(const size_t len, char** buf) { - *buf = allocator_->Allocate(len); + *buf = + allocator_->Allocate(len, ArenaTracker::ArenaStats::DefaultMemtableImpl); return static_cast(*buf); } @@ -560,7 +561,8 @@ class MemTableIterator : public InternalIterator { InternalIterator* MemTable::NewIterator(const ReadOptions& read_options, Arena* arena) { assert(arena != nullptr); - auto mem = arena->AllocateAligned(sizeof(MemTableIterator)); + auto mem = arena->AllocateAligned( + sizeof(MemTableIterator), ArenaTracker::ArenaStats::MemTableNewIterator); return new (mem) MemTableIterator(*this, read_options, arena); } diff --git a/db/version_set.cc b/db/version_set.cc index 7db376d168..c9eb849217 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -870,7 +870,9 @@ void DoGenerateLevelFilesBrief(LevelFilesBrief* file_level, size_t num = files.size(); file_level->num_files = num; - char* mem = arena->AllocateAligned(num * sizeof(FdWithKeyRange)); + char* mem = arena->AllocateAligned( + num * sizeof(FdWithKeyRange), + ArenaTracker::ArenaStats::DoGenerateLevelFilesBrief); file_level->files = new (mem) FdWithKeyRange[num]; for (size_t i = 0; i < num; i++) { @@ -880,7 +882,9 @@ void DoGenerateLevelFilesBrief(LevelFilesBrief* file_level, // Copy key slice to sequential memory size_t smallest_size = smallest_key.size(); size_t largest_size = largest_key.size(); - mem = arena->AllocateAligned(smallest_size + largest_size); + mem = arena->AllocateAligned( + smallest_size + largest_size, + ArenaTracker::ArenaStats::DoGenerateLevelFilesBrief); memcpy(mem, smallest_key.data(), smallest_size); memcpy(mem + smallest_size, largest_key.data(), largest_size); @@ -1906,7 +1910,8 @@ InternalIterator* Version::TEST_GetLevelIterator( const ReadOptions& read_options, MergeIteratorBuilder* merge_iter_builder, int level, bool allow_unprepared_value) { auto* arena = merge_iter_builder->GetArena(); - auto* mem = arena->AllocateAligned(sizeof(LevelIterator)); + auto* mem = arena->AllocateAligned( + sizeof(LevelIterator), ArenaTracker::ArenaStats::TEST_GetLevelIterator); TruncatedRangeDelIterator*** tombstone_iter_ptr = nullptr; auto level_iter = new (mem) LevelIterator( cfd_->table_cache(), read_options, file_options_, @@ -2040,7 +2045,9 @@ void Version::AddIteratorsForLevel(const ReadOptions& read_options, // For levels > 0, we can use a concatenating iterator that sequentially // walks through the non-overlapping files in the level, opening them // lazily. - auto* mem = arena->AllocateAligned(sizeof(LevelIterator)); + auto* mem = arena->AllocateAligned( + sizeof(LevelIterator), + ArenaTracker::ArenaStats::VersionAddIteratorsForLevel); TruncatedRangeDelIterator*** tombstone_iter_ptr = nullptr; auto level_iter = new (mem) LevelIterator( cfd_->table_cache(), read_options, soptions, @@ -2103,7 +2110,9 @@ Status Version::OverlapWithLevelIterator(const ReadOptions& read_options, } } } else if (storage_info_.LevelFilesBrief(level).num_files > 0) { - auto mem = arena.AllocateAligned(sizeof(LevelIterator)); + auto mem = arena.AllocateAligned( + sizeof(LevelIterator), + ArenaTracker::ArenaStats::VersionOverlapWithLevelIterator); ScopedArenaIterator iter(new (mem) LevelIterator( cfd_->table_cache(), read_options, file_options, cfd_->internal_comparator(), &storage_info_.LevelFilesBrief(level), diff --git a/db/version_set_test.cc b/db/version_set_test.cc index 0a01c1fb21..3547593334 100644 --- a/db/version_set_test.cc +++ b/db/version_set_test.cc @@ -986,7 +986,8 @@ class FindLevelFileTest : public testing::Test { ~FindLevelFileTest() override {} void LevelFileInit(size_t num = 0) { - char* mem = arena_.AllocateAligned(num * sizeof(FdWithKeyRange)); + char* mem = arena_.AllocateAligned(num * sizeof(FdWithKeyRange), + ArenaTracker::ArenaStats::LevelFileInit); file_level_.files = new (mem) FdWithKeyRange[num]; file_level_.num_files = 0; } @@ -1001,7 +1002,8 @@ class FindLevelFileTest : public testing::Test { Slice largest_slice = largest_key.Encode(); char* mem = - arena_.AllocateAligned(smallest_slice.size() + largest_slice.size()); + arena_.AllocateAligned(smallest_slice.size() + largest_slice.size(), + ArenaTracker::ArenaStats::FindLevelFileTestAdd); memcpy(mem, smallest_slice.data(), smallest_slice.size()); memcpy(mem + smallest_slice.size(), largest_slice.data(), largest_slice.size()); diff --git a/db/write_controller.cc b/db/write_controller.cc index 64e4acd5a3..ce5487d6f4 100644 --- a/db/write_controller.cc +++ b/db/write_controller.cc @@ -149,6 +149,10 @@ void WriteController::HandleNewDelayReq(void* client_id, { std::lock_guard logger_lock(loggers_map_mu_); + // The below WARN msg is intended only when the WC is shared among loggers. + if (loggers_to_client_ids_map_.size() == 1) { + return; + } for (auto& logger_and_clients : loggers_to_client_ids_map_) { ROCKS_LOG_WARN(logger_and_clients.first.get(), "WC setting delay of %" PRIu64 diff --git a/db_stress_tool/db_stress_test_base.cc b/db_stress_tool/db_stress_test_base.cc index f254d1fb8f..fd3be38ad0 100644 --- a/db_stress_tool/db_stress_test_base.cc +++ b/db_stress_tool/db_stress_test_base.cc @@ -147,6 +147,22 @@ bool is_default(const char* flag_name) { } void ValidateEnableSpeedbFlags() { + std::vector confilct_flags = {"max_background_compactions", + "max_background_flushes", + "cache_size", + "cache_type", + "memtablerep", + "pinning_policy", + "bloom_bits", + "allow_wbm_stalls", + "db_write_buffer_size", + "initiate_wbm_flushes", + "bytes_per_sync", + "use_dynamic_delay", + "start_delay_percent", + "max_num_parallel_flushes", + "use_blob_cache"}; + if (FLAGS_enable_speedb_features && !FLAGS_crash_test) { if (is_default("max_background_jobs") || is_default("total_ram_size")) { fprintf( @@ -155,35 +171,13 @@ void ValidateEnableSpeedbFlags() { "in bytes and max_background_jobs \n"); exit(1); } - if (!is_default("max_background_compactions")) { - fprintf(stderr, - "enable_speedb_features and max_background_compactions cannot be " - "configured together \n"); - exit(1); - } - if (!is_default("max_background_flushes")) { - fprintf(stderr, - "enable_speedb_features and max_background_flushes cannot be " - "configured together \n"); - exit(1); - } - if (!FLAGS_use_dynamic_delay) { - fprintf(stderr, - "enable_speedb_features and use_dynamic_delay == false cannot be " - "configured together \n"); - exit(1); - } - if (!is_default("cache_size")) { - fprintf(stderr, - "enable_speedb_features and cache_size cannot be " - "configured together \n"); - exit(1); - } - if (FLAGS_cache_type != "lru_cache") { - fprintf(stderr, - "enable_speedb_features and cache_type != lru_cache cannot be " - "configured together \n"); - exit(1); + for (const auto& flag : confilct_flags) { + if (!is_default(flag.c_str())) { + std::string msg = "enable_speedb_features and " + flag + + " cannot be configured together \n"; + fprintf(stderr, "%s", msg.c_str()); + exit(1); + } } } } diff --git a/db_stress_tool/expected_state.cc b/db_stress_tool/expected_state.cc index 443e021454..9fa8d83bbb 100644 --- a/db_stress_tool/expected_state.cc +++ b/db_stress_tool/expected_state.cc @@ -396,7 +396,15 @@ class ExpectedStateTraceRecordHandler : public TraceRecord::Handler, state_(state), buffered_writes_(nullptr) {} - ~ExpectedStateTraceRecordHandler() { assert(IsDone()); } + ~ExpectedStateTraceRecordHandler() { + fprintf( + stderr, + "WARNING: ~ExpectedStateTraceRecordHandler - num_write_ops_: %" PRIu64 + " max_write_ops_: %" PRIu64 "\n", + num_write_ops_, max_write_ops_); + // assert(IsDone()) + ; + } // True if we have already reached the limit on write operations to apply. bool IsDone() { return num_write_ops_ == max_write_ops_; } diff --git a/db_stress_tool/no_batched_ops_stress.cc b/db_stress_tool/no_batched_ops_stress.cc index 57d5fb8a75..442ed84d5c 100644 --- a/db_stress_tool/no_batched_ops_stress.cc +++ b/db_stress_tool/no_batched_ops_stress.cc @@ -1844,7 +1844,7 @@ class NonBatchedOpsStressTest : public StressTest { op_logs += "P"; } - if (thread->rand.OneIn(2)) { + if (thread->rand.OneIn(2) && iter->IsAllowRefresh()) { pre_read_expected_values.clear(); post_read_expected_values.clear(); // Refresh after forward/backward scan to allow higher chance of SV @@ -1853,7 +1853,11 @@ class NonBatchedOpsStressTest : public StressTest { pre_read_expected_values.push_back( shared->Get(rand_column_family, i + lb)); } + // the return of Refresh doesnt has effect here cause we clear the + // pre/post expected values before. thats why we add the previous check of + // IsAllowRefresh iter->Refresh(); + for (int64_t i = 0; i < static_cast(expected_values_size); ++i) { post_read_expected_values.push_back( shared->Get(rand_column_family, i + lb)); diff --git a/include/rocksdb/iterator.h b/include/rocksdb/iterator.h index 9d4c9f73a1..937200b0be 100644 --- a/include/rocksdb/iterator.h +++ b/include/rocksdb/iterator.h @@ -1,3 +1,17 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -113,7 +127,8 @@ class Iterator : public Cleanable { virtual Status Refresh() { return Status::NotSupported("Refresh() is not supported"); } - + // Internally - previous check to Refresh + virtual bool IsAllowRefresh() { return true; } // Property "rocksdb.iterator.is-key-pinned": // If returning "1", this means that the Slice returned by key() is valid // as long as the iterator is not deleted. diff --git a/include/rocksdb/memtablerep.h b/include/rocksdb/memtablerep.h index 6344def611..6bb8baf190 100644 --- a/include/rocksdb/memtablerep.h +++ b/include/rocksdb/memtablerep.h @@ -378,6 +378,7 @@ class MemTableRepFactory : public Customizable { // false when if the already exists. // Default: false virtual bool CanHandleDuplicatedKey() const { return false; } + virtual bool IsRefreshIterSupported() const { return true; } virtual MemTableRep* PreCreateMemTableRep() { return nullptr; } virtual void PostCreateMemTableRep( MemTableRep* /*switch_mem*/, @@ -495,6 +496,7 @@ class VectorRepFactory : public MemTableRepFactory { static const char* kNickName() { return "vector"; } const char* Name() const override { return kClassName(); } const char* NickName() const override { return kNickName(); } + bool IsRefreshIterSupported() const override { return false; } // Methods for MemTableRepFactory class overrides using MemTableRepFactory::CreateMemTableRep; diff --git a/logging/log_buffer.cc b/logging/log_buffer.cc index 2763e617f4..ecababe363 100644 --- a/logging/log_buffer.cc +++ b/logging/log_buffer.cc @@ -1,8 +1,26 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + #include "logging/log_buffer.h" #include "port/port.h" @@ -20,7 +38,8 @@ void LogBuffer::AddLogToBuffer(size_t max_log_size, const char* format, return; } - char* alloc_mem = arena_.AllocateAligned(max_log_size); + char* alloc_mem = arena_.AllocateAligned( + max_log_size, ArenaTracker::ArenaStats::LogBufferAddLogToBuffer); BufferedLog* buffered_log = new (alloc_mem) BufferedLog(); char* p = buffered_log->message; char* limit = alloc_mem + max_log_size - 1; diff --git a/memory/allocator.h b/memory/allocator.h index fbbd778ca6..01998aac5a 100644 --- a/memory/allocator.h +++ b/memory/allocator.h @@ -38,8 +38,9 @@ class Allocator { public: virtual ~Allocator() {} - virtual char* Allocate(size_t bytes) = 0; - virtual char* AllocateAligned(size_t bytes, size_t huge_page_size = 0, + virtual char* Allocate(size_t bytes, uint8_t caller_name) = 0; + virtual char* AllocateAligned(size_t bytes, uint8_t caller_name, + size_t huge_page_size = 0, Logger* logger = nullptr) = 0; virtual size_t BlockSize() const = 0; diff --git a/memory/arena.cc b/memory/arena.cc index 8a1cc32741..90d63ee726 100644 --- a/memory/arena.cc +++ b/memory/arena.cc @@ -24,6 +24,8 @@ #include "memory/arena.h" #include +#include +#include #include "logging/logging.h" #include "port/malloc.h" @@ -31,7 +33,6 @@ #include "rocksdb/env.h" #include "test_util/sync_point.h" #include "util/string_util.h" - namespace ROCKSDB_NAMESPACE { size_t Arena::OptimizeBlockSize(size_t block_size) { @@ -68,18 +69,31 @@ Arena::Arena(size_t block_size, AllocTracker* tracker, size_t huge_page_size) } Arena::~Arena() { +#ifdef MEMORY_REPORTING + for (const auto& itr : blocks_) { + size_t block_size = malloc_usable_size( + const_cast(static_cast(itr.first.get()))); + arena_tracker_.arena_stats[itr.second].second.fetch_sub(block_size); + arena_tracker_.total.fetch_sub(block_size); + } + for (const auto& itr : huge_blocks_) { + size_t block_size = itr.second.second; + arena_tracker_.arena_stats[itr.second.first].second.fetch_sub(block_size); + arena_tracker_.total.fetch_sub(block_size); + } +#endif if (tracker_ != nullptr) { assert(tracker_->IsMemoryFreed()); tracker_->FreeMem(); } } -char* Arena::AllocateFallback(size_t bytes, bool aligned) { +char* Arena::AllocateFallback(size_t bytes, bool aligned, uint8_t caller_name) { if (bytes > kBlockSize / 4) { ++irregular_block_num; // Object is more than a quarter of our block size. Allocate it separately // to avoid wasting too much space in leftover bytes. - return AllocateNewBlock(bytes); + return AllocateNewBlock(bytes, caller_name); } // We waste the remaining space in the current block. @@ -87,11 +101,11 @@ char* Arena::AllocateFallback(size_t bytes, bool aligned) { char* block_head = nullptr; if (MemMapping::kHugePageSupported && hugetlb_size_ > 0) { size = hugetlb_size_; - block_head = AllocateFromHugePage(size); + block_head = AllocateFromHugePage(size, caller_name); } if (!block_head) { size = kBlockSize; - block_head = AllocateNewBlock(size); + block_head = AllocateNewBlock(size, caller_name); } alloc_bytes_remaining_ = size - bytes; @@ -106,11 +120,21 @@ char* Arena::AllocateFallback(size_t bytes, bool aligned) { } } -char* Arena::AllocateFromHugePage(size_t bytes) { +char* Arena::AllocateFromHugePage(size_t bytes, + [[maybe_unused]] uint8_t caller_name) { MemMapping mm = MemMapping::AllocateHuge(bytes); +#ifdef MEMORY_REPORTING + arena_tracker_.arena_stats[caller_name].second.fetch_add(bytes); + arena_tracker_.total.fetch_add(bytes); +#endif auto addr = static_cast(mm.Get()); if (addr) { +#ifdef MEMORY_REPORTING + huge_blocks_.push_back( + std::make_pair(std::move(mm), std::make_pair(caller_name, bytes))); +#else huge_blocks_.push_back(std::move(mm)); +#endif blocks_memory_ += bytes; if (tracker_ != nullptr) { tracker_->Allocate(bytes); @@ -119,8 +143,8 @@ char* Arena::AllocateFromHugePage(size_t bytes) { return addr; } -char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size, - Logger* logger) { +char* Arena::AllocateAligned(size_t bytes, uint8_t caller_name, + size_t huge_page_size, Logger* logger) { if (MemMapping::kHugePageSupported && hugetlb_size_ > 0 && huge_page_size > 0 && bytes > 0) { // Allocate from a huge page TLB table. @@ -128,7 +152,7 @@ char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size, ((bytes - 1U) / huge_page_size + 1U) * huge_page_size; assert(reserved_size >= bytes); - char* addr = AllocateFromHugePage(reserved_size); + char* addr = AllocateFromHugePage(reserved_size, caller_name); if (addr == nullptr) { ROCKS_LOG_WARN(logger, "AllocateAligned fail to allocate huge TLB pages: %s", @@ -150,19 +174,28 @@ char* Arena::AllocateAligned(size_t bytes, size_t huge_page_size, alloc_bytes_remaining_ -= needed; } else { // AllocateFallback always returns aligned memory - result = AllocateFallback(bytes, true /* aligned */); + result = AllocateFallback(bytes, true /* aligned */, caller_name); } assert((reinterpret_cast(result) & (kAlignUnit - 1)) == 0); return result; } -char* Arena::AllocateNewBlock(size_t block_bytes) { +char* Arena::AllocateNewBlock(size_t block_bytes, + [[maybe_unused]] uint8_t caller_name) { // NOTE: std::make_unique zero-initializes the block so is not appropriate // here char* block = new char[block_bytes]; + size_t allocated_size; +#ifdef MEMORY_REPORTING + allocated_size = malloc_usable_size(block); + arena_tracker_.arena_stats[caller_name].second.fetch_add(allocated_size); + arena_tracker_.total.fetch_add(allocated_size); + blocks_.push_back( + std::make_pair(std::unique_ptr(block), caller_name)); +#else blocks_.push_back(std::unique_ptr(block)); +#endif - size_t allocated_size; #ifdef ROCKSDB_MALLOC_USABLE_SIZE allocated_size = malloc_usable_size(block); #ifndef NDEBUG diff --git a/memory/arena.h b/memory/arena.h index 39399aa71b..ad860a8800 100644 --- a/memory/arena.h +++ b/memory/arena.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -21,10 +39,106 @@ #include "rocksdb/env.h" namespace ROCKSDB_NAMESPACE { +struct ArenaTracker { + // Count must be the last item of the enum + enum ArenaStats { + ArenaWrappedDBIter, + FileIndexerUpdateIndex, + MemTableNewIterator, + LevelFileInit, + FindLevelFileTestAdd, + DoGenerateLevelFilesBrief, + TEST_GetLevelIterator, + VersionAddIteratorsForLevel, + VersionOverlapWithLevelIterator, + LogBufferAddLogToBuffer, + arena_test, + HashLinkList, + HashLinkListIterator, + HashLinkListDynamicIterator, + HashSkipList, + HashSkipListIterator, + HashSkipListDynamicIterator, + HashSpdb, + HashSpdbIterator, + InlineSkipList, + SkipList, + SkipListIterator, + SkipListLookaheadIterator, + VectorMemtable, + CompactionMergingIterator, + NewErrorInternalIterator, + NewEmptyInternalIterator, + MergingIterator, + BlockBasedTableIterator, + BlockPrefixIndexBuilder, + CuckooTableIterator, + PlainTableBloomV1, + PlainTableIndexBuilderFillIndexes, + PlainTableReaderNewIterator, + DynamicBloom, + DefaultMemtableImpl, + WriteBatchWithIndex, + Count + }; + using stats_pair = std::pair; + std::vector arena_stats; + std::atomic_uint64_t total = {0}; + ArenaTracker() : arena_stats(Count) { + // arena_stats.reserve(ArenaStats::Count); + // The order must be the same as the enum ArenaStats order + int i = 0; + for (auto const& key : {"ArenaWrappedDBIter", + "FileIndexer::UpdateIndex", + "MemTable::NewIterator", + "LevelFileInit", + "FindLevelFileTest::Add", + "DoGenerateLevelFilesBrief", + "TEST_GetLevelIterator", + "Version::AddIteratorsForLevel", + "Version::OverlapWithLevelIterator", + "LogBuffer::AddLogToBuffer", + "arena_test", + "HashLinkList", + "HashLinkListIterator", + "HashLinkListDynamicIterator", + "HashSkipList", + "HashSkipListIterator", + "HashSkipListDynamicIterator", + "HashSpdb", + "HashSpdbIterator", + "InlineSkipList", + "SkipList", + "SkipListIterator", + "SkipListLookaheadIterator", + "VectorMemtable", + "CompactionMergingIterator", + "NewErrorInternalIterator", + "NewEmptyInternalIterator", + "MergingIterator", + "BlockBasedTableIterator", + "BlockPrefixIndex::Builder", + "CuckooTableIterator", + "PlainTableBloomV1", + "PlainTableIndexBuilder::FillIndexes", + "PlainTableReader::NewIterator", + "DynamicBloom", + "DefaultMemtableImpl", + "WriteBatchWithIndex"}) { + arena_stats[i].first = key; + arena_stats[i].second.store(0); + ++i; + } + assert(Count == i); + }; +}; class Arena : public Allocator { public: // No copying allowed +#ifdef MEMORY_REPORTING + inline static ArenaTracker arena_tracker_; +#endif Arena(const Arena&) = delete; void operator=(const Arena&) = delete; @@ -43,7 +157,7 @@ class Arena : public Allocator { AllocTracker* tracker = nullptr, size_t huge_page_size = 0); ~Arena(); - char* Allocate(size_t bytes) override; + char* Allocate(size_t bytes, uint8_t caller_name) override; // huge_page_size: if >0, will try to allocate from huage page TLB. // The argument will be the size of the page size for huge page TLB. Bytes @@ -57,7 +171,8 @@ class Arena : public Allocator { // normal cases. The messages will be logged to logger. So when calling with // huge_page_tlb_size > 0, we highly recommend a logger is passed in. // Otherwise, the error message will be printed out to stderr directly. - char* AllocateAligned(size_t bytes, size_t huge_page_size = 0, + char* AllocateAligned(size_t bytes, uint8_t caller_name, + size_t huge_page_size = 0, Logger* logger = nullptr) override; // Returns an estimate of the total memory usage of data allocated @@ -91,10 +206,17 @@ class Arena : public Allocator { alignas(std::max_align_t) char inline_block_[kInlineSize]; // Number of bytes allocated in one block const size_t kBlockSize; +#ifdef MEMORY_REPORTING + // Allocated memory blocks + std::deque, uint8_t>> blocks_; + // Huge page allocations + std::deque>> huge_blocks_; +#else // Allocated memory blocks std::deque> blocks_; // Huge page allocations std::deque huge_blocks_; +#endif size_t irregular_block_num = 0; // Stats for current active block. @@ -109,9 +231,9 @@ class Arena : public Allocator { size_t hugetlb_size_ = 0; - char* AllocateFromHugePage(size_t bytes); - char* AllocateFallback(size_t bytes, bool aligned); - char* AllocateNewBlock(size_t block_bytes); + char* AllocateFromHugePage(size_t bytes, uint8_t caller_name); + char* AllocateFallback(size_t bytes, bool aligned, uint8_t caller_name); + char* AllocateNewBlock(size_t block_bytes, uint8_t caller_name); // Bytes of memory in blocks allocated so far size_t blocks_memory_ = 0; @@ -119,7 +241,7 @@ class Arena : public Allocator { AllocTracker* tracker_; }; -inline char* Arena::Allocate(size_t bytes) { +inline char* Arena::Allocate(size_t bytes, uint8_t caller_name) { // The semantics of what to return are a bit messy if we allow // 0-byte allocations, so we disallow them here (we don't need // them for our internal use). @@ -129,7 +251,7 @@ inline char* Arena::Allocate(size_t bytes) { alloc_bytes_remaining_ -= bytes; return unaligned_alloc_ptr_; } - return AllocateFallback(bytes, false /* unaligned */); + return AllocateFallback(bytes, false /* unaligned */, caller_name); } } // namespace ROCKSDB_NAMESPACE diff --git a/memory/arena_test.cc b/memory/arena_test.cc index 592bbd723f..9c53f6f37d 100644 --- a/memory/arena_test.cc +++ b/memory/arena_test.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -46,13 +64,13 @@ void MemoryAllocatedBytesTest(size_t huge_page_size) { // allocate requested size separately req_sz = 12 * 1024; for (int i = 0; i < N; i++) { - arena.Allocate(req_sz); + arena.Allocate(req_sz, ArenaTracker::ArenaStats::arena_test); } expected_memory_allocated = req_sz * N + Arena::kInlineSize; ASSERT_PRED2(CheckMemoryAllocated, arena.MemoryAllocatedBytes(), expected_memory_allocated); - arena.Allocate(Arena::kInlineSize - 1); + arena.Allocate(Arena::kInlineSize - 1, ArenaTracker::ArenaStats::arena_test); // requested size < quarter of a block: // allocate a block with the default size, then try to use unused part @@ -60,7 +78,7 @@ void MemoryAllocatedBytesTest(size_t huge_page_size) { // Allocate(99) call. All the remaining calls won't lead to new allocation. req_sz = 99; for (int i = 0; i < N; i++) { - arena.Allocate(req_sz); + arena.Allocate(req_sz, ArenaTracker::ArenaStats::arena_test); } if (huge_page_size) { ASSERT_TRUE( @@ -79,7 +97,7 @@ void MemoryAllocatedBytesTest(size_t huge_page_size) { expected_memory_allocated = arena.MemoryAllocatedBytes(); req_sz = 8 * 1024 * 1024; for (int i = 0; i < N; i++) { - arena.Allocate(req_sz); + arena.Allocate(req_sz, ArenaTracker::ArenaStats::arena_test); } expected_memory_allocated += req_sz * N; ASSERT_PRED2(CheckMemoryAllocated, arena.MemoryAllocatedBytes(), @@ -98,11 +116,13 @@ static void ApproximateMemoryUsageTest(size_t huge_page_size) { // allocate inline bytes const size_t kAlignUnit = alignof(max_align_t); EXPECT_TRUE(arena.IsInInlineBlock()); - arena.AllocateAligned(kAlignUnit); + arena.AllocateAligned(kAlignUnit, ArenaTracker::ArenaStats::arena_test); EXPECT_TRUE(arena.IsInInlineBlock()); - arena.AllocateAligned(Arena::kInlineSize / 2 - (2 * kAlignUnit)); + arena.AllocateAligned(Arena::kInlineSize / 2 - (2 * kAlignUnit), + ArenaTracker::ArenaStats::arena_test); EXPECT_TRUE(arena.IsInInlineBlock()); - arena.AllocateAligned(Arena::kInlineSize / 2); + arena.AllocateAligned(Arena::kInlineSize / 2, + ArenaTracker::ArenaStats::arena_test); EXPECT_TRUE(arena.IsInInlineBlock()); ASSERT_EQ(arena.ApproximateMemoryUsage(), Arena::kInlineSize - kAlignUnit); ASSERT_PRED2(CheckMemoryAllocated, arena.MemoryAllocatedBytes(), @@ -111,7 +131,7 @@ static void ApproximateMemoryUsageTest(size_t huge_page_size) { auto num_blocks = kBlockSize / kEntrySize; // first allocation - arena.AllocateAligned(kEntrySize); + arena.AllocateAligned(kEntrySize, ArenaTracker::ArenaStats::arena_test); EXPECT_FALSE(arena.IsInInlineBlock()); auto mem_usage = arena.MemoryAllocatedBytes(); if (huge_page_size) { @@ -125,7 +145,7 @@ static void ApproximateMemoryUsageTest(size_t huge_page_size) { auto usage = arena.ApproximateMemoryUsage(); ASSERT_LT(usage, mem_usage); for (size_t i = 1; i < num_blocks; ++i) { - arena.AllocateAligned(kEntrySize); + arena.AllocateAligned(kEntrySize, ArenaTracker::ArenaStats::arena_test); ASSERT_EQ(mem_usage, arena.MemoryAllocatedBytes()); ASSERT_EQ(arena.ApproximateMemoryUsage(), usage + kEntrySize); EXPECT_FALSE(arena.IsInInlineBlock()); @@ -160,9 +180,9 @@ static void SimpleTest(size_t huge_page_size) { } char* r; if (rnd.OneIn(10)) { - r = arena.AllocateAligned(s); + r = arena.AllocateAligned(s, ArenaTracker::ArenaStats::arena_test); } else { - r = arena.Allocate(s); + r = arena.Allocate(s, ArenaTracker::ArenaStats::arena_test); } for (unsigned int b = 0; b < s; b++) { @@ -273,7 +293,7 @@ TEST_F(ArenaTest, UnmappedAllocation) { // The allocator might give us back recycled memory for a while, but // shouldn't last forever. for (int i = 0;; ++i) { - char* p = arena.Allocate(kBlockSize); + char* p = arena.Allocate(kBlockSize, ArenaTracker::ArenaStats::arena_test); // Start counting page faults PopMinorPageFaultCount(); diff --git a/memory/concurrent_arena.h b/memory/concurrent_arena.h index f14507d302..67c1d8f27b 100644 --- a/memory/concurrent_arena.h +++ b/memory/concurrent_arena.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -49,22 +67,29 @@ class ConcurrentArena : public Allocator { AllocTracker* tracker = nullptr, size_t huge_page_size = 0); - char* Allocate(size_t bytes) override { - return AllocateImpl(bytes, false /*force_arena*/, - [this, bytes]() { return arena_.Allocate(bytes); }); + char* Allocate(size_t bytes, uint8_t caller_name) override { + return AllocateImpl( + bytes, false /*force_arena*/, + [this, caller_name, bytes]() { + return arena_.Allocate(bytes, caller_name); + }, + caller_name); } - char* AllocateAligned(size_t bytes, size_t huge_page_size = 0, + char* AllocateAligned(size_t bytes, uint8_t caller_name, + size_t huge_page_size = 0, Logger* logger = nullptr) override { size_t rounded_up = ((bytes - 1) | (sizeof(void*) - 1)) + 1; assert(rounded_up >= bytes && rounded_up < bytes + sizeof(void*) && (rounded_up % sizeof(void*)) == 0); - return AllocateImpl(rounded_up, huge_page_size != 0 /*force_arena*/, - [this, rounded_up, huge_page_size, logger]() { - return arena_.AllocateAligned(rounded_up, - huge_page_size, logger); - }); + return AllocateImpl( + rounded_up, huge_page_size != 0 /*force_arena*/, + [this, caller_name, rounded_up, huge_page_size, logger]() { + return arena_.AllocateAligned(rounded_up, caller_name, huge_page_size, + logger); + }, + caller_name); } size_t ApproximateMemoryUsage() const { @@ -126,7 +151,8 @@ class ConcurrentArena : public Allocator { } template - char* AllocateImpl(size_t bytes, bool force_arena, const Func& func) { + char* AllocateImpl(size_t bytes, bool force_arena, const Func& func, + uint8_t caller_name) { size_t cpu; // Go directly to the arena if the allocation is too large, or if @@ -182,7 +208,7 @@ class ConcurrentArena : public Allocator { avail = exact >= shard_block_size_ / 2 && exact < shard_block_size_ * 2 ? exact : shard_block_size_; - s->free_begin_ = arena_.AllocateAligned(avail); + s->free_begin_ = arena_.AllocateAligned(avail, caller_name); Fixup(); } s->allocated_and_unused_.store(avail - bytes, std::memory_order_relaxed); diff --git a/memory/memory_allocator.cc b/memory/memory_allocator.cc index b509f98b26..66fd46f5c7 100644 --- a/memory/memory_allocator.cc +++ b/memory/memory_allocator.cc @@ -27,6 +27,7 @@ #include "utilities/memory_allocators.h" namespace ROCKSDB_NAMESPACE { + namespace { static std::unordered_map ma_wrapper_type_info = { {Customizable::kTargetPropName(), diff --git a/memory/memory_allocator_impl.h b/memory/memory_allocator_impl.h index 68aa35beb8..9070255ae7 100644 --- a/memory/memory_allocator_impl.h +++ b/memory/memory_allocator_impl.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -7,15 +25,26 @@ #pragma once #include +#include #include "rocksdb/memory_allocator.h" - +#ifdef ROCKSDB_MALLOC_USABLE_SIZE +#include +#endif namespace ROCKSDB_NAMESPACE { - +#ifdef MEMORY_REPORTING +struct blockfetchermem { + inline static std::atomic_int64_t mem = {0}; +}; +#endif struct CustomDeleter { CustomDeleter(MemoryAllocator* a = nullptr) : allocator(a) {} void operator()(char* ptr) const { +#ifdef MEMORY_REPORTING + ROCKSDB_NAMESPACE::blockfetchermem::mem.fetch_sub( + malloc_usable_size(const_cast(static_cast(ptr)))); +#endif if (allocator) { allocator->Deallocate(reinterpret_cast(ptr)); } else { @@ -24,6 +53,7 @@ struct CustomDeleter { } MemoryAllocator* allocator; + size_t bytes_ = 0; }; using CacheAllocationPtr = std::unique_ptr; @@ -31,10 +61,18 @@ using CacheAllocationPtr = std::unique_ptr; inline CacheAllocationPtr AllocateBlock(size_t size, MemoryAllocator* allocator) { if (allocator) { +#ifdef MEMORY_REPORTING + ROCKSDB_NAMESPACE::blockfetchermem::mem.fetch_add(size); +#endif auto block = reinterpret_cast(allocator->Allocate(size)); - return CacheAllocationPtr(block, allocator); + return CacheAllocationPtr(block, {allocator}); } - return CacheAllocationPtr(new char[size]); + char* cache = new char[size]; +#ifdef MEMORY_REPORTING + ROCKSDB_NAMESPACE::blockfetchermem::mem.fetch_add( + malloc_usable_size(const_cast(static_cast(cache)))); +#endif + return CacheAllocationPtr(cache); } inline CacheAllocationPtr AllocateAndCopyBlock(const Slice& data, diff --git a/memtable/hash_linklist_rep.cc b/memtable/hash_linklist_rep.cc index 32fcbcb457..ff77998007 100644 --- a/memtable/hash_linklist_rep.cc +++ b/memtable/hash_linklist_rep.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -517,8 +535,9 @@ HashLinkListRep::HashLinkListRep( logger_(logger), bucket_entries_logging_threshold_(bucket_entries_logging_threshold), if_log_bucket_dist_when_flash_(if_log_bucket_dist_when_flash) { - char* mem = allocator_->AllocateAligned(sizeof(Pointer) * bucket_size, - huge_page_tlb_size, logger); + char* mem = allocator_->AllocateAligned( + sizeof(Pointer) * bucket_size, ArenaTracker::ArenaStats::HashLinkList, + huge_page_tlb_size, logger); buckets_ = new (mem) Pointer[bucket_size]; @@ -530,7 +549,8 @@ HashLinkListRep::HashLinkListRep( HashLinkListRep::~HashLinkListRep() {} KeyHandle HashLinkListRep::Allocate(const size_t len, char** buf) { - char* mem = allocator_->AllocateAligned(sizeof(Node) + len); + char* mem = allocator_->AllocateAligned( + sizeof(Node) + len, ArenaTracker::ArenaStats::HashLinkList); Node* x = new (mem) Node(); *buf = x->key; return static_cast(x); @@ -608,7 +628,8 @@ void HashLinkListRep::Insert(KeyHandle handle) { // the new node. Otherwise, we might need to change next pointer of first. // In that case, a reader might sees the next pointer is NULL and wrongly // think the node is a bucket header. - auto* mem = allocator_->AllocateAligned(sizeof(BucketHeader)); + auto* mem = allocator_->AllocateAligned( + sizeof(BucketHeader), ArenaTracker::ArenaStats::HashLinkList); header = new (mem) BucketHeader(first, 1); bucket.store(header, std::memory_order_release); } else { @@ -643,7 +664,8 @@ void HashLinkListRep::Insert(KeyHandle handle) { LinkListIterator bucket_iter( this, reinterpret_cast( first_next_pointer->load(std::memory_order_relaxed))); - auto mem = allocator_->AllocateAligned(sizeof(SkipListBucketHeader)); + auto mem = allocator_->AllocateAligned( + sizeof(SkipListBucketHeader), ArenaTracker::ArenaStats::HashLinkList); SkipListBucketHeader* new_skip_list_header = new (mem) SkipListBucketHeader(compare_, allocator_, header->GetNumEntries() + 1); auto& skip_list = new_skip_list_header->skip_list; @@ -799,7 +821,9 @@ MemTableRep::Iterator* HashLinkListRep::GetIterator(Arena* alloc_arena, if (alloc_arena == nullptr) { return new FullListIterator(list, new_arena); } else { - auto mem = alloc_arena->AllocateAligned(sizeof(FullListIterator)); + auto mem = alloc_arena->AllocateAligned( + sizeof(FullListIterator), + ArenaTracker::ArenaStats::HashLinkListIterator); return new (mem) FullListIterator(list, new_arena); } } @@ -809,7 +833,9 @@ MemTableRep::Iterator* HashLinkListRep::GetDynamicPrefixIterator( if (alloc_arena == nullptr) { return new DynamicIterator(*this); } else { - auto mem = alloc_arena->AllocateAligned(sizeof(DynamicIterator)); + auto mem = alloc_arena->AllocateAligned( + sizeof(DynamicIterator), + ArenaTracker::ArenaStats::HashLinkListDynamicIterator); return new (mem) DynamicIterator(*this); } } diff --git a/memtable/hash_skiplist_rep.cc b/memtable/hash_skiplist_rep.cc index b3ffc4227c..228f6cd469 100644 --- a/memtable/hash_skiplist_rep.cc +++ b/memtable/hash_skiplist_rep.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -241,7 +259,8 @@ HashSkipListRep::HashSkipListRep(const MemTableRep::KeyComparator& compare, compare_(compare), allocator_(allocator) { auto mem = - allocator->AllocateAligned(sizeof(std::atomic) * bucket_size); + allocator->AllocateAligned(sizeof(std::atomic) * bucket_size, + ArenaTracker::ArenaStats::HashSkipList); buckets_ = new (mem) std::atomic[bucket_size]; for (size_t i = 0; i < bucket_size_; ++i) { @@ -256,7 +275,8 @@ HashSkipListRep::Bucket* HashSkipListRep::GetInitializedBucket( size_t hash = GetHash(transformed); auto bucket = GetBucket(hash); if (bucket == nullptr) { - auto addr = allocator_->AllocateAligned(sizeof(Bucket)); + auto addr = allocator_->AllocateAligned( + sizeof(Bucket), ArenaTracker::ArenaStats::HashSkipList); bucket = new (addr) Bucket(compare_, allocator_, skiplist_height_, skiplist_branching_factor_); buckets_[hash].store(bucket, std::memory_order_release); @@ -313,7 +333,8 @@ MemTableRep::Iterator* HashSkipListRep::GetIterator(Arena* arena, if (arena == nullptr) { return new Iterator(list, true, new_arena); } else { - auto mem = arena->AllocateAligned(sizeof(Iterator)); + auto mem = arena->AllocateAligned( + sizeof(Iterator), ArenaTracker::ArenaStats::HashSkipListIterator); return new (mem) Iterator(list, true, new_arena); } } @@ -322,7 +343,9 @@ MemTableRep::Iterator* HashSkipListRep::GetDynamicPrefixIterator(Arena* arena) { if (arena == nullptr) { return new DynamicIterator(*this); } else { - auto mem = arena->AllocateAligned(sizeof(DynamicIterator)); + auto mem = arena->AllocateAligned( + sizeof(DynamicIterator), + ArenaTracker::ArenaStats::HashSkipListDynamicIterator); return new (mem) DynamicIterator(*this); } } diff --git a/memtable/hash_spdb_rep.cc b/memtable/hash_spdb_rep.cc index be88d3ca77..44858746da 100644 --- a/memtable/hash_spdb_rep.cc +++ b/memtable/hash_spdb_rep.cc @@ -483,7 +483,8 @@ KeyHandle HashSpdbRep::Allocate(const size_t len, char** buf) { // std::max(len, kInlineDataSize) - kInlineDataSize + // sizeof(SpdbKeyHandle); SpdbKeyHandle* h = - reinterpret_cast(allocator_->AllocateAligned(alloc_size)); + reinterpret_cast(allocator_->AllocateAligned( + alloc_size, ArenaTracker::ArenaStats::HashSpdb)); *buf = h->key_; return h; } @@ -526,7 +527,8 @@ MemTableRep::Iterator* HashSpdbRep::GetIterator(Arena* arena, bool part_of_flush) { if (arena != nullptr) { void* mem; - mem = arena->AllocateAligned(sizeof(SpdbVectorIterator)); + mem = arena->AllocateAligned(sizeof(SpdbVectorIterator), + ArenaTracker::ArenaStats::HashSpdbIterator); return new (mem) SpdbVectorIterator(spdb_vectors_cont_, GetComparator(), part_of_flush); } @@ -566,6 +568,7 @@ class HashSpdbRepFactory : public MemTableRepFactory { Logger* logger) override; bool IsInsertConcurrentlySupported() const override { return true; } bool CanHandleDuplicatedKey() const override { return true; } + bool IsRefreshIterSupported() const override { return false; } MemTableRep* PreCreateMemTableRep() override; void PostCreateMemTableRep(MemTableRep* switch_mem, const MemTableRep::KeyComparator& compare, diff --git a/memtable/inlineskiplist.h b/memtable/inlineskiplist.h index abb3c3ddb7..ccd22e2018 100644 --- a/memtable/inlineskiplist.h +++ b/memtable/inlineskiplist.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -49,6 +67,7 @@ #include #include "memory/allocator.h" +#include "memory/arena.h" #include "port/likely.h" #include "port/port.h" #include "rocksdb/slice.h" @@ -679,7 +698,9 @@ InlineSkipList::AllocateNode(size_t key_size, int height) { // raw + prefix, and holds the bottom-mode (level 0) skip list pointer // next_[0]. key_size is the bytes for the key, which comes just after // the Node. - char* raw = allocator_->AllocateAligned(prefix + sizeof(Node) + key_size); + char* raw = + allocator_->AllocateAligned(prefix + sizeof(Node) + key_size, + ArenaTracker::ArenaStats::InlineSkipList); Node* x = reinterpret_cast(raw + prefix); // Once we've linked the node into the skip list we don't actually need @@ -698,7 +719,9 @@ typename InlineSkipList::Splice* InlineSkipList::AllocateSplice() { // size of prev_ and next_ size_t array_size = sizeof(Node*) * (kMaxHeight_ + 1); - char* raw = allocator_->AllocateAligned(sizeof(Splice) + array_size * 2); + char* raw = + allocator_->AllocateAligned(sizeof(Splice) + array_size * 2, + ArenaTracker::ArenaStats::InlineSkipList); Splice* splice = reinterpret_cast(raw); splice->height_ = 0; splice->prev_ = reinterpret_cast(raw + sizeof(Splice)); diff --git a/memtable/skiplist.h b/memtable/skiplist.h index e3cecd30c1..7e8856368c 100644 --- a/memtable/skiplist.h +++ b/memtable/skiplist.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -37,9 +55,9 @@ #include #include "memory/allocator.h" +#include "memory/arena.h" #include "port/port.h" #include "util/random.h" - namespace ROCKSDB_NAMESPACE { template @@ -206,7 +224,8 @@ template typename SkipList::Node* SkipList::NewNode( const Key& key, int height) { char* mem = allocator_->AllocateAligned( - sizeof(Node) + sizeof(std::atomic) * (height - 1)); + sizeof(Node) + sizeof(std::atomic) * (height - 1), + ArenaTracker::ArenaStats::SkipList); return new (mem) Node(key); } @@ -425,8 +444,8 @@ SkipList::SkipList(const Comparator cmp, Allocator* allocator, // Allocate the prev_ Node* array, directly from the passed-in allocator. // prev_ does not need to be freed, as its life cycle is tied up with // the allocator as a whole. - prev_ = reinterpret_cast( - allocator_->AllocateAligned(sizeof(Node*) * kMaxHeight_)); + prev_ = reinterpret_cast(allocator_->AllocateAligned( + sizeof(Node*) * kMaxHeight_, ArenaTracker::ArenaStats::SkipList)); for (int i = 0; i < kMaxHeight_; i++) { head_->SetNext(i, nullptr); prev_[i] = head_; diff --git a/memtable/skiplistrep.cc b/memtable/skiplistrep.cc index cb8132073e..cc322b81ea 100644 --- a/memtable/skiplistrep.cc +++ b/memtable/skiplistrep.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -330,12 +348,17 @@ class SkipListRep : public MemTableRep { MemTableRep::Iterator* SkipListRep::GetIterator(Arena* arena, bool /*part_of_flush*/) { if (lookahead_ > 0) { - void* mem = - arena ? arena->AllocateAligned(sizeof(SkipListRep::LookaheadIterator)) : - operator new(sizeof(SkipListRep::LookaheadIterator)); + void* mem = arena ? arena->AllocateAligned( + sizeof(SkipListRep::LookaheadIterator), + ArenaTracker::ArenaStats::SkipListLookaheadIterator) + : + operator new(sizeof(SkipListRep::LookaheadIterator)); return new (mem) SkipListRep::LookaheadIterator(*this); } else { - void* mem = arena ? arena->AllocateAligned(sizeof(SkipListRep::Iterator)) : + void* mem = arena ? arena->AllocateAligned( + sizeof(SkipListRep::Iterator), + ArenaTracker::ArenaStats::SkipListIterator) + : operator new(sizeof(SkipListRep::Iterator)); return new (mem) SkipListRep::Iterator(&skip_list_); } diff --git a/memtable/vectorrep.cc b/memtable/vectorrep.cc index c64e38dc5e..e42569e75b 100644 --- a/memtable/vectorrep.cc +++ b/memtable/vectorrep.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -268,7 +286,8 @@ MemTableRep::Iterator* VectorRep::GetIterator(Arena* arena, bool /*part_of_flush*/) { char* mem = nullptr; if (arena != nullptr) { - mem = arena->AllocateAligned(sizeof(Iterator)); + mem = arena->AllocateAligned(sizeof(Iterator), + ArenaTracker::ArenaStats::VectorMemtable); } ReadLock l(&rwlock_); // Do not sort here. The sorting would be done the first time diff --git a/memtable/write_buffer_manager.cc b/memtable/write_buffer_manager.cc index 9d8bfe600e..bdfc389798 100644 --- a/memtable/write_buffer_manager.cc +++ b/memtable/write_buffer_manager.cc @@ -809,9 +809,9 @@ void WriteBufferManager::FlushEnded(bool /* wbm_initiated */) { // the WBM will not be aware of the number of running flushes at the time // it is enabled. The counter will become valid once all of the flushes // that were running when it was enabled will have completed. - if (num_running_flushes_ > 0U) { - --num_running_flushes_; - } + assert(num_running_flushes_ > 0U); + --num_running_flushes_; + size_t curr_memory_used = memory_usage(); RecalcFlushInitiationSize(); ReevaluateNeedForMoreFlushesLockHeld(curr_memory_used); diff --git a/memtable/write_buffer_manager_test.cc b/memtable/write_buffer_manager_test.cc index 035490a5d3..893893b6dc 100644 --- a/memtable/write_buffer_manager_test.cc +++ b/memtable/write_buffer_manager_test.cc @@ -905,7 +905,8 @@ TEST_P(WriteBufferManagerFlushInitiationTest, DISABLED_FlushInitiationSteps) { DeregisterInitiator(initiator_id); } -TEST_P(WriteBufferManagerFlushInitiationTest, RegisteringLate) { +// TODO - The test is flaky. Investigate why and either fix it or remvoe it +TEST_P(WriteBufferManagerFlushInitiationTest, DISABLED_RegisteringLate) { // Reach the 1st step, but no registered initiators wbm_->ReserveMem(flush_step_size_); IncNumFlushesToInitiate(); diff --git a/monitoring/statistics.cc b/monitoring/statistics.cc index 6b9ca4b6c9..b6a19badd0 100644 --- a/monitoring/statistics.cc +++ b/monitoring/statistics.cc @@ -389,8 +389,6 @@ static std::unordered_map stats_type_info = { StatisticsImpl::StatisticsImpl(std::shared_ptr stats) : stats_(std::move(stats)) { RegisterOptions("StatisticsOptions", &stats_, &stats_type_info); - printf("StatisticsData.size=%d\n", (int)sizeof(StatisticsData)); - printf("per_core_stats_.size=%d\n", (int)sizeof(per_core_stats_)); } StatisticsImpl::~StatisticsImpl() {} diff --git a/speedb/version.h b/speedb/version.h index f50314d836..2b3b29709d 100644 --- a/speedb/version.h +++ b/speedb/version.h @@ -16,7 +16,7 @@ #pragma once #define SPEEDB_MAJOR 2 -#define SPEEDB_MINOR 7 +#define SPEEDB_MINOR 8 #define SPEEDB_PATCH 0 namespace ROCKSDB_NAMESPACE { diff --git a/table/block_based/block_based_table_reader.cc b/table/block_based/block_based_table_reader.cc index 498bdfab14..9c87f6bb58 100644 --- a/table/block_based/block_based_table_reader.cc +++ b/table/block_based/block_based_table_reader.cc @@ -1886,7 +1886,9 @@ InternalIterator* BlockBasedTable::NewIterator( need_upper_bound_check, prefix_extractor, caller, compaction_readahead_size, allow_unprepared_value); } else { - auto* mem = arena->AllocateAligned(sizeof(BlockBasedTableIterator)); + auto* mem = arena->AllocateAligned( + sizeof(BlockBasedTableIterator), + ArenaTracker::ArenaStats::BlockBasedTableIterator); return new (mem) BlockBasedTableIterator( this, read_options, rep_->internal_comparator, std::move(index_iter), !skip_filters && !read_options.total_order_seek && diff --git a/table/block_based/block_prefix_index.cc b/table/block_based/block_prefix_index.cc index c83701d69c..5b6f5b5008 100644 --- a/table/block_based/block_prefix_index.cc +++ b/table/block_based/block_prefix_index.cc @@ -1,3 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -70,8 +89,10 @@ struct PrefixRecord { class BlockPrefixIndex::Builder { public: void Add(const Slice& key_prefix, uint32_t start_block, uint32_t num_blocks) { - PrefixRecord* record = reinterpret_cast( - arena_.AllocateAligned(sizeof(PrefixRecord))); + PrefixRecord* record = + reinterpret_cast(arena_.AllocateAligned( + sizeof(PrefixRecord), + ArenaTracker::ArenaStats::BlockPrefixIndexBuilder)); record->prefix = key_prefix; record->start_block = start_block; record->end_block = start_block + num_blocks - 1; diff --git a/table/block_fetcher.cc b/table/block_fetcher.cc index 34d3e23e9a..6a829a52d6 100644 --- a/table/block_fetcher.cc +++ b/table/block_fetcher.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -11,6 +29,7 @@ #include #include +#include #include #include "logging/logging.h" @@ -155,6 +174,7 @@ inline void BlockFetcher::PrepareBufferForBlockFromFile() { AllocateBlock(block_size_with_trailer_, memory_allocator_compressed_); used_buf_ = compressed_buf_.get(); } else { + // std::cout << block_size_with_trailer_ << std::endl; heap_buf_ = AllocateBlock(block_size_with_trailer_, memory_allocator_); used_buf_ = heap_buf_.get(); } diff --git a/table/compaction_merging_iterator.cc b/table/compaction_merging_iterator.cc index 98581b16d7..c1272d1b4e 100644 --- a/table/compaction_merging_iterator.cc +++ b/table/compaction_merging_iterator.cc @@ -1,3 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // Copyright (c) Meta Platforms, Inc. and affiliates. // // This source code is licensed under both the GPLv2 (found in the @@ -361,7 +380,9 @@ InternalIterator* NewCompactionMergingIterator( false /* is_arena_mode */, range_tombstone_iters); } else { - auto mem = arena->AllocateAligned(sizeof(CompactionMergingIterator)); + auto mem = arena->AllocateAligned( + sizeof(CompactionMergingIterator), + ArenaTracker::ArenaStats::CompactionMergingIterator); return new (mem) CompactionMergingIterator(comparator, children, n, true /* is_arena_mode */, range_tombstone_iters); diff --git a/table/cuckoo/cuckoo_table_reader.cc b/table/cuckoo/cuckoo_table_reader.cc index a4479ab60c..8bd9453424 100644 --- a/table/cuckoo/cuckoo_table_reader.cc +++ b/table/cuckoo/cuckoo_table_reader.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -400,7 +418,9 @@ InternalIterator* CuckooTableReader::NewIterator( if (arena == nullptr) { iter = new CuckooTableIterator(this); } else { - auto iter_mem = arena->AllocateAligned(sizeof(CuckooTableIterator)); + auto iter_mem = + arena->AllocateAligned(sizeof(CuckooTableIterator), + ArenaTracker::ArenaStats::CuckooTableIterator); iter = new (iter_mem) CuckooTableIterator(this); } return iter; diff --git a/table/iterator.cc b/table/iterator.cc index 14e280a07b..774955bf69 100644 --- a/table/iterator.cc +++ b/table/iterator.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -98,7 +116,8 @@ InternalIteratorBase* NewErrorInternalIterator(const Status& status, if (arena == nullptr) { return NewErrorInternalIterator(status); } else { - auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator)); + auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator), + ArenaTracker::NewErrorInternalIterator); return new (mem) EmptyInternalIterator(status); } } @@ -119,7 +138,8 @@ InternalIteratorBase* NewEmptyInternalIterator(Arena* arena) { if (arena == nullptr) { return NewEmptyInternalIterator(); } else { - auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator)); + auto mem = arena->AllocateAligned(sizeof(EmptyInternalIterator), + ArenaTracker::NewEmptyInternalIterator); return new (mem) EmptyInternalIterator(Status::OK()); } } diff --git a/table/merging_iterator.cc b/table/merging_iterator.cc index 505cd76d38..c74ec0e354 100644 --- a/table/merging_iterator.cc +++ b/table/merging_iterator.cc @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -1635,7 +1653,8 @@ InternalIterator* NewMergingIterator(const InternalKeyComparator* cmp, if (arena == nullptr) { return new MergingIterator(cmp, list, n, false, prefix_seek_mode); } else { - auto mem = arena->AllocateAligned(sizeof(MergingIterator)); + auto mem = arena->AllocateAligned( + sizeof(MergingIterator), ArenaTracker::ArenaStats::MergingIterator); return new (mem) MergingIterator(cmp, list, n, true, prefix_seek_mode); } } @@ -1645,7 +1664,8 @@ MergeIteratorBuilder::MergeIteratorBuilder( const InternalKeyComparator* comparator, Arena* a, bool prefix_seek_mode, const Slice* iterate_upper_bound) : first_iter(nullptr), use_merging_iter(false), arena(a) { - auto mem = arena->AllocateAligned(sizeof(MergingIterator)); + auto mem = arena->AllocateAligned(sizeof(MergingIterator), + ArenaTracker::ArenaStats::MergingIterator); merge_iter = new (mem) MergingIterator(comparator, nullptr, 0, true, prefix_seek_mode, iterate_upper_bound); } diff --git a/table/plain/plain_table_bloom.cc b/table/plain/plain_table_bloom.cc index 21441f6161..b0d4b8f15a 100644 --- a/table/plain/plain_table_bloom.cc +++ b/table/plain/plain_table_bloom.cc @@ -1,8 +1,26 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + #include "table/plain/plain_table_bloom.h" #include @@ -56,7 +74,9 @@ void PlainTableBloomV1::SetTotalBits(Allocator* allocator, uint32_t total_bits, } assert(allocator); - char* raw = allocator->AllocateAligned(sz, huge_page_tlb_size, logger); + char* raw = allocator->AllocateAligned( + sz, ArenaTracker::ArenaStats::PlainTableBloomV1, huge_page_tlb_size, + logger); memset(raw, 0, sz); auto cache_line_offset = reinterpret_cast(raw) % CACHE_LINE_SIZE; if (kNumBlocks > 0 && cache_line_offset > 0) { diff --git a/table/plain/plain_table_bloom.h b/table/plain/plain_table_bloom.h index 460e7ec390..055f516315 100644 --- a/table/plain/plain_table_bloom.h +++ b/table/plain/plain_table_bloom.h @@ -1,4 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). @@ -8,12 +26,12 @@ #include #include +#include "memory/arena.h" #include "port/port.h" #include "rocksdb/slice.h" #include "util/bloom_impl.h" #include "util/hash.h" #include "util/math.h" - namespace ROCKSDB_NAMESPACE { class Slice; class Allocator; diff --git a/table/plain/plain_table_index.cc b/table/plain/plain_table_index.cc index c85176d6ca..2a7b7aaa1c 100644 --- a/table/plain/plain_table_index.cc +++ b/table/plain/plain_table_index.cc @@ -1,8 +1,26 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + #include "table/plain/plain_table_index.h" #include @@ -158,7 +176,9 @@ Slice PlainTableIndexBuilder::FillIndexes( sub_index_size_); auto total_allocate_size = GetTotalSize(); char* allocated = arena_->AllocateAligned( - total_allocate_size, huge_page_tlb_size_, ioptions_.logger); + total_allocate_size, + ArenaTracker::ArenaStats::PlainTableIndexBuilderFillIndexes, + huge_page_tlb_size_, ioptions_.logger); auto temp_ptr = EncodeVarint32(allocated, index_size_); uint32_t* index = diff --git a/table/plain/plain_table_reader.cc b/table/plain/plain_table_reader.cc index a74da1f895..feaaa56b70 100644 --- a/table/plain/plain_table_reader.cc +++ b/table/plain/plain_table_reader.cc @@ -1,3 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. // Copyright (c) 2011 The LevelDB Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -207,7 +226,9 @@ InternalIterator* PlainTableReader::NewIterator( if (arena == nullptr) { return new PlainTableIterator(this, use_prefix_seek); } else { - auto mem = arena->AllocateAligned(sizeof(PlainTableIterator)); + auto mem = arena->AllocateAligned( + sizeof(PlainTableIterator), + ArenaTracker::ArenaStats::PlainTableReaderNewIterator); return new (mem) PlainTableIterator(this, use_prefix_seek); } } diff --git a/test_util/sync_point_impl.h b/test_util/sync_point_impl.h index 64cc0445e0..ccb7c94130 100644 --- a/test_util/sync_point_impl.h +++ b/test_util/sync_point_impl.h @@ -1,8 +1,26 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + #include #include @@ -28,11 +46,12 @@ namespace ROCKSDB_NAMESPACE { // Arena depends on SyncPoint and create circular dependency. class SingleAllocator : public Allocator { public: - char* Allocate(size_t) override { + char* Allocate(size_t, [[maybe_unused]] uint8_t caller_name) override { assert(false); return nullptr; } - char* AllocateAligned(size_t bytes, size_t, Logger*) override { + char* AllocateAligned(size_t bytes, [[maybe_unused]] uint8_t caller_name, + size_t, Logger*) override { buf_.resize(bytes); return const_cast(buf_.data()); } diff --git a/tools/db_bench_tool.cc b/tools/db_bench_tool.cc index 0fbee58055..4c965d4e4c 100644 --- a/tools/db_bench_tool.cc +++ b/tools/db_bench_tool.cc @@ -2537,6 +2537,7 @@ class Stats { next_report_ += 50000; else next_report_ += 100000; + fprintf(stderr, "... finished %" PRIu64 " ops%30s\r", done_, ""); } else { uint64_t now = clock_->NowMicros(); diff --git a/tools/db_crashtest.py b/tools/db_crashtest.py index 4f71f1ae6c..44f56d1dec 100644 --- a/tools/db_crashtest.py +++ b/tools/db_crashtest.py @@ -247,15 +247,12 @@ "sync_wal_one_in": 100000, "customopspercent": 0, # "filter_uri": lambda: random.choice(["speedb.PairedBloomFilter", ""]), - # disable hash_spd until issues are fixed. - # "memtablerep": lambda: random.choice(["skip_list", "hash_spdb"]), - "memtablerep": "skip_list", + "memtablerep": lambda: random.choice(["skip_list", "hash_spdb"]), "pinning_policy": lambda: random.choice(["default", "scoped"]), "use_dynamic_delay": lambda: random.choice([0, 1, 1, 1]), "allow_wbm_stalls": lambda: random.randint(0, 1), "start_delay_percent": lambda: random.randint(0, 99), - # disable until hash_spd issues are fixed. - # "enable_speedb_features": lambda: random.randint(0, 1), + "enable_speedb_features": lambda: random.randint(0, 1), "total_ram_size": lambda: random.choice([512 * 1024 * 1024, 1024 * 1024 * 1024]), "max_background_jobs": lambda: random.choice([4, 8]), "crash_test": 1, diff --git a/util/dynamic_bloom.cc b/util/dynamic_bloom.cc index 0ff3b4a758..301cbe56f3 100644 --- a/util/dynamic_bloom.cc +++ b/util/dynamic_bloom.cc @@ -1,3 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -55,7 +74,8 @@ DynamicBloom::DynamicBloom(Allocator* allocator, uint32_t total_bits, sz += block_bytes - 1; assert(allocator); - char* raw = allocator->AllocateAligned(sz, huge_page_tlb_size, logger); + char* raw = allocator->AllocateAligned( + sz, ArenaTracker::ArenaStats::DynamicBloom, huge_page_tlb_size, logger); memset(raw, 0, sz); auto block_offset = reinterpret_cast(raw) % block_bytes; if (block_offset > 0) { diff --git a/util/dynamic_bloom.h b/util/dynamic_bloom.h index 0ff1053ca6..5a6463ede3 100644 --- a/util/dynamic_bloom.h +++ b/util/dynamic_bloom.h @@ -1,3 +1,22 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License @@ -10,6 +29,7 @@ #include #include +#include "memory/arena.h" #include "port/port.h" #include "rocksdb/slice.h" #include "table/multiget_context.h" diff --git a/utilities/write_batch_with_index/write_batch_with_index.cc b/utilities/write_batch_with_index/write_batch_with_index.cc index 208eeb44be..f6b8e85fe6 100644 --- a/utilities/write_batch_with_index/write_batch_with_index.cc +++ b/utilities/write_batch_with_index/write_batch_with_index.cc @@ -1,8 +1,25 @@ +// Copyright (C) 2023 Speedb Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). #include "rocksdb/utilities/write_batch_with_index.h" @@ -159,7 +176,8 @@ void WriteBatchWithIndex::Rep::AddNewEntry(uint32_t column_family_id) { key.remove_suffix(ts_sz); } - auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry)); + auto* mem = arena.Allocate(sizeof(WriteBatchIndexEntry), + ArenaTracker::ArenaStats::WriteBatchWithIndex); auto* index_entry = new (mem) WriteBatchIndexEntry(last_entry_offset, column_family_id, key.data() - wb_data.data(), key.size());