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