blob: 6cc94b09cd65e5bcffeeced6f5ff452e4ccc4084 [file]
/*
* 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.
*/
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include "paimon/catalog/identifier.h"
#include "paimon/core/catalog/commit_lock.h"
#include "paimon/logging.h"
#include "paimon/result.h"
#include "paimon/status.h"
namespace paimon {
class RestApi;
/// A renewable REST commit lease bound to a table or branch and to one writer, mirroring Java
/// `RESTCatalogLock`.
///
/// `Acquire()` asks the server for a lease and polls while another writer holds one, until the
/// acquisition timeout elapses. The timeout is checked after each response, so it does not
/// interrupt a request in flight. The scope it returns renews the lease in the background every
/// third of the lease duration, on a thread of its own; when that thread cannot be started,
/// `Acquire()` fails and may be called again. The scope tracks the deadline on a monotonic clock
/// from when each grant was requested, so `EnsureValid()` fails once a renewal is refused or
/// fails, or the deadline passes even if no renewal ran.
///
/// There is no unlock request. The server ends a lease when a snapshot is published under it;
/// ending a scope only stops renewing, so a lease that published nothing stays held until it
/// expires. Ending a scope does not wait for a renewal in flight: its request is cancelled, and
/// its thread exits on its own once the call returns.
class RestCommitLock : public CommitLock {
public:
/// Monotonic time in milliseconds.
using Clock = std::function<int64_t()>;
/// Runs a task on a new detached thread, failing instead of throwing when none can be started.
using ThreadStarter = std::function<Status(std::function<void()> task)>;
/// Milliseconds of `std::chrono::steady_clock`.
static int64_t SteadyClockMillis();
/// Runs `task` on a detached `std::thread`.
static Status StartDetachedThread(std::function<void()> task);
/// Creates the lock without sending any request.
///
/// @param api Client of the REST server holding the leases.
/// @param identifier Table or branch to lock, as the server addresses it.
/// @param table_uuid Catalog UUID of the table or branch, so a recreated table cannot inherit
/// a lease; required.
/// @param commit_user Exact commit user of the snapshots published under the lease; required.
/// @param acquire_timeout_millis How long `Acquire()` waits while another writer holds the
/// lease.
/// @param clock Monotonic clock, replaceable for tests.
/// @param start_thread Starts the thread renewing each lease, replaceable for tests.
static Result<std::unique_ptr<RestCommitLock>> Create(
const std::shared_ptr<RestApi>& api, const Identifier& identifier,
const std::optional<std::string>& table_uuid, const std::string& commit_user,
int64_t acquire_timeout_millis, Clock clock = &RestCommitLock::SteadyClockMillis,
ThreadStarter start_thread = &RestCommitLock::StartDetachedThread);
Result<std::unique_ptr<CommitLockScope>> Acquire() override;
private:
RestCommitLock(const std::shared_ptr<RestApi>& api, const Identifier& identifier,
const std::string& table_uuid, const std::string& commit_user,
int64_t acquire_timeout_millis, Clock clock, ThreadStarter start_thread);
std::shared_ptr<RestApi> api_;
Identifier identifier_;
std::string table_uuid_;
std::string commit_user_;
int64_t acquire_timeout_millis_;
Clock clock_;
ThreadStarter start_thread_;
std::shared_ptr<Logger> logger_;
};
} // namespace paimon