blob: 6ccb40f1c8a835f47eb6afe6a921840f7ef23be1 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#ifndef KUDU_CONSENSUS_LOG_ANCHOR_REGISTRY_
#define KUDU_CONSENSUS_LOG_ANCHOR_REGISTRY_
#include <cstddef>
#include <cstdint>
#include <map>
#include <string>
#include <gtest/gtest_prod.h>
#include "kudu/gutil/macros.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/util/locks.h"
#include "kudu/util/monotime.h"
#include "kudu/util/status.h"
namespace kudu {
namespace log {
struct LogAnchor;
// This class allows callers to register their interest in (anchor) a particular
// log index. The primary use case for this is to prevent the deletion of segments of
// the WAL that reference as-yet unflushed in-memory operations.
//
// This class is thread-safe.
class LogAnchorRegistry : public RefCountedThreadSafe<LogAnchorRegistry> {
public:
LogAnchorRegistry();
// Register interest for a particular log index.
// log_index: The log index the caller wishes to anchor.
// owner: String to describe who is registering the anchor. Used in assert
// messages for debugging purposes.
// anchor: Pointer to LogAnchor structure that will be populated on registration.
void Register(int64_t log_index, const std::string& owner, LogAnchor* anchor);
// Register interest for a particular log index, or update an anchor if it
// already exists.
Status RegisterOrUpdate(int64_t log_index,
const std::string& owner,
LogAnchor* anchor);
// Release the anchor on a log index.
// Note: anchor must be the original pointer passed to Register().
Status Unregister(LogAnchor* anchor);
// Release the anchor on a log index if it is registered.
// Otherwise, do nothing.
Status UnregisterIfAnchored(LogAnchor* anchor);
// Query the registry to find the earliest anchored log index in the registry.
// Returns Status::NotFound if no anchors are currently active.
Status GetEarliestRegisteredLogIndex(int64_t* log_index);
// Simply returns the number of active anchors for use in debugging / tests.
// This is _not_ a constant-time operation.
size_t GetAnchorCountForTests() const;
// Dumps information about registered anchors to a string.
std::string DumpAnchorInfo() const;
private:
friend class RefCountedThreadSafe<LogAnchorRegistry>;
~LogAnchorRegistry();
typedef std::multimap<int64_t, LogAnchor*> AnchorMultiMap;
// Register a new anchor after taking the lock. See Register().
void RegisterUnlocked(int64_t log_index, const std::string& owner, LogAnchor* anchor);
// Unregister an anchor after taking the lock. See Unregister().
Status UnregisterUnlocked(LogAnchor* anchor);
AnchorMultiMap anchors_;
mutable simple_spinlock lock_;
DISALLOW_COPY_AND_ASSIGN(LogAnchorRegistry);
};
// A simple struct that allows us to keep track of which log segments we want
// to anchor (prevent log GC on).
struct LogAnchor {
public:
LogAnchor();
~LogAnchor();
private:
FRIEND_TEST(LogTestOptionalCompression, TestGCWithLogRunning);
FRIEND_TEST(LogAnchorRegistryTest, TestUpdateRegistration);
friend class LogAnchorRegistry;
// Whether any log index is currently registered with this anchor.
bool is_registered;
// When this anchor was last registered or updated.
MonoTime when_registered;
// The index of the log entry we are anchoring on.
int64_t log_index;
// An arbitrary string containing details of the subsystem holding the
// anchor, and any relevant information about it that should be displayed in
// the log or the web UI.
std::string owner;
DISALLOW_COPY_AND_ASSIGN(LogAnchor);
};
// Helper class that will anchor the minimum log index recorded.
class MinLogIndexAnchorer {
public:
// Construct anchorer for specified registry that will register anchors with
// the specified owner name.
MinLogIndexAnchorer(LogAnchorRegistry* registry, std::string owner);
// The destructor will unregister the anchor if it is registered.
~MinLogIndexAnchorer();
// If op_id is less than the minimum index registered so far, or if no indexes
// are currently registered, anchor on 'log_index'.
void AnchorIfMinimum(int64_t log_index);
// Un-anchors the earliest index (which is the only one tracked).
// If no minimum is known (no anchor registered), returns OK.
Status ReleaseAnchor();
// Returns the first recorded log index, kInvalidOpIdIndex if there's none.
int64_t minimum_log_index() const;
private:
const scoped_refptr<LogAnchorRegistry> registry_;
const std::string owner_;
LogAnchor anchor_;
// The index currently anchored, or kInvalidOpIdIndex if no anchor has yet been registered.
int64_t minimum_log_index_;
mutable simple_spinlock lock_;
DISALLOW_COPY_AND_ASSIGN(MinLogIndexAnchorer);
};
} // namespace log
} // namespace kudu
#endif // KUDU_CONSENSUS_LOG_ANCHOR_REGISTRY_