sapling/eden/fs/testharness/StoredObject.h
Adam Simpkins 251da81f36 update all copyright statements to "2016-present"
Summary:
Update copyright statements to "2016-present".  This makes our updated lint
rules happy and complies with the recommended license header statement.

Reviewed By: wez, bolinfest

Differential Revision: D4433594

fbshipit-source-id: e9ecb1c1fc66e4ec49c1f046c6a98d425b13bc27
2017-01-20 22:03:02 -08:00

135 lines
3.3 KiB
C++

/*
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
#pragma once
#include <folly/futures/Future.h>
#include <memory>
namespace facebook {
namespace eden {
class Blob;
class Hash;
class Tree;
template <typename T>
class StoredObject;
using StoredBlob = StoredObject<Blob>;
using StoredHash = StoredObject<Hash>;
using StoredTree = StoredObject<Tree>;
/**
* A helper class for TestBackingStore.
*
* This contains a Tree, Blob, or Hash, but allows tracking when it should
* actually be marked ready to return to callers. The getFuture() API can be
* used to get a folly::Future that will be fulfilled when the object is marked
* ready.
*
* This allows test code to test the code behavior when backing store objects
* are not immediately ready.
*/
template <typename T>
class StoredObject {
public:
explicit StoredObject(const T& t) : object_(t) {}
/**
* Get the underlying object.
*/
const T& get() const {
return object_;
}
/**
* Get a Future for this object.
*
* If the StoredObject is ready, the returned future will already have a
* value available. Otherwise the future will become ready when trigger() or
* setReady() is called on this StoredObject.
*/
folly::Future<std::unique_ptr<T>> getFuture() {
auto data = data_.wlock();
if (data->ready) {
return folly::makeFuture(std::make_unique<T>(object_));
}
data->promises.emplace_back();
return data->promises.back().getFuture();
}
/**
* Mark the object as ready.
*
* This will fulfill any pending Futures waiting on this object.
* New Futures returned by getFuture() after setReady() is called will be
* immediately ready.
*/
void setReady() {
std::vector<folly::Promise<std::unique_ptr<T>>> promises;
{
auto data = data_.wlock();
data->ready = true;
data->promises.swap(promises);
}
triggerImpl(promises);
}
/**
* Fulfill all pending Futures waiting on this object.
*
* This fulfills currently pending Futures, but subsequent calls to
* getFuture() will still return Futures that are not ready yet.
*/
void trigger() {
std::vector<folly::Promise<std::unique_ptr<T>>> promises;
{
auto data = data_.wlock();
data->promises.swap(promises);
}
triggerImpl(promises);
}
/**
* Fail all pending Futures waiting on this object.
*
* This fulfills currently pending Futures with the specified exception.
*/
template <class E>
void triggerError(const E& e) {
std::vector<folly::Promise<std::unique_ptr<T>>> promises;
{
auto data = data_.wlock();
data->promises.swap(promises);
}
for (auto& p : promises) {
p.setException(e);
}
}
private:
struct Data {
bool ready{false};
std::vector<folly::Promise<std::unique_ptr<T>>> promises;
};
void triggerImpl(std::vector<folly::Promise<std::unique_ptr<T>>>& promises) {
for (auto& p : promises) {
p.setValue(std::make_unique<T>(object_));
}
}
const T object_;
folly::Synchronized<Data> data_;
};
}
}