// 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_NODE_RESERVER_H_
#define SRC_STORAGE_BLOBFS_ALLOCATOR_NODE_RESERVER_H_

#include <lib/zx/status.h>
#include <stdbool.h>
#include <stdint.h>
#include <zircon/types.h>

#include <bitmap/rle-bitmap.h>

#include "src/storage/blobfs/format.h"

namespace blobfs {

class ReservedNode;

// Interface for reserving and unreserving nodes. The purpose of reservation is to allow allocation
// of nodes to occur without yet allocating structures which could be written out to durable
// storage.
class NodeReserverInterface {
 public:
  // Reserves space for a node in memory. Does not update disk. Returns an error if a node could not
  // be reserved.
  virtual zx::status<ReservedNode> ReserveNode() = 0;

  // Unreserves space for a node in memory. Does not update disk.
  virtual void UnreserveNode(ReservedNode node) = 0;

  // Returns the total number of reserved nodes.
  virtual uint64_t ReservedNodeCount() const = 0;
};

// Wraps a node reservation in RAII to hold the reservation active, and release it when it goes out
// of scope.
// Thread-compatible.
class ReservedNode {
 public:
  DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ReservedNode);

  ReservedNode(NodeReserverInterface* reserver, uint32_t node);
  ReservedNode(ReservedNode&& o);
  ReservedNode& operator=(ReservedNode&& o);

  ~ReservedNode();

  // Access the underlying node index which has been reserved.
  //
  // Unsafe to call if the node has not actually been reserved.
  uint32_t index() const;

  // Update internal state such that future calls to |Reserved| return false.
  void Release();

 private:
  // Releases the underlying node, unreserving it and preventing continued access to |index()|.
  void Reset();

  // Identify if the underlying node is reserved, and able to be accessed.
  bool Reserved() const;

  NodeReserverInterface* reserver_;
  uint32_t node_;
};

}  // namespace blobfs

#endif  // SRC_STORAGE_BLOBFS_ALLOCATOR_NODE_RESERVER_H_
