1. 12 Sep, 2017 1 commit
    • Christopher Dykes's avatar
      Fix CMake build · 14b06383
      Christopher Dykes authored
      Summary: Spookyhash got moved a long time ago, and a duplicate test name was added with the migration of executors from wangle to folly.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5811321
      
      fbshipit-source-id: 789b4d3187a2e1e21c6cf8297f733bb4dffdbd60
      14b06383
  2. 11 Sep, 2017 2 commits
    • Phil Willoughby's avatar
      Dead shift in ConcurrentHashMapSegment · d25d17e7
      Phil Willoughby authored
      Summary: Original problem detected by compiling with `-Werror,-Wunused-value`. On further inspection the only place which uses this detail class ensures that the `max_size` parameter is a power of two already, so we can discard the logic to manipulate `max_size` and put a `CHECK` clause in its place to guard against future changes to the caller that break this assumption.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5799110
      
      fbshipit-source-id: d21ed9ff196d54ef91e38254df8b1b88bbf29275
      d25d17e7
    • Anirudh Ramachandran's avatar
      Move SSL_CTX sessionContext initialization into main SSL_CTX initialization path · 001275d1
      Anirudh Ramachandran authored
      Summary: This field was only previously set if setupSessionCache was called on the wangle::ServerSSLContext
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5776057
      
      fbshipit-source-id: ecdbe83816fee2ecbe7ea1b26a67b682a571309a
      001275d1
  3. 10 Sep, 2017 2 commits
    • Giuseppe Ottaviano's avatar
      Add convenience std::string overload for toLowerAscii · d84e6482
      Giuseppe Ottaviano authored
      Summary:
      `toLowerAscii` is surprisingly hard to use with `std::string` because (until C++17) `data()` returns a `const char*`. In addition, it is not widely known that `s[0]` is legal even if the string is empty. This can lead to a variety of suboptimal code, from explicitly checking emptiness, to casting away the `const` (which causes UB).
      
      Let's just have a simple overload for it.
      
      Reviewed By: pixelb, philippv, yfeldblum
      
      Differential Revision: D5801970
      
      fbshipit-source-id: 407e2e9e66147a0662a5e09c75921255adff0702
      d84e6482
    • Giuseppe Ottaviano's avatar
      Fix typo in async/README.md · cb471a45
      Giuseppe Ottaviano authored
      Reviewed By: yfeldblum
      
      Differential Revision: D5802013
      
      fbshipit-source-id: 472b09da2be7234157a7886018004e2f4ed4f279
      cb471a45
  4. 08 Sep, 2017 3 commits
    • Benjamin Jaeger's avatar
      Optional.h - make == operators constexprs · 4b351b61
      Benjamin Jaeger authored
      Summary: This more closely matches std optional and allows folly Optional to be a drop in replacement.
      
      Reviewed By: aary, yfeldblum
      
      Differential Revision: D5775541
      
      fbshipit-source-id: f754c006429fa3c5a866b6b5ffdfd8883ec2dd4f
      4b351b61
    • Eric Niebler's avatar
      support using co_await with folly::Optional when it is available · d6217b2f
      Eric Niebler authored
      Summary:
      Coroutines can be used to simulate the monadic "do" notion of Haskell. Use coroutines to enable monadic composition with folly::Optional.
      
      ```
      Optional<int> f() {
        return 7;
      }
      Optional<int> g(int) {
        return folly::none;
      }
      
      void MonadicOptional() {
        Optional<int> r = []() -> Optional<int> {
          int x = co_await f();
          assert(x == 7);
          int y = co_await g(x);
          assert(false); // not executed
          co_return y;
        }();
        assert(!r.hasValue());
      }
      ```
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5763371
      
      fbshipit-source-id: 9babc682244f38da7006d0b3a8444fd4efec1747
      d6217b2f
    • Michael Bolin's avatar
      Grammar fix: s/it's/its/ · e74c15ff
      Michael Bolin authored
      Summary:
      I noticed this while reading the docs.
      
      (Note: this ignores all push blocking failures!)
      
      Reviewed By: lbrandy
      
      Differential Revision: D5795548
      
      fbshipit-source-id: 9ec5aa13a8913f217b3118e72714d02dc4a9407f
      e74c15ff
  5. 07 Sep, 2017 1 commit
    • Kenny Yu's avatar
      Fix data race in folly/executors/Codel.cpp exposed by TSAN · 88903796
      Kenny Yu authored
      Summary:
      I found a data race with TSAN while attempting to run a sanitizer version of my service:
      
      ```
      WARNING: ThreadSanitizer: data race (pid=266)
        Read of size 8 at 0x7b58000c0c08 by thread T370:
          @ folly::Codel::overloaded(std::chrono::duration<long, std::ratio<1l, 1000000000l> >) at ./folly/executors/Codel.cpp:44
          @ apache::thrift::concurrency::ThreadManager::ImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::Worker<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::run() at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:119
          @ apache::thrift::concurrency::PthreadThread::threadMain(void*) at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:200
          @ __tsan_thread_start_func at crtstuff.c:?
      
        Previous write of size 8 at 0x7b58000c0c08 by thread T371:
          @ folly::Codel::overloaded(std::chrono::duration<long, std::ratio<1l, 1000000000l> >) at ./folly/executors/Codel.cpp:62
          @ apache::thrift::concurrency::ThreadManager::ImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::Worker<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::run() at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:119
          @ apache::thrift::concurrency::PthreadThread::threadMain(void*) at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:200
          @ __tsan_thread_start_func at crtstuff.c:?
      
        Location is heap block of size 744 at 0x7b58000c0c00 allocated by thread T314:
          @ operator new(unsigned long) at ??:?
          @ PriorityImplT at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:826
          @ void __gnu_cxx::new_allocator<apache::thrift::concurrency::PriorityThreadManager::PriorityImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > > >::construct<apache::thrift::concurrency::PriorityThreadManager::PriorityImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >, std::array<std::pair<std::shared_ptr<apache::thrift::concurrency::ThreadFactory>, unsigned long>, 5ul>&, bool&, unsigned long&>(apache::thrift::concurrency::PriorityThreadManager::PriorityImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >*, std::array<std::pair<std::shared_ptr<apache::thrift::concurrency::ThreadFactory>, unsigned long>, 5ul>&, bool&, unsigned long&)
          @ std::shared_ptr<apache::thrift::concurrency::PriorityThreadManager> apache::thrift::concurrency::PriorityThreadManager::newPriorityThreadManager<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >(std::array<unsigned long, 5ul> const&, bool, unsigned long) at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:1090
          @ std::shared_ptr<apache::thrift::concurrency::PriorityThreadManager> apache::thrift::concurrency::PriorityThreadManager::newPriorityThreadManager<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >(unsigned long, bool, unsigned long) at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:1100
          @ apache::thrift::ThriftServer::serve() at ./thrift/lib/cpp2/server/ThriftServer.cpp:475
          @ apache::thrift::server::TServer::run() at ./thrift/lib/cpp/server/TServer.h:186
          @ apache::thrift::concurrency::PthreadThread::threadMain(void*) at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:200
          @ __tsan_thread_start_func at crtstuff.c:?
      
        Thread T370 (tid=638, running) created by thread T314 at:
          @ pthread_create at ??:?
          @ apache::thrift::concurrency::PthreadThread::start() at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:108
          @ apache::thrift::concurrency::ThreadManager::ImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::addWorker(unsigned long) at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:185
          @ apache::thrift::concurrency::PriorityThreadManager::PriorityImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::start() at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:840
          @ apache::thrift::ThriftServer::setup() at ./thrift/lib/cpp2/server/ThriftServer.cpp:347
          @ apache::thrift::ThriftServer::serve() at ./thrift/lib/cpp2/server/ThriftServer.cpp:475
          @ apache::thrift::server::TServer::run() at ./thrift/lib/cpp/server/TServer.h:186
          @ apache::thrift::concurrency::PthreadThread::threadMain(void*) at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:200
          @ __tsan_thread_start_func at crtstuff.c:?
      
        Thread T371 (tid=639, running) created by thread T314 at:
          @ pthread_create at ??:?
          @ apache::thrift::concurrency::PthreadThread::start() at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:108
          @ apache::thrift::concurrency::ThreadManager::ImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::addWorker(unsigned long) at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:185
          @ apache::thrift::concurrency::PriorityThreadManager::PriorityImplT<folly::LifoSemImpl<std::atomic, folly::Baton<std::atomic, true, true> > >::start() at ./thrift/lib/cpp/concurrency/ThreadManager.tcc:840
          @ apache::thrift::ThriftServer::setup() at ./thrift/lib/cpp2/server/ThriftServer.cpp:347
          @ apache::thrift::ThriftServer::serve() at ./thrift/lib/cpp2/server/ThriftServer.cpp:475
          @ apache::thrift::server::TServer::run() at ./thrift/lib/cpp/server/TServer.h:186
          @ apache::thrift::concurrency::PthreadThread::threadMain(void*) at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:200
          @ __tsan_thread_start_func at crtstuff.c:?
      
        Thread T314 (tid=582, running) created by main thread at:
          @ pthread_create at ??:?
          @ apache::thrift::concurrency::PthreadThread::start() at ./thrift/lib/cpp/concurrency/PosixThreadFactory.cpp:108
          ...
      ```
      
      Looks like there is a data race in how `codelMinDelay_` is used. I couldn't get `std::atomic` to compile with `std::chrono::nanoseconds`,
      so I used `std::atomic<uint64_t>` and converted between `uint64_t` and time types appropriately.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5759588
      
      fbshipit-source-id: 8213f3789808265ddfe5ab122f0f86490d0ea6ea
      88903796
  6. 06 Sep, 2017 1 commit
    • James Sedgwick's avatar
      move wangle/concurrent to folly/executors · af4a3352
      James Sedgwick authored
      Summary:
      For the initial cutover, just pull the copies in folly into the wangle namespace
      The main problem with that approach is that forward declarations of wangle components no longer work, so I fixed those manually
      
      ALSO, IMPORTANT: This is a great, once in a lifetime opportunity to rename/restructure these components. I have a few ideas that I'll noodle and share eventually, e.g. changing LifoSemMPMCQueue so it's just descriptive and not an enumeration of implementation details. Please chip in with yr ideas!
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5694213
      
      fbshipit-source-id: 4fc0ea9359d1216191676fc9729fb53a3f06339f
      af4a3352
  7. 05 Sep, 2017 1 commit
    • Stella Lau's avatar
      Compress empty strings with underlying compressor · 049fb12e
      Stella Lau authored
      Summary:
      - Current behavior compresses empty strings to empty strings. This is undesirable as decompression using underlying decompressor (side-stepping the codec) will fail. This change passes empty strings to the underlying compressor
      - Decompressing empty string -> empty string was kept for backwards compatibility
      - Fix `getUncompressedLength` for zlib
      
      Reviewed By: terrelln, yfeldblum
      
      Differential Revision: D5740034
      
      fbshipit-source-id: 5a747ea4963dad872103209aa4410197f6c605db
      049fb12e
  8. 02 Sep, 2017 1 commit
    • Yedidya Feldblum's avatar
      Fix constexpr_min after D5739715 · 4fd5e900
      Yedidya Feldblum authored
      Summary:
      [Folly] Fix `constexpr_min` after {D5739715} (facebook/folly@6d7c6d55f0f4b7b75607608ef9037db58083368f).
      
      Add new unit-tests for `constexpr_min` and `constexpr_max` to avoid silly mistakes like this in the future.
      
      It was defined recursively in terms of `constexpr_max` rather than, as intended, in terns of `constexpr_min`. HT Mandar12.
      
      Reviewed By: Orvid
      
      Differential Revision: D5761831
      
      fbshipit-source-id: 2dad5833e05679232b3c529d33325a0205c2e4e4
      4fd5e900
  9. 01 Sep, 2017 2 commits
    • Igor Sugak's avatar
      increase stack size when TSAN is enabled · 555494f0
      Igor Sugak authored
      Reviewed By: meyering
      
      Differential Revision: D5757469
      
      fbshipit-source-id: ad70c47251993c79a502d30f312534e28c9241d4
      555494f0
    • Kyle Nekritz's avatar
      Deflake some AsyncSSLSocket tests. · bb9a2237
      Kyle Nekritz authored
      Summary: Fulfilling starts destroying the evb in another thread which races with the socket closing on the evb.
      
      Reviewed By: siyengar, ngoyal
      
      Differential Revision: D5755271
      
      fbshipit-source-id: ace37eee63e684c97ca0fe503293eee83514e0ac
      bb9a2237
  10. 31 Aug, 2017 3 commits
    • Aravind Anbudurai's avatar
      Add a comment on File.h · e540cbee
      Aravind Anbudurai authored
      Summary: title
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5751299
      
      fbshipit-source-id: d3967c2499da9a2c98c2862b9bdc9994c12edc76
      e540cbee
    • Yedidya Feldblum's avatar
      Extract non-portability constexpr math functions to new header · 6d7c6d55
      Yedidya Feldblum authored
      Summary:
      [Folly] Extract non-portability `constexpr` math functions to new header.
      
      This new header, `folly/ConstexprMath.h`, is specifically for compile-time-computable math functions. We start with `min`, `max`, `abs`, and `log2`.
      
      Included substantive changes:
      * Add new tests for `constexpr_strlen`, which remains in the portability header.
      * Make `constexpr_min` and `constexpr_max` variadic.
      * Make `constexpr_log2` tail-recursive, remove `const_log2` in `FixedString.h`, and move the related comment.
      
      Reviewed By: Orvid
      
      Differential Revision: D5739715
      
      fbshipit-source-id: 29d3cc846ce98bb4bdddcc8b0fa80e4d32075fe0
      6d7c6d55
    • Philip Jameson's avatar
      Don't use symbolizer on OSX · 4717bdad
      Philip Jameson authored
      Summary:
      When trying to build with targets files on OSX, I couldn't use the symbolizer because it needs StackTrace, which requires libunwind and elf. This makes it so that we only build on linux for now. This also makes it so that we set FOLLY_USE_SYMBOLIZER in autoconf, since that wasn't set before.
      
      Does a few things surrounding usage of the symbolizer library:
      - Introduce FOLLY_USE_SYMBOLIZER in folly-config.h and USE_SYMBOLIZER as an AM definition
      -- Filter some code out of init and some other random libs that optionally need the symbolizer
      - Fix libdwarf detection. Previously on a fresh ubuntu container, we didn't find libdwarf/dwarf.h, so we stopped trying before looking at dwarf.h
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5644352
      
      fbshipit-source-id: f0a3580c41122e5e8fdfd17a9fdbb0921be21401
      4717bdad
  11. 30 Aug, 2017 6 commits
    • Michael Lee's avatar
      Include `<array>` for test · faa5f598
      Michael Lee authored
      Summary: <array> is sometimes necessary for using `std::array`. Fix up
      
      Reviewed By: aary
      
      Differential Revision: D5740866
      
      fbshipit-source-id: 13bafadd26fdd0f2eff3513115b43811682e7cda
      faa5f598
    • Aaryaman Sagar's avatar
      Conditionally compiled for_each with constexpr · f45b792f
      Aaryaman Sagar authored
      Summary:
      Code was breaking in versions of C++ where constexpr functions are
      required to have one line bodies
      
      Reviewed By: yfeldblum, mzlee
      
      Differential Revision: D5739062
      
      fbshipit-source-id: 6c509f1daf77751d33ce9c173a0d7f1d3bd2a006
      f45b792f
    • Maged Michael's avatar
      Dynamic MPMCQueue: Eliminate cases of enqueue indefinite blocking and failure... · 9ce176b1
      Maged Michael authored
      Dynamic MPMCQueue: Eliminate cases of enqueue indefinite blocking and failure in the extensible version that impossible under the default pre-allocated version
      
      Summary:
      Currently under the extensible version (Dynamic == true), some enqueue operations may block indefinitely or fail (return false) even though such outcomes are impossible under the default (Dynamic == false) pre-allocated version.
      
      This diff eliminates such cases by changing the algorithms for the extensible version. Some of the high-level changes:
      - The offset formula for an expansion guarantees that no enqueue operation left behind in a closed array does not have an existing dequeue operation that unblocks it. The old formula was 1 + max(head, tail). The new formula is max(head, current offset) + current capacity.
      - Conditional operations validate state after the success of CAS.
      
      Reviewed By: djwatson
      
      Differential Revision: D5701013
      
      fbshipit-source-id: 4917c5b35b7e2a2fddfd2e11fb5aeb478502137c
      9ce176b1
    • Yedidya Feldblum's avatar
      constexpr_log2 · f7ec2efe
      Yedidya Feldblum authored
      Summary:
      [Folly] `constexpr_log2`.
      
      Useful for anything that needs to compute log2 at compile time.
      
      Reviewed By: eduardo-elizondo
      
      Differential Revision: D5734727
      
      fbshipit-source-id: 8eab7991eea2104570eecd8e84ede6160bb0b549
      f7ec2efe
    • Yedidya Feldblum's avatar
      Shrink MicroSpinLock.h transitive includes and inline methods · 70137200
      Yedidya Feldblum authored
      Summary: [Folly] Shrink `MicroSpinLock.h` transitive includes and inline methods.
      
      Reviewed By: meyering
      
      Differential Revision: D5732693
      
      fbshipit-source-id: 386816f0d97c145ff8a4180d41c8a682694aa6cb
      70137200
    • Xiao Shi's avatar
      rm old comment on HHWheelTimer::UniquePtr · 985a7f47
      Xiao Shi authored
      Summary: This comment is outdated.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5730049
      
      fbshipit-source-id: f6088c4354210fafb019656cdf8246abf90fbc06
      985a7f47
  12. 29 Aug, 2017 7 commits
  13. 28 Aug, 2017 3 commits
    • Christopher Dykes's avatar
      Enable auto-deps in all of Folly · 2ccbaf9e
      Christopher Dykes authored
      Summary: This enables the last of the magic internally.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5719795
      
      fbshipit-source-id: fb59a0d7873e9a9f3b73f556b42b647091ca7e67
      2ccbaf9e
    • Yedidya Feldblum's avatar
      Shrink MicroSpinLock.h transitive includes and inline methods · 053fb025
      Yedidya Feldblum authored
      Summary: [Folly] Shrink `MicroSpinLock.h` transitive includes and inline methods.
      
      Reviewed By: Orvid
      
      Differential Revision: D5714883
      
      fbshipit-source-id: 1744685ff9fa8d3620aef2545c8fe3ebc481df06
      053fb025
    • Patryk Zaryjewski's avatar
      Make cancelling and rescheduling of functions O(1) · 951a822c
      Patryk Zaryjewski authored
      Summary: Currently FunctionScheduler calls that cancel/restart timer for a function of particular id are O(n). By introducing hashmap that translate id to pointer of particular RepeatFunc, we make it O(1).
      
      Reviewed By: simpkins
      
      Differential Revision: D5668557
      
      fbshipit-source-id: e5e8bf9bd75b6d5d42f0bfa398d476703e5801fa
      951a822c
  14. 25 Aug, 2017 5 commits
    • Aaryaman Sagar's avatar
      gcc 6.2 was not accepting the current definition of void_t · db9fd491
      Aaryaman Sagar authored
      Summary:
      The current definition of void_t was leading to errors because unused
      template parameters are ignored and SFINAE SFIAEs
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5700825
      
      fbshipit-source-id: d23336070c217e8594980d6db710cb417b014236
      db9fd491
    • Marko Novakovic's avatar
      Added a flag FOLLY_FORCE_EXCEPTION_COUNT_USE_STD · 04a42b09
      Marko Novakovic authored
      Summary:
      The flag FOLLY_FORCE_EXCEPTION_COUNT_USE_STD forces
      the usage of std:uncaught_exceptions() for folly's
      implementation of uncaught_exceptions()
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5542302
      
      fbshipit-source-id: 2c2f507ab9dde916a160a9c370a267cdcfd7203a
      04a42b09
    • Stella Lau's avatar
      Enforce forward progress with StreamCodec · 91022bb0
      Stella Lau authored
      Summary:
      - Throw exception if no forward progress was made with `StreamCodec.compress()` and `StreamCodec.uncompress()`
      - Prevents infinite looping behavior when no forward progress was made
      - Update tests
      
      Reviewed By: terrelln
      
      Differential Revision: D5685690
      
      fbshipit-source-id: 969393896b74f51250f0e0ce3af0cd4fedcab49a
      91022bb0
    • Qinfan Wu's avatar
      Fix typo in Function.h · 82ee3be4
      Qinfan Wu authored
      Summary: [Folly] Fix typo in `Function.h`.
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5703550
      
      fbshipit-source-id: 9dc09697fd09db6c65b1a4f2d8bdf44451b4aab2
      82ee3be4
    • Greg Nisbet's avatar
      add public kSlotSize to IndexedMemPool · 37c61971
      Greg Nisbet authored
      Summary:
      add public kSlotSize to IndexedMemPool,
      needed to support getting the approximate memory footprint of the pool
      (since a Slot has two atomic uint32_t's more than a bare Elem)
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5690225
      
      fbshipit-source-id: 667da6b67b339038b92b0e5acde17219fe1c85c5
      37c61971
  15. 24 Aug, 2017 2 commits
    • Aaryaman Sagar's avatar
      Added rvalue and const rvalue overloads to Try · 51647aaa
      Aaryaman Sagar authored
      Summary:
      Try was missing some important-ish overloads that help it behave well
      in rvalue contexts
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5692021
      
      fbshipit-source-id: c34627b56eb52dceaeb1f00ae930ee3bc6e00306
      51647aaa
    • Aaryaman Sagar's avatar
      unwrapTryTuple only accepted rvalue tuple types · 374d408b
      Aaryaman Sagar authored
      Summary:
      unwrapTryTuple only accepted rvalue tuple types, this diff fixes that
      to work with forwarding reference tuple types.
      
      Also reduces the number of template instantiations
      
      Reviewed By: yfeldblum
      
      Differential Revision: D5682996
      
      fbshipit-source-id: ee6dd2c20d8dfca33e769a98a6ca56fa96c73b72
      374d408b