/* * Copyright (c) 2016, 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 #include namespace facebook { namespace eden { class Blob; class Hash; class Tree; template class StoredObject; using StoredBlob = StoredObject; using StoredHash = StoredObject; using StoredTree = StoredObject; /** * 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 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> getFuture() { auto data = data_.wlock(); if (data->ready) { return folly::makeFuture(std::make_unique(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>> 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>> 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 void triggerError(const E& e) { std::vector>> promises; { auto data = data_.wlock(); data->promises.swap(promises); } for (auto& p : promises) { p.setException(e); } } private: struct Data { bool ready{false}; std::vector>> promises; }; void triggerImpl(std::vector>>& promises) { for (auto& p : promises) { p.setValue(std::make_unique(object_)); } } const T object_; folly::Synchronized data_; }; } }