2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <folly/Baton.h>
24 #include <folly/experimental/flat_combining/FlatCombining.h>
29 FOLLY_ALIGN_TO_AVOID_FALSE_SHARING
33 class Data { // Sequential data structure
35 explicit Data(size_t size) : size_(size) {
36 x_ = std::make_unique<Line[]>(size_);
40 uint64_t val = x_[0].val_;
41 for (size_t i = 1; i < size_; ++i) {
42 assert(x_[i].val_ == val);
49 void add(uint64_t val) {
50 uint64_t oldval = x_[0].val_;
51 for (size_t i = 0; i < size_; ++i) {
52 assert(x_[i].val_ == oldval);
53 x_[i].val_ = oldval + val;
57 uint64_t fetchAdd(uint64_t val) {
58 uint64_t res = x_[0].val_;
59 for (size_t i = 0; i < size_; ++i) {
60 assert(x_[i].val_ == res);
68 std::unique_ptr<Line[]> x_;
71 // Example of FC concurrent data structure using simple interface
74 typename Mutex = std::mutex,
75 template <typename> class Atom = std::atomic>
77 : public FlatCombining<FcSimpleExample<Mutex, Atom>, Mutex, Atom> {
78 using FC = FlatCombining<FcSimpleExample<Mutex, Atom>, Mutex, Atom>;
79 using Rec = typename FC::Rec;
82 explicit FcSimpleExample(
84 bool dedicated = true,
87 : FC(dedicated, numRecs, maxOps), data_(size) {}
90 return data_.getVal();
95 void addNoFC(uint64_t val) {
96 this->requestNoFC([&] { data_.add(val); });
99 void add(uint64_t val, Rec* rec = nullptr) {
100 auto opFn = [&, val] { // asynchronous -- capture val by value
103 this->requestFC(opFn, rec, false);
108 uint64_t fetchAddNoFC(uint64_t val) {
110 auto opFn = [&] { res = data_.fetchAdd(val); };
111 this->requestNoFC(opFn);
115 uint64_t fetchAdd(uint64_t val, Rec* rec = nullptr) {
117 auto opFn = [&] { res = data_.fetchAdd(val); };
118 this->requestFC(opFn, rec);
126 // Example of FC data structure using custom request processing
130 enum class Type { ADD, FETCHADD };
132 void setType(Type type) {
140 void setVal(uint64_t val) {
148 void setRes(uint64_t res) {
164 typename Mutex = std::mutex,
165 template <typename> class Atom = std::atomic>
166 class FcCustomExample : public FlatCombining<
167 FcCustomExample<Req, Mutex, Atom>,
171 using FC = FlatCombining<FcCustomExample<Req, Mutex, Atom>, Mutex, Atom, Req>;
172 using Rec = typename FC::Rec;
175 explicit FcCustomExample(
177 bool dedicated = true,
178 uint32_t numRecs = 0,
180 : FC(dedicated, numRecs, maxOps), data_(size) {}
183 return data_.getVal();
188 void addNoFC(uint64_t val) {
189 this->requestNoFC([&] { data_.add(val); });
192 void add(uint64_t val, Rec* rec = nullptr) {
193 auto opFn = [&, val] { data_.add(val); };
194 auto fillFn = [&](Req& req) {
195 req.setType(Req::Type::ADD);
198 this->requestFC(opFn, fillFn, rec, false); // asynchronous
203 uint64_t fetchAddNoFC(uint64_t val) {
205 auto opFn = [&] { res = data_.fetchAdd(val); };
206 this->requestNoFC(opFn);
210 uint64_t fetchAdd(uint64_t val, Rec* rec = nullptr) {
212 auto opFn = [&] { res = data_.fetchAdd(val); };
213 auto fillFn = [&](Req& req) {
214 req.setType(Req::Type::FETCHADD);
217 auto resFn = [&](Req& req) { res = req.getRes(); };
218 this->requestFC(opFn, fillFn, resFn, rec);
222 // custom combined op processing - overrides FlatCombining::combinedOp(Req&)
223 void combinedOp(Req& req) {
224 switch (req.getType()) {
225 case Req::Type::ADD: {
226 data_.add(req.getVal());
228 case Req::Type::FETCHADD: {
229 req.setRes(data_.fetchAdd(req.getVal()));
231 default: { assert(false); }