Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PageStorage: Log down the gc time for external pages #5739

Merged
merged 13 commits into from
Aug 31, 2022
1 change: 1 addition & 0 deletions dbms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ add_headers_and_sources(dbms src/Storages/Page/V3)
add_headers_and_sources(dbms src/Storages/Page/V3/LogFile)
add_headers_and_sources(dbms src/Storages/Page/V3/WAL)
add_headers_and_sources(dbms src/Storages/Page/V3/spacemap)
add_headers_and_sources(dbms src/Storages/Page/V3/PageDirectory)
add_headers_and_sources(dbms src/Storages/Page/)
add_headers_and_sources(dbms src/TiDB)
add_headers_and_sources(dbms src/Client)
Expand Down
11 changes: 2 additions & 9 deletions dbms/src/Storages/DeltaMerge/StoragePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,6 @@ void StoragePool::dataRegisterExternalPagesCallbacks(const ExternalPageCallbacks
break;
}
case PageStorageRunMode::ONLY_V3:
{
data_storage_v3->registerExternalPagesCallbacks(callbacks);
break;
}
case PageStorageRunMode::MIX_MODE:
{
// We have transformed all pages from V2 to V3 in `restore`, so
Expand All @@ -570,13 +566,10 @@ void StoragePool::dataUnregisterExternalPagesCallbacks(NamespaceId ns_id)
break;
}
case PageStorageRunMode::ONLY_V3:
{
data_storage_v3->unregisterExternalPagesCallbacks(ns_id);
break;
}
case PageStorageRunMode::MIX_MODE:
{
// no need unregister callback in V2.
// We have transformed all pages from V2 to V3 in `restore`, so
// only need to unregister callbacks for V3.
data_storage_v3->unregisterExternalPagesCallbacks(ns_id);
break;
}
Expand Down
23 changes: 1 addition & 22 deletions dbms/src/Storages/Page/V3/PageDirectory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1170,8 +1170,7 @@ void PageDirectory::apply(PageEntriesEdit && edit, const WriteLimiterPtr & write
{
// put the new created holder into `external_ids`
*holder = r.page_id;
std::lock_guard guard(external_ids_mutex);
external_ids.emplace_back(std::weak_ptr<PageIdV3Internal>(holder));
external_ids_by_ns.addExternalId(holder);
}
break;
}
Expand Down Expand Up @@ -1235,26 +1234,6 @@ void PageDirectory::gcApply(PageEntriesEdit && migrated_edit, const WriteLimiter
LOG_FMT_INFO(log, "GC apply done. [edit size={}]", migrated_edit.size());
}

std::set<PageId> PageDirectory::getAliveExternalIds(NamespaceId ns_id) const
{
std::set<PageId> valid_external_ids;
{
std::lock_guard guard(external_ids_mutex);
for (auto iter = external_ids.begin(); iter != external_ids.end(); /*empty*/)
{
if (auto holder = iter->lock(); holder == nullptr)
iter = external_ids.erase(iter);
else
{
if (holder->high == ns_id)
valid_external_ids.emplace(holder->low);
++iter;
}
}
}
return valid_external_ids;
}

