//------------------------------------------------------------------------------
//! @file QdbMaster.hh
//! @author Elvin Sindrilaru - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2018 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
//------------------------------------------------------------------------------
//! @brief Master interface for Qdb implementation
//------------------------------------------------------------------------------
#pragma once
#include "mgm/IMaster.hh"
#include "common/AssistedThread.hh"
#include "namespace/ns_quarkdb/QdbContactDetails.hh"
//! Forward declaration
namespace qclient
{
class QClient;
}
EOSMGMNAMESPACE_BEGIN
//------------------------------------------------------------------------------
//! Class IMaster
//------------------------------------------------------------------------------
class QdbMaster: public IMaster
{
public:
static std::string sLeaseKey;
//----------------------------------------------------------------------------
//! Constructor
//!
//! @param qdb_info contact details for QDB cluster
//! @param host_port hostname:port of the current mgm
//----------------------------------------------------------------------------
QdbMaster(const eos::QdbContactDetails& qdb_info,
const std::string& host_port);
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
~QdbMaster();
//----------------------------------------------------------------------------
//! Copy constructor
//----------------------------------------------------------------------------
QdbMaster(const QdbMaster& other) = delete;
//----------------------------------------------------------------------------
//! Copy assignment operator
//----------------------------------------------------------------------------
QdbMaster& operator=(const QdbMaster&) = delete;
//----------------------------------------------------------------------------
//! Init method to determine the current master/slave state
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool Init() override;
//----------------------------------------------------------------------------
//! Boot namespace
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool BootNamespace() override;
//----------------------------------------------------------------------------
//! Apply configuration setting
//!
//! @param stdOut output string
//! @param stdErr output error string
//! @param transition_type transition type
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool ApplyMasterConfig(std::string& stdOut, std::string& stdErr,
Transition::Type transitiontype) override;
//----------------------------------------------------------------------------
//! Check if we are the master host
//!
//! @return true if master, otherwise false
//----------------------------------------------------------------------------
bool IsMaster() override
{
return mIsMaster;
}
//----------------------------------------------------------------------------
//! Check if remove master is OK
//!
//! @return true if OK, otherwise false
//----------------------------------------------------------------------------
bool IsRemoteMasterOk() const override;
//----------------------------------------------------------------------------
//! Get current master hostname
//----------------------------------------------------------------------------
const std::string GetMasterId() const override
{
std::unique_lock lock(mMutexId);
return mMasterIdentity;
}
//----------------------------------------------------------------------------
//! Set the new master hostname
//!
//! @param hostname new master hostname
//! @param port new master port, default 1094
//! @param err_msg error message
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool SetMasterId(const std::string& hostname, int port,
std::string& err_msg) override;
//----------------------------------------------------------------------------
//! Return a delay time for balancing & draining since after a transition
//! we don't know the maps of already scheduled ID's and we have to make
//! sure not to reissue a transfer too early!
//----------------------------------------------------------------------------
size_t GetServiceDelay() override
{
// @todo (esindril): this needs to be properly implemented
return 0;
}
//----------------------------------------------------------------------------
//! Get master log
//----------------------------------------------------------------------------
void GetLog(std::string& stdOut) override
{
stdOut = mLog;
}
//----------------------------------------------------------------------------
//! Show the current master/slave run configuration (used by ns stat)
//!
//! @return string describing the status
//----------------------------------------------------------------------------
std::string PrintOut() override;
private:
//----------------------------------------------------------------------------
//! Update the current master id
//!
//! @param master_id current master id
//----------------------------------------------------------------------------
inline void UpdateMasterId(const std::string& master_id)
{
std::unique_lock lock(mMutexId);
mMasterIdentity = master_id;
}
//----------------------------------------------------------------------------
//! Method supervising the master/slave status
//!
//! @param assistant thread executing the method
//----------------------------------------------------------------------------
void Supervisor(ThreadAssistant& assistant) noexcept;
//----------------------------------------------------------------------------
//! Try to acquire lease
//!
//! @param validity_msec validity in milliseconds of the lease
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool AcquireLease(uint64_t validity_msec = 0ull);
//----------------------------------------------------------------------------
//! Try to acquire lease with delay. If the mAcquireDelay timestamp is set
//! then we skip trying to acquire the lease until the delay has expired.
//!
//! @return true if successful, otherwise false
//----------------------------------------------------------------------------
bool AcquireLeaseWithDelay();
//----------------------------------------------------------------------------
//! Release lease
//----------------------------------------------------------------------------
void ReleaseLease();
//----------------------------------------------------------------------------
//! Get the identity of the current lease holder
//!
//! @return identity string or empty string if noone holds the leas
//----------------------------------------------------------------------------
std::string GetLeaseHolder();
//----------------------------------------------------------------------------
//! Slave to master transition
//----------------------------------------------------------------------------
void SlaveToMaster();
//----------------------------------------------------------------------------
//! Master to slave transition
//----------------------------------------------------------------------------
void MasterToSlave();
//----------------------------------------------------------------------------
//! Disable namespace caching
//----------------------------------------------------------------------------
void DisableNsCaching();
//----------------------------------------------------------------------------
//! Enable namespace caching with default values
//----------------------------------------------------------------------------
void EnableNsCaching();
//----------------------------------------------------------------------------
//! Configure QDB lease timeouts/validity
//!
//! @param master_init_lease lease timeout used during a transition
//----------------------------------------------------------------------------
void ConfigureTimeouts(uint64_t& master_init_lease);
std::atomic mOneOff; ///< Flag to mark that supervisor ran once
std::string mIdentity; ///< MGM identity hostname:port
mutable std::mutex mMutexId; ///< Mutex for the master identity
std::string mMasterIdentity; ///< Current master host
std::atomic mIsMaster; ///< Mark if current instance is master
std::atomic mConfigLoaded; ///< Mark if configuration is loaded
///! Timepoint until when to delay the acquiring of the lease - so that we
///! give the chance to other MGMs to become masters
std::atomic mAcquireDelay;
AssistedThread mThread; ///< Supervisor thread updating master/slave state
std::unique_ptr
mQcl; ///< qclient for talking to the QDB cluster
//! Time for which a lease is aquired
std::chrono::milliseconds mLeaseValidity {10000};
};
EOSMGMNAMESPACE_END