1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license.
3
4#pragma once
5
6#include <atomic>
7#include <cassert>
8#include <cstdint>
9#include "core/faster.h"
10#include "core/utility.h"
11#include "device/file_system_disk.h"
12
13using namespace FASTER::core;
14
15namespace sum_store {
16
17// Sum store's key type.
18class AdId {
19 public:
20 AdId(uint64_t key)
21 : key_{ key } {
22 }
23
24 inline static constexpr uint32_t size() {
25 return static_cast<uint32_t>(sizeof(AdId));
26 }
27 inline KeyHash GetHash() const {
28 return KeyHash{ Utility::GetHashCode(key_) };
29 }
30
31 /// Comparison operators.
32 inline bool operator==(const AdId& other) const {
33 return key_ == other.key_;
34 }
35 inline bool operator!=(const AdId& other) const {
36 return key_ != other.key_;
37 }
38
39 private:
40 uint64_t key_;
41};
42static_assert(sizeof(AdId) == 8, "sizeof(AdId) != 8)");
43
44// Sum store's value type.
45class NumClicks {
46 public:
47 NumClicks()
48 : num_clicks{ 0 } {
49 }
50 NumClicks(const NumClicks& other)
51 : num_clicks{ other.num_clicks } {
52 }
53
54 inline static constexpr uint32_t size() {
55 return static_cast<uint32_t>(sizeof(NumClicks));
56 }
57
58 union {
59 uint64_t num_clicks;
60 std::atomic<uint64_t> atomic_num_clicks;
61 };
62};
63
64/// Key is an 8-byte advertising ID.
65typedef AdId key_t;
66
67/// Value is an 8-byte count of clicks.
68typedef NumClicks value_t;
69
70/// Context to update the sum store (via read-modify-write).
71class RmwContext : public IAsyncContext {
72 public:
73 typedef sum_store::key_t key_t;
74 typedef sum_store::value_t value_t;
75
76 RmwContext(const AdId& key, uint64_t increment)
77 : key_{ key }
78 , increment_{ increment } {
79 }
80
81 /// Copy (and deep-copy) constructor.
82 RmwContext(const RmwContext& other)
83 : key_{ other.key_ }
84 , increment_{ other.increment_ } {
85 }
86
87 /// The implicit and explicit interfaces require a key() accessor.
88 inline const AdId& key() const {
89 return key_;
90 }
91
92 inline void RmwInitial(NumClicks& value) {
93 value.num_clicks = increment_;
94 }
95 inline void RmwCopy(const NumClicks& old_value, NumClicks& value) {
96 value.num_clicks = old_value.num_clicks + increment_;
97 }
98 inline bool RmwAtomic(NumClicks& value) {
99 value.atomic_num_clicks.fetch_add(increment_);
100 return true;
101 }
102 inline static constexpr uint32_t value_size() {
103 return sizeof(value_t);
104 }
105
106 protected:
107 /// The explicit interface requires a DeepCopy_Internal() implementation.
108 Status DeepCopy_Internal(IAsyncContext*& context_copy) {
109 return IAsyncContext::DeepCopy_Internal(*this, context_copy);
110 }
111
112 private:
113 AdId key_;
114 uint64_t increment_;
115};
116
117/// Context to read the store (after recovery).
118class ReadContext : public IAsyncContext {
119 public:
120 typedef sum_store::key_t key_t;
121 typedef sum_store::value_t value_t;
122
123 ReadContext(const AdId& key, uint64_t* result)
124 : key_{ key }
125 , result_{ result } {
126 }
127
128 /// Copy (and deep-copy) constructor.
129 ReadContext(const ReadContext& other)
130 : key_{ other.key_ }
131 , result_{ other.result_ } {
132 }
133
134 /// The implicit and explicit interfaces require a key() accessor.
135 inline const AdId& key() const {
136 return key_;
137 }
138
139 inline void Get(const value_t& value) {
140 *result_ = value.num_clicks;
141 }
142 inline void GetAtomic(const value_t& value) {
143 *result_ = value.atomic_num_clicks;
144 }
145
146 protected:
147 /// The explicit interface requires a DeepCopy_Internal() implementation.
148 Status DeepCopy_Internal(IAsyncContext*& context_copy) {
149 return IAsyncContext::DeepCopy_Internal(*this, context_copy);
150 }
151
152 private:
153 AdId key_;
154 uint64_t* result_;
155};
156
157typedef FasterKv<key_t, value_t, FASTER::device::FileSystemDisk<
158FASTER::environment::QueueIoHandler, 1073741824L>> store_t;
159
160} // namespace sum_store
161