std::pair<std::map<BlobFileId, PageIdAndVersionedEntries>, PageSize>
PageDirectory::getEntriesByBlobIds(const std::vector<BlobFileId> & blob_ids) const
{
Expand Down
20 changes: 17 additions & 3 deletions dbms/src/Storages/Page/V3/PageDirectory.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
#include <Encryption/FileProvider.h>
#include <Poco/Ext/ThreadNumber.h>
#include <Storages/Page/Page.h>
#include <Storages/Page/PageDefines.h>
#include <Storages/Page/Snapshot.h>
#include <Storages/Page/V3/BlobStore.h>
#include <Storages/Page/V3/MapUtils.h>
#include <Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h>
#include <Storages/Page/V3/PageEntriesEdit.h>
#include <Storages/Page/V3/PageEntry.h>
#include <Storages/Page/V3/WALStore.h>
Expand Down Expand Up @@ -348,7 +350,20 @@ class PageDirectory
// When dump snapshot, we need to keep the last valid entry. Check out `tryDumpSnapshot` for the reason.
PageEntriesV3 gcInMemEntries(bool return_removed_entries = true, bool keep_last_valid_var_entry = false);

std::set<PageId> getAliveExternalIds(NamespaceId ns_id) const;
// Get the external id that is not deleted or being ref by another id by
// `ns_id`.
std::set<PageId> getAliveExternalIds(NamespaceId ns_id) const
{
return external_ids_by_ns.getAliveIds(ns_id);
}

// After table dropped, the `getAliveIds` with specified
// `ns_id` will not be cleaned. We need this method to
// cleanup all external id ptrs.
void unregisterNamespace(NamespaceId ns_id)
{
external_ids_by_ns.unregisterNamespace(ns_id);
}

PageEntriesEdit dumpSnapshotToEdit(PageDirectorySnapshotPtr snap = nullptr);

Expand Down Expand Up @@ -391,8 +406,7 @@ class PageDirectory
mutable std::mutex snapshots_mutex;
mutable std::list<std::weak_ptr<PageDirectorySnapshot>> snapshots;

mutable std::mutex external_ids_mutex;
mutable std::list<std::weak_ptr<PageIdV3Internal>> external_ids;
mutable ExternalIdsByNamespace external_ids_by_ns;

WALStorePtr wal;
const UInt64 max_persisted_log_files;
Expand Down
78 changes: 78 additions & 0 deletions dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2022 PingCAP, Ltd.
//
// 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.

#include <Storages/Page/PageDefines.h>
#include <Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h>

#include <mutex>

namespace DB::PS::V3
{
void ExternalIdsByNamespace::addExternalIdUnlock(const std::shared_ptr<PageIdV3Internal> & external_id)
{
const NamespaceId & ns_id = external_id->high;
// create a new ExternalIds if the ns_id is not exists, else return
// the existing one.
auto [ns_iter, new_inserted] = ids_by_ns.try_emplace(ns_id, ExternalIds{});
ns_iter->second.emplace_back(std::weak_ptr<PageIdV3Internal>(external_id));
}

void ExternalIdsByNamespace::addExternalId(const std::shared_ptr<PageIdV3Internal> & external_id)
{
std::unique_lock map_guard(mu);
addExternalIdUnlock(external_id);
}

std::set<PageId> ExternalIdsByNamespace::getAliveIds(NamespaceId ns_id) const
{
// Now we assume a lock among all NamespaceIds is good enough.
std::unique_lock map_guard(mu);

std::set<PageId> valid_external_ids;
auto ns_iter = ids_by_ns.find(ns_id);
if (ns_iter == ids_by_ns.end())
return valid_external_ids;

// Only scan the given `ns_id`
auto & external_ids = ns_iter->second;
for (auto iter = external_ids.begin(); iter != external_ids.end(); /*empty*/)
{
if (auto holder = iter->lock(); holder == nullptr)
{
// the external id has been removed from `PageDirectory`,
// cleanup the invalid weak_ptr
iter = external_ids.erase(iter);
continue;
}
else
{
valid_external_ids.emplace(holder->low);
++iter;
}
}
// No valid external pages in this `ns_id`
if (valid_external_ids.empty())
{
valid_external_ids.erase(ns_id);
}
return valid_external_ids;
}

void ExternalIdsByNamespace::unregisterNamespace(NamespaceId ns_id)
{
std::unique_lock map_guard(mu);
// free all weak_ptrs of this namespace
ids_by_ns.erase(ns_id);
}
} // namespace DB::PS::V3
56 changes: 56 additions & 0 deletions dbms/src/Storages/Page/V3/PageDirectory/ExternalIdsByNamespace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2022 PingCAP, Ltd.
//
// 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.

#pragma once

#include <Common/nocopyable.h>
#include <Storages/Page/PageDefines.h>

#include <unordered_map>

namespace DB::PS::V3
{

// A thread-safe class to manage external ids.
// Manage all external ids by NamespaceId.
class ExternalIdsByNamespace
{
public:
ExternalIdsByNamespace() = default;

// Add a external ids
void addExternalId(const std::shared_ptr<PageIdV3Internal> & external_id);
// non thread-safe version, only for restore
void addExternalIdUnlock(const std::shared_ptr<PageIdV3Internal> & external_id);

// Get all alive external ids of given `ns_id`
// Will also cleanup the invalid external ids.
std::set<PageId> getAliveIds(NamespaceId ns_id) const;

// After table dropped, the `getAliveIds` with specified
// `ns_id` will not be cleaned. We need this method to
// cleanup all external id ptrs.
void unregisterNamespace(NamespaceId ns_id);

DISALLOW_COPY_AND_MOVE(ExternalIdsByNamespace);

private:
mutable std::mutex mu;
// Only store weak_ptrs. The weak_ptrs will be invalid after the external id
// in PageDirectory get removed.
using ExternalIds = std::list<std::weak_ptr<PageIdV3Internal>>;
using NamespaceMap = std::unordered_map<NamespaceId, ExternalIds>;
mutable NamespaceMap ids_by_ns;
};
} // namespace DB::PS::V3
4 changes: 2 additions & 2 deletions dbms/src/Storages/Page/V3/PageDirectoryFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ void PageDirectoryFactory::applyRecord(
if (holder)
{
*holder = r.page_id;
dir->external_ids.emplace_back(std::weak_ptr<PageIdV3Internal>(holder));
dir->external_ids_by_ns.addExternalIdUnlock(holder);
}
break;
}
Expand All @@ -162,7 +162,7 @@ void PageDirectoryFactory::applyRecord(
if (holder)
{
*holder = r.page_id;
dir->external_ids.emplace_back(std::weak_ptr<PageIdV3Internal>(holder));
dir->external_ids_by_ns.addExternalIdUnlock(holder);
}
break;
}
Expand Down
Loading