Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'include/afio/v2.0/algorithm/shared_fs_mutex/base.hpp')
-rw-r--r--include/afio/v2.0/algorithm/shared_fs_mutex/base.hpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/include/afio/v2.0/algorithm/shared_fs_mutex/base.hpp b/include/afio/v2.0/algorithm/shared_fs_mutex/base.hpp
new file mode 100644
index 00000000..0f652226
--- /dev/null
+++ b/include/afio/v2.0/algorithm/shared_fs_mutex/base.hpp
@@ -0,0 +1,223 @@
+/* Protect a shared filing system resource from concurrent modification
+(C) 2016-2017 Niall Douglas <http://www.nedproductions.biz/> (12 commits)
+File Created: March 2016
+
+
+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 in the accompanying file
+Licence.txt or 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.
+
+
+Distributed under the Boost Software License, Version 1.0.
+ (See accompanying file Licence.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+*/
+
+#ifndef BOOST_AFIO_SHARED_FS_MUTEX_BASE_HPP
+#define BOOST_AFIO_SHARED_FS_MUTEX_BASE_HPP
+
+#include "../../handle.hpp"
+
+#include "../../hash.hpp"
+
+//! \file base.hpp Provides algorithm::shared_fs_mutex::shared_fs_mutex
+
+BOOST_AFIO_V2_NAMESPACE_BEGIN
+
+namespace algorithm
+{
+ //! Algorithms for protecting a shared filing system resource from racy modification
+ namespace shared_fs_mutex
+ {
+ //! Unsigned 64 bit integer
+ using uint64 = unsigned long long;
+ //! Unsigned 128 bit integer
+ using uint128 = boost_lite::integers128::uint128;
+
+ /*! \class shared_fs_mutex
+ \brief Abstract base class for an object which protects shared filing system resources
+
+ The implementations of this abstract base class have various pros and cons with varying
+ time and space complexities. See their documentation for details. All share the concept
+ of "entity_type" as being a unique 63 bit identifier of a lockable entity. Various
+ conversion functions are provided below for converting strings, buffers etc. into an
+ entity_type.
+ */
+ class shared_fs_mutex
+ {
+ public:
+ //! The type of an entity id
+ struct entity_type
+ {
+ //! The type backing the value
+ using value_type = handle::extent_type;
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4201) // nameless union used
+#endif
+ union {
+ value_type _init;
+ struct
+ {
+ //! The value of the entity type which can range between 0 and (2^63)-1
+ value_type value : 63;
+ //! True if entity should be locked for exclusive access
+ value_type exclusive : 1;
+ };
+ };
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ //! Default constructor
+ constexpr entity_type() noexcept : _init(0) {}
+ //! Constructor
+#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 7
+ BOOSTLITE_CONSTEXPR
+#endif
+ entity_type(value_type _value, bool _exclusive) noexcept : _init(0)
+ {
+ value = _value;
+ exclusive = _exclusive;
+ }
+ };
+ static_assert(std::is_literal_type<entity_type>::value, "entity_type is not a literal type");
+ static_assert(sizeof(entity_type) == sizeof(entity_type::value_type), "entity_type is bit equal to its underlying type");
+ //! The type of a sequence of entities
+ using entities_type = span<entity_type>;
+
+ protected:
+ constexpr shared_fs_mutex() {}
+
+ public:
+ virtual ~shared_fs_mutex() {}
+
+ //! Generates an entity id from a sequence of bytes
+ entity_type entity_from_buffer(const char *buffer, size_t bytes, bool exclusive = true) noexcept
+ {
+ uint128 hash = boost_lite::algorithm::hash::fast_hash::hash(buffer, bytes);
+ return entity_type(hash.as_longlongs[0] ^ hash.as_longlongs[1], exclusive);
+ }
+ //! Generates an entity id from a string
+ template <typename T> entity_type entity_from_string(const std::basic_string<T> &str, bool exclusive = true) noexcept
+ {
+ uint128 hash = boost_lite::algorithm::hash::fast_hash::hash(str);
+ return entity_type(hash.as_longlongs[0] ^ hash.as_longlongs[1], exclusive);
+ }
+ //! Generates a cryptographically random entity id.
+ entity_type random_entity(bool exclusive = true) noexcept
+ {
+ entity_type::value_type v;
+ utils::random_fill((char *) &v, sizeof(v));
+ return entity_type(v, exclusive);
+ }
+ //! Fills a sequence of entity ids with cryptographic randomness. Much faster than calling random_entity() individually.
+ void fill_random_entities(span<entity_type> seq, bool exclusive = true) noexcept
+ {
+ utils::random_fill((char *) seq.data(), seq.size() * sizeof(entity_type));
+ for(auto &i : seq)
+ i.exclusive = exclusive;
+ }
+
+ //! RAII holder for a lock on a sequence of entities
+ class entities_guard
+ {
+ entity_type _entity;
+
+ public:
+ shared_fs_mutex *parent;
+ entities_type entities;
+ unsigned long long hint;
+ entities_guard() = default;
+ entities_guard(shared_fs_mutex *_parent, entities_type _entities)
+ : parent(_parent)
+ , entities(_entities)
+ , hint(0)
+ {
+ }
+ entities_guard(shared_fs_mutex *_parent, entity_type entity)
+ : _entity(entity)
+ , parent(_parent)
+ , entities(&_entity, 1)
+ , hint(0)
+ {
+ }
+ entities_guard(const entities_guard &) = delete;
+ entities_guard &operator=(const entities_guard &) = delete;
+ entities_guard(entities_guard &&o) noexcept : _entity(std::move(o._entity)), parent(o.parent), entities(std::move(o.entities)), hint(o.hint)
+ {
+ if(entities.data() == &o._entity)
+ entities = entities_type(&_entity, 1);
+ o.release();
+ }
+ entities_guard &operator=(entities_guard &&o) noexcept
+ {
+ this->~entities_guard();
+ new(this) entities_guard(std::move(o));
+ return *this;
+ }
+ ~entities_guard()
+ {
+ if(parent)
+ unlock();
+ }
+ //! True if extent guard is valid
+ explicit operator bool() const noexcept { return parent != nullptr; }
+ //! True if extent guard is invalid
+ bool operator!() const noexcept { return parent == nullptr; }
+ //! Unlocks the locked entities immediately
+ void unlock() noexcept
+ {
+ if(parent)
+ {
+ parent->unlock(entities, hint);
+ release();
+ }
+ }
+ //! Detach this RAII unlocker from the locked state
+ void release() noexcept
+ {
+ parent = nullptr;
+ entities = entities_type();
+ }
+ };
+
+ virtual result<void> _lock(entities_guard &out, deadline d, bool spin_not_sleep) noexcept = 0;
+
+ //! Lock all of a sequence of entities for exclusive or shared access
+ result<entities_guard> lock(entities_type entities, deadline d = deadline(), bool spin_not_sleep = false) noexcept
+ {
+ entities_guard ret(this, std::move(entities));
+ BOOST_OUTCOME_TRYV(_lock(ret, std::move(d), spin_not_sleep));
+ return std::move(ret);
+ }
+ //! Lock a single entity for exclusive or shared access
+ result<entities_guard> lock(entity_type entity, deadline d = deadline(), bool spin_not_sleep = false) noexcept
+ {
+ entities_guard ret(this, entity);
+ BOOST_OUTCOME_TRYV(_lock(ret, std::move(d), spin_not_sleep));
+ return std::move(ret);
+ }
+ //! Try to lock all of a sequence of entities for exclusive or shared access
+ result<entities_guard> try_lock(entities_type entities) noexcept { return lock(std::move(entities), deadline(std::chrono::seconds(0))); }
+ //! Try to lock a single entity for exclusive or shared access
+ result<entities_guard> try_lock(entity_type entity) noexcept { return lock(std::move(entity), deadline(std::chrono::seconds(0))); }
+ //! Unlock a previously locked sequence of entities
+ virtual void unlock(entities_type entities, unsigned long long hint = 0) noexcept = 0;
+ };
+
+ } // namespace
+} // namespace
+
+BOOST_AFIO_V2_NAMESPACE_END
+
+
+#endif