mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-06-07 19:22:02 +03:00
272 lines
6.9 KiB
C++
272 lines
6.9 KiB
C++
/* Copyright (C) 2014 InfiniDB, Inc.
|
|
Copyright (C) 2016-2022 MariaDB Corporation
|
|
|
|
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; version 2 of
|
|
the License.
|
|
|
|
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, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
/******************************************************************************
|
|
* $Id$
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/** @file
|
|
* class RWLock interface
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <array>
|
|
|
|
#include <unistd.h>
|
|
#include <stdexcept>
|
|
|
|
#include <boost/interprocess/shared_memory_object.hpp>
|
|
#include <boost/interprocess/mapped_region.hpp>
|
|
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
|
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
|
|
#define EXPORT
|
|
|
|
namespace rwlock
|
|
{
|
|
const std::array<const std::string, 7> RWLockNames = {{
|
|
"all",
|
|
"VSS",
|
|
"ExtentMap",
|
|
"FreeList",
|
|
"VBBM",
|
|
"CopyLocks",
|
|
"ExtentMapIndex",
|
|
}};
|
|
|
|
/// the layout of the shmseg
|
|
struct State
|
|
{
|
|
int writerswaiting;
|
|
int writing;
|
|
int readerswaiting;
|
|
int reading;
|
|
boost::interprocess::interprocess_semaphore sems[3];
|
|
};
|
|
|
|
/* the lock state without the semaphores, passed out by timed_write_lock() for
|
|
class RWLockMonitor
|
|
*/
|
|
struct LockState
|
|
{
|
|
int writerswaiting;
|
|
int writing;
|
|
int readerswaiting;
|
|
int reading;
|
|
bool mutexLocked;
|
|
};
|
|
|
|
class RWLockShmImpl
|
|
{
|
|
public:
|
|
~RWLockShmImpl() = delete;
|
|
|
|
static RWLockShmImpl* makeRWLockShmImpl(int key, bool* excl = nullptr);
|
|
|
|
boost::interprocess::shared_memory_object fStateShm;
|
|
boost::interprocess::mapped_region fRegion;
|
|
State* fState;
|
|
|
|
std::string keyString()
|
|
{
|
|
return fKeyString;
|
|
}
|
|
|
|
private:
|
|
explicit RWLockShmImpl(int key, bool excl = false);
|
|
RWLockShmImpl(const RWLockShmImpl& rhs);
|
|
RWLockShmImpl& operator=(const RWLockShmImpl& rhs);
|
|
std::string fKeyString;
|
|
};
|
|
|
|
class not_excl : public std::exception
|
|
{
|
|
public:
|
|
const char* what() const noexcept override
|
|
{
|
|
return "not_excl";
|
|
}
|
|
};
|
|
|
|
class wouldblock : public std::exception
|
|
{
|
|
public:
|
|
const char* what() const noexcept override
|
|
{
|
|
return "wouldblock";
|
|
}
|
|
};
|
|
|
|
/** @brief Implements RW locks for use across threads & processes
|
|
*
|
|
* Implements RW locks for use across threads & processes. Every
|
|
* instance that shares a lock must be instantiated using the same
|
|
* key. There is 'no limit' on the number of RW locks that can
|
|
* exist on the system at any one time.
|
|
*
|
|
* Summary of operation:
|
|
* - readers can work concurrently
|
|
* - writers get exclusive access
|
|
* - writers have priority
|
|
* - all state persists across all invocations sharing a given key
|
|
*
|
|
* Note: because state has to persist, it will have to be cleaned
|
|
* up somewhere else. Crashes while holding a read or write lock will
|
|
* eventually deadlock the set of processes that share the same key obviously.
|
|
*/
|
|
class RWLock
|
|
{
|
|
public:
|
|
// semaphore numbers
|
|
static const int MUTEX = 0;
|
|
static const int READERS = 1;
|
|
static const int WRITERS = 2;
|
|
|
|
/** @brief Keyed constructor.
|
|
*
|
|
* Instantiate an RWLock with the given key. All instances that
|
|
* share a key share the same lock.
|
|
*
|
|
* @param key The key
|
|
* @param excl If true and this is the first instance with the
|
|
* supplied key, it will return holding the write lock. If true and
|
|
* this is not the first instance, it will throw not_excl. The intent
|
|
* is similar to the IPC_EXCL flag in the sem/shm implementations.
|
|
*/
|
|
EXPORT explicit RWLock(int key, bool* excl = nullptr);
|
|
|
|
EXPORT ~RWLock();
|
|
|
|
/** @brief Grab a read lock
|
|
*
|
|
* Grab a read lock. This will block iff writers are waiting or
|
|
* a writer is active. The version with priority ignores any
|
|
* waiting threads and grabs the lock.
|
|
*
|
|
* @param block (For testing only) If false, will throw
|
|
* wouldblock instead of blocking
|
|
*/
|
|
EXPORT void read_lock(bool block = true);
|
|
|
|
EXPORT void read_lock_priority(bool block = true);
|
|
|
|
/** @brief Release a read lock.
|
|
*
|
|
* Release a read lock.
|
|
*/
|
|
EXPORT void read_unlock();
|
|
|
|
/** @brief Grab a write lock
|
|
*
|
|
* Grab a write lock. This will block while another writer or reader is
|
|
* active and will have exclusive access on waking.
|
|
*
|
|
* @param block (For testing only) If false, will throw
|
|
* wouldblock instead of blocking
|
|
*/
|
|
EXPORT void write_lock(bool block = true);
|
|
|
|
/** @brief A timed write lock.
|
|
*
|
|
* Queues up for the write lock for a specified amount of time. Returns
|
|
* true if it got the lock, return false if it timed out first.
|
|
* If the timeout happens, it will also return the lock state if passed
|
|
* a non-NULL LockState struct. This is a specialization for supporting
|
|
* the RWLockMonitor class.
|
|
*/
|
|
EXPORT bool timed_write_lock(const struct timespec& ts, struct LockState* state = nullptr);
|
|
|
|
/** @brief Release a write lock.
|
|
*
|
|
* Release a write lock.
|
|
*/
|
|
EXPORT void write_unlock();
|
|
|
|
/* note: these haven't been proven yet */
|
|
|
|
/** @brief Upgrade a read lock to a write lock
|
|
*
|
|
* Upgrade a read lock to a write lock. It may have to block
|
|
* if there are other readers currently reading. No guarantees of atomicity.
|
|
*/
|
|
EXPORT void upgrade_to_write();
|
|
|
|
/** @brief Downgrade a write lock to a read lock
|
|
*
|
|
* Downgrade a write lock to a read lock. The conversion happens
|
|
* atomically.
|
|
*/
|
|
EXPORT void downgrade_to_read();
|
|
|
|
/** @brief Reset the lock's state (Use with caution!)
|
|
*
|
|
* If the lock gets into a bad state in testing or something,
|
|
* this will reset the state.
|
|
* @warning This is safe only if there are no other threads using this
|
|
* lock.
|
|
*/
|
|
EXPORT void reset();
|
|
|
|
/* These are for white box testing only */
|
|
inline void lock()
|
|
{
|
|
down(MUTEX, true);
|
|
}
|
|
inline void unlock()
|
|
{
|
|
up(MUTEX);
|
|
}
|
|
inline int getWriting() const
|
|
{
|
|
return fPImpl->fState->writing;
|
|
}
|
|
inline int getReading() const
|
|
{
|
|
return fPImpl->fState->reading;
|
|
}
|
|
inline int getWritersWaiting() const
|
|
{
|
|
return fPImpl->fState->writerswaiting;
|
|
}
|
|
inline int getReadersWaiting() const
|
|
{
|
|
return fPImpl->fState->readerswaiting;
|
|
}
|
|
LockState getLockState();
|
|
|
|
private:
|
|
RWLock(const RWLock& rwl);
|
|
RWLock& operator=(const RWLock& rwl);
|
|
|
|
inline int getSemval(int) const
|
|
{
|
|
return 0;
|
|
}
|
|
void down(int num, bool block = true);
|
|
bool timed_down(int num, const boost::posix_time::ptime& ts); // to support timed_write_lock()
|
|
void up(int num);
|
|
|
|
RWLockShmImpl* fPImpl;
|
|
};
|
|
|
|
} // namespace rwlock
|
|
|
|
#undef EXPORT
|