1 /*
2 * CommitTransaction.h
3 *
4 * This source file is part of the FoundationDB open source project
5 *
6 * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 #ifndef FLOW_FDBCLIENT_COMMITTRANSACTION_H
22 #define FLOW_FDBCLIENT_COMMITTRANSACTION_H
23 #pragma once
24
25 #include "fdbclient/FDBTypes.h"
26
27 static const char* typeString[] = { "SetValue",
28 "ClearRange",
29 "AddValue",
30 "DebugKeyRange",
31 "DebugKey",
32 "NoOp",
33 "And",
34 "Or",
35 "Xor",
36 "AppendIfFits",
37 "AvailableForReuse",
38 "Reserved_For_LogProtocolMessage",
39 "Max",
40 "Min",
41 "SetVersionstampedKey",
42 "SetVersionstampedValue",
43 "ByteMin",
44 "ByteMax",
45 "MinV2",
46 "AndV2",
47 "CompareAndClear" };
48
49 struct MutationRef {
50 static const int OVERHEAD_BYTES = 12; //12 is the size of Header in MutationList entries
51 enum Type : uint8_t {
52 SetValue = 0,
53 ClearRange,
54 AddValue,
55 DebugKeyRange,
56 DebugKey,
57 NoOp,
58 And,
59 Or,
60 Xor,
61 AppendIfFits,
62 AvailableForReuse,
63 Reserved_For_LogProtocolMessage /* See fdbserver/LogProtocolMessage.h */,
64 Max,
65 Min,
66 SetVersionstampedKey,
67 SetVersionstampedValue,
68 ByteMin,
69 ByteMax,
70 MinV2,
71 AndV2,
72 CompareAndClear,
73 MAX_ATOMIC_OP
74 };
75 // This is stored this way for serialization purposes.
76 uint8_t type;
77 StringRef param1, param2;
78
MutationRefMutationRef79 MutationRef() {}
MutationRefMutationRef80 MutationRef( Type t, StringRef a, StringRef b ) : type(t), param1(a), param2(b) {}
MutationRefMutationRef81 MutationRef( Arena& to, const MutationRef& from ) : type(from.type), param1( to, from.param1 ), param2( to, from.param2 ) {}
totalSizeMutationRef82 int totalSize() const { return OVERHEAD_BYTES + param1.size() + param2.size(); }
expectedSizeMutationRef83 int expectedSize() const { return param1.size() + param2.size(); }
84
toStringMutationRef85 std::string toString() const {
86 if (type < MutationRef::MAX_ATOMIC_OP) {
87 return format("code: %s param1: %s param2: %s", typeString[type], printable(param1).c_str(), printable(param2).c_str());
88 }
89 else {
90 return format("code: %s param1: %s param2: %s", "Invalid", printable(param1).c_str(), printable(param2).c_str());
91 }
92 }
93
94 template <class Ar>
serializeMutationRef95 void serialize( Ar& ar ) {
96 serializer(ar, type, param1, param2);
97 }
98
99 // These masks define which mutation types have particular properties (they are used to implement isSingleKeyMutation() etc)
100 enum {
101 ATOMIC_MASK = (1 << AddValue) | (1 << And) | (1 << Or) | (1 << Xor) | (1 << AppendIfFits) | (1 << Max) |
102 (1 << Min) | (1 << SetVersionstampedKey) | (1 << SetVersionstampedValue) | (1 << ByteMin) |
103 (1 << ByteMax) | (1 << MinV2) | (1 << AndV2) | (1 << CompareAndClear),
104 SINGLE_KEY_MASK = ATOMIC_MASK | (1 << SetValue),
105 NON_ASSOCIATIVE_MASK = (1 << AddValue) | (1 << Or) | (1 << Xor) | (1 << Max) | (1 << Min) |
106 (1 << SetVersionstampedKey) | (1 << SetVersionstampedValue) | (1 << MinV2) |
107 (1 << CompareAndClear)
108 };
109 };
110
111 // A 'single key mutation' is one which affects exactly the value of the key specified by its param1
isSingleKeyMutation(MutationRef::Type type)112 static inline bool isSingleKeyMutation(MutationRef::Type type) {
113 return (MutationRef::SINGLE_KEY_MASK & (1<<type)) != 0;
114 }
115
116 // Returns true if the given type can be safely cast to MutationRef::Type and used as a parameter to
117 // isSingleKeyMutation, isAtomicOp, etc. It does NOT mean that the type is a valid type of a MutationRef in any
118 // particular context.
isValidMutationType(uint32_t type)119 static inline bool isValidMutationType(uint32_t type) {
120 return (type < MutationRef::MAX_ATOMIC_OP);
121 }
122
123 // An 'atomic operation' is a single key mutation which sets the key specified by its param1 to a
124 // nontrivial function of the previous value of the key and param2, and thus requires a
125 // read/modify/write to implement. (Basically a single key mutation other than a set)
isAtomicOp(MutationRef::Type mutationType)126 static inline bool isAtomicOp(MutationRef::Type mutationType) {
127 return (MutationRef::ATOMIC_MASK & (1<<mutationType)) != 0;
128 }
129
130 // Returns true for operations which do not obey the associative law (i.e. a*(b*c) == (a*b)*c) in all cases
131 // unless a, b, and c have equal lengths, in which case even these operations are associative.
isNonAssociativeOp(MutationRef::Type mutationType)132 static inline bool isNonAssociativeOp(MutationRef::Type mutationType) {
133 return (MutationRef::NON_ASSOCIATIVE_MASK & (1<<mutationType)) != 0;
134 }
135
136 struct CommitTransactionRef {
CommitTransactionRefCommitTransactionRef137 CommitTransactionRef() : read_snapshot(0) {}
CommitTransactionRefCommitTransactionRef138 CommitTransactionRef(Arena &a, const CommitTransactionRef &from)
139 : read_conflict_ranges(a, from.read_conflict_ranges),
140 write_conflict_ranges(a, from.write_conflict_ranges),
141 mutations(a, from.mutations),
142 read_snapshot(from.read_snapshot) {
143 }
144 VectorRef< KeyRangeRef > read_conflict_ranges;
145 VectorRef< KeyRangeRef > write_conflict_ranges;
146 VectorRef< MutationRef > mutations;
147 Version read_snapshot;
148
149 template <class Ar>
serializeCommitTransactionRef150 force_inline void serialize( Ar& ar ) {
151 serializer(ar, read_conflict_ranges, write_conflict_ranges, mutations, read_snapshot);
152 }
153
154 // Convenience for internal code required to manipulate these without the Native API
setCommitTransactionRef155 void set( Arena& arena, KeyRef const& key, ValueRef const& value ) {
156 mutations.push_back_deep(arena, MutationRef(MutationRef::SetValue, key, value));
157 write_conflict_ranges.push_back(arena, singleKeyRange(key, arena));
158 }
159
clearCommitTransactionRef160 void clear( Arena& arena, KeyRangeRef const& keys ) {
161 mutations.push_back_deep(arena, MutationRef(MutationRef::ClearRange, keys.begin, keys.end));
162 write_conflict_ranges.push_back_deep(arena, keys);
163 }
164
expectedSizeCommitTransactionRef165 size_t expectedSize() const {
166 return read_conflict_ranges.expectedSize() + write_conflict_ranges.expectedSize() + mutations.expectedSize();
167 }
168 };
169
170 bool debugMutation( const char* context, Version version, MutationRef const& m );
171 bool debugKeyRange( const char* context, Version version, KeyRangeRef const& keyRange );
172
173 #endif
174