blob: 6aa90e8b207b3267c7785ca0b335a10378e5dd0a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_STORAGE_BLOBFS_ALLOCATOR_EXTENT_RESERVER_H_
#define SRC_STORAGE_BLOBFS_ALLOCATOR_EXTENT_RESERVER_H_
#include <stdbool.h>
#include <stdint.h>
#include <zircon/types.h>
#include <mutex>
#include <bitmap/rle-bitmap.h>
#include "src/storage/blobfs/format.h"
namespace blobfs {
class ReservedExtent;
// Allows extents to be reserved and unreserved. The purpose of reservation is to allow allocation
// of extents to occur without yet allocating structures which could be written out to durable
// storage.
//
// These extents may be observed by derived classes of ExtentReserver
class ExtentReserver {
public:
ReservedExtent Reserve(const Extent& extent);
// Unreserves space for blocks in memory. Does not update disk.
void Unreserve(const Extent& extent);
// Returns the total number of reserved blocks.
uint64_t ReservedBlockCount() const;
protected:
std::mutex& mutex() const __TA_RETURN_CAPABILITY(mutex_) { return mutex_; }
// Reserves space for blocks in memory. Does not update disk.
//
// |extent.Length()| must be > 0.
ReservedExtent ReserveLocked(const Extent& extent) __TA_REQUIRES(mutex());
// Returns an iterator to the underlying reserved blocks.
//
// This iterator becomes invalid on the next call to either |ReserveExtent| or
// |UnreserveExtent|.
bitmap::RleBitmap::const_iterator ReservedBlocksCbegin() const __TA_REQUIRES(mutex()) {
return reserved_blocks_.cbegin();
}
bitmap::RleBitmap::const_iterator ReservedBlocksCend() const __TA_REQUIRES(mutex()) {
return reserved_blocks_.end();
}
private:
mutable std::mutex mutex_;
bitmap::RleBitmap reserved_blocks_ __TA_GUARDED(mutex_);
};
// Wraps an extent reservation in RAII to hold the reservation active, and release it when it goes
// out of scope.
class ReservedExtent {
public:
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ReservedExtent);
ReservedExtent(ReservedExtent&& o);
ReservedExtent& operator=(ReservedExtent&& o);
~ReservedExtent();
// Access the underlying extent which has been reserved.
//
// Unsafe to call if this extent has not actually been reserved.
const Extent& extent() const;
// Split a reserved extent from [start, start + length) such that:
// This retains [start, start + block_split),
// and returns [start + block_split, start + length)
//
// This function requires that |block_split| < |extent.block_count|.
ReservedExtent SplitAt(BlockCountType block_split);
// Releases the underlying reservation, unreserving the extent and preventing continued access
// to |extent()|.
void Reset();
private:
friend ExtentReserver;
// Creates a reserved extent.
//
// |extent.Length()| must be > 0.
// The caller is responsible for actually reserving an extent.
ReservedExtent(ExtentReserver* reserver, Extent extent) : reserver_(reserver), extent_(extent) {}
// Update internal state such that future calls to |Reserved| return false.
void Release();
// Identify if the underlying extent is reserved, and able to be accessed.
bool Reserved() const;
ExtentReserver* reserver_;
Extent extent_;
};
inline ReservedExtent ExtentReserver::Reserve(const Extent& extent) {
std::scoped_lock lock(mutex());
return ReserveLocked(extent);
}
} // namespace blobfs
#endif // SRC_STORAGE_BLOBFS_ALLOCATOR_EXTENT_RESERVER_H_