1 // Copyright (c) 2017-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
8 #include "util/testharness.h"
9 #include "utilities/cassandra/format.h"
10 #include "utilities/cassandra/serialize.h"
11 #include "utilities/cassandra/test_utils.h"
13 using namespace rocksdb::cassandra
;
18 TEST(ColumnTest
, Column
) {
19 char data
[4] = {'d', 'a', 't', 'a'};
22 int64_t timestamp
= 1494022807044;
23 Column c
= Column(mask
, index
, timestamp
, sizeof(data
), data
);
25 EXPECT_EQ(c
.Index(), index
);
26 EXPECT_EQ(c
.Timestamp(), timestamp
);
27 EXPECT_EQ(c
.Size(), 14 + sizeof(data
));
29 // Verify the serialization.
31 dest
.reserve(c
.Size() * 2);
34 EXPECT_EQ(dest
.size(), c
.Size());
35 std::size_t offset
= 0;
36 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), mask
);
37 offset
+= sizeof(int8_t);
38 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), index
);
39 offset
+= sizeof(int8_t);
40 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), timestamp
);
41 offset
+= sizeof(int64_t);
42 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), sizeof(data
));
43 offset
+= sizeof(int32_t);
44 EXPECT_TRUE(std::memcmp(data
, dest
.c_str() + offset
, sizeof(data
)) == 0);
46 // Verify the deserialization.
47 std::string saved_dest
= dest
;
48 std::shared_ptr
<Column
> c1
= Column::Deserialize(saved_dest
.c_str(), 0);
49 EXPECT_EQ(c1
->Index(), index
);
50 EXPECT_EQ(c1
->Timestamp(), timestamp
);
51 EXPECT_EQ(c1
->Size(), 14 + sizeof(data
));
54 EXPECT_EQ(dest
.size(), 2 * c
.Size());
56 std::memcmp(dest
.c_str(), dest
.c_str() + c
.Size(), c
.Size()) == 0);
58 // Verify the ColumnBase::Deserialization.
60 std::shared_ptr
<ColumnBase
> c2
=
61 ColumnBase::Deserialize(saved_dest
.c_str(), c
.Size());
63 EXPECT_EQ(dest
.size(), 3 * c
.Size());
65 std::memcmp(dest
.c_str() + c
.Size(), dest
.c_str() + c
.Size() * 2, c
.Size())
69 TEST(ExpiringColumnTest
, ExpiringColumn
) {
70 char data
[4] = {'d', 'a', 't', 'a'};
71 int8_t mask
= ColumnTypeMask::EXPIRATION_MASK
;
73 int64_t timestamp
= 1494022807044;
75 ExpiringColumn c
= ExpiringColumn(mask
, index
, timestamp
,
76 sizeof(data
), data
, ttl
);
78 EXPECT_EQ(c
.Index(), index
);
79 EXPECT_EQ(c
.Timestamp(), timestamp
);
80 EXPECT_EQ(c
.Size(), 18 + sizeof(data
));
82 // Verify the serialization.
84 dest
.reserve(c
.Size() * 2);
87 EXPECT_EQ(dest
.size(), c
.Size());
88 std::size_t offset
= 0;
89 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), mask
);
90 offset
+= sizeof(int8_t);
91 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), index
);
92 offset
+= sizeof(int8_t);
93 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), timestamp
);
94 offset
+= sizeof(int64_t);
95 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), sizeof(data
));
96 offset
+= sizeof(int32_t);
97 EXPECT_TRUE(std::memcmp(data
, dest
.c_str() + offset
, sizeof(data
)) == 0);
98 offset
+= sizeof(data
);
99 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), ttl
);
101 // Verify the deserialization.
102 std::string saved_dest
= dest
;
103 std::shared_ptr
<ExpiringColumn
> c1
=
104 ExpiringColumn::Deserialize(saved_dest
.c_str(), 0);
105 EXPECT_EQ(c1
->Index(), index
);
106 EXPECT_EQ(c1
->Timestamp(), timestamp
);
107 EXPECT_EQ(c1
->Size(), 18 + sizeof(data
));
109 c1
->Serialize(&dest
);
110 EXPECT_EQ(dest
.size(), 2 * c
.Size());
112 std::memcmp(dest
.c_str(), dest
.c_str() + c
.Size(), c
.Size()) == 0);
114 // Verify the ColumnBase::Deserialization.
116 std::shared_ptr
<ColumnBase
> c2
=
117 ColumnBase::Deserialize(saved_dest
.c_str(), c
.Size());
118 c2
->Serialize(&dest
);
119 EXPECT_EQ(dest
.size(), 3 * c
.Size());
121 std::memcmp(dest
.c_str() + c
.Size(), dest
.c_str() + c
.Size() * 2, c
.Size())
125 TEST(TombstoneTest
, TombstoneCollectable
) {
126 int32_t now
= (int32_t)time(nullptr);
127 int32_t gc_grace_seconds
= 16440;
128 int32_t time_delta_seconds
= 10;
129 EXPECT_TRUE(Tombstone(ColumnTypeMask::DELETION_MASK
, 0,
130 now
- gc_grace_seconds
- time_delta_seconds
,
131 ToMicroSeconds(now
- gc_grace_seconds
- time_delta_seconds
))
132 .Collectable(gc_grace_seconds
));
133 EXPECT_FALSE(Tombstone(ColumnTypeMask::DELETION_MASK
, 0,
134 now
- gc_grace_seconds
+ time_delta_seconds
,
135 ToMicroSeconds(now
- gc_grace_seconds
+ time_delta_seconds
))
136 .Collectable(gc_grace_seconds
));
139 TEST(TombstoneTest
, Tombstone
) {
140 int8_t mask
= ColumnTypeMask::DELETION_MASK
;
142 int32_t local_deletion_time
= 1494022807;
143 int64_t marked_for_delete_at
= 1494022807044;
144 Tombstone c
= Tombstone(mask
, index
, local_deletion_time
,
145 marked_for_delete_at
);
147 EXPECT_EQ(c
.Index(), index
);
148 EXPECT_EQ(c
.Timestamp(), marked_for_delete_at
);
149 EXPECT_EQ(c
.Size(), 14);
151 // Verify the serialization.
153 dest
.reserve(c
.Size() * 2);
156 EXPECT_EQ(dest
.size(), c
.Size());
157 std::size_t offset
= 0;
158 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), mask
);
159 offset
+= sizeof(int8_t);
160 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), index
);
161 offset
+= sizeof(int8_t);
162 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), local_deletion_time
);
163 offset
+= sizeof(int32_t);
164 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), marked_for_delete_at
);
166 // Verify the deserialization.
167 std::shared_ptr
<Tombstone
> c1
= Tombstone::Deserialize(dest
.c_str(), 0);
168 EXPECT_EQ(c1
->Index(), index
);
169 EXPECT_EQ(c1
->Timestamp(), marked_for_delete_at
);
170 EXPECT_EQ(c1
->Size(), 14);
172 c1
->Serialize(&dest
);
173 EXPECT_EQ(dest
.size(), 2 * c
.Size());
175 std::memcmp(dest
.c_str(), dest
.c_str() + c
.Size(), c
.Size()) == 0);
177 // Verify the ColumnBase::Deserialization.
178 std::shared_ptr
<ColumnBase
> c2
=
179 ColumnBase::Deserialize(dest
.c_str(), c
.Size());
180 c2
->Serialize(&dest
);
181 EXPECT_EQ(dest
.size(), 3 * c
.Size());
183 std::memcmp(dest
.c_str() + c
.Size(), dest
.c_str() + c
.Size() * 2, c
.Size())
187 TEST(RowValueTest
, RowTombstone
) {
188 int32_t local_deletion_time
= 1494022807;
189 int64_t marked_for_delete_at
= 1494022807044;
190 RowValue r
= RowValue(local_deletion_time
, marked_for_delete_at
);
192 EXPECT_EQ(r
.Size(), 12);
193 EXPECT_EQ(r
.IsTombstone(), true);
194 EXPECT_EQ(r
.LastModifiedTime(), marked_for_delete_at
);
196 // Verify the serialization.
198 dest
.reserve(r
.Size() * 2);
201 EXPECT_EQ(dest
.size(), r
.Size());
202 std::size_t offset
= 0;
203 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), local_deletion_time
);
204 offset
+= sizeof(int32_t);
205 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), marked_for_delete_at
);
207 // Verify the deserialization.
208 RowValue r1
= RowValue::Deserialize(dest
.c_str(), r
.Size());
209 EXPECT_EQ(r1
.Size(), 12);
210 EXPECT_EQ(r1
.IsTombstone(), true);
211 EXPECT_EQ(r1
.LastModifiedTime(), marked_for_delete_at
);
214 EXPECT_EQ(dest
.size(), 2 * r
.Size());
216 std::memcmp(dest
.c_str(), dest
.c_str() + r
.Size(), r
.Size()) == 0);
219 TEST(RowValueTest
, RowWithColumns
) {
220 std::vector
<std::shared_ptr
<ColumnBase
>> columns
;
221 int64_t last_modified_time
= 1494022807048;
222 std::size_t columns_data_size
= 0;
224 char e_data
[5] = {'e', 'd', 'a', 't', 'a'};
226 int64_t e_timestamp
= 1494022807044;
227 int32_t e_ttl
= 3600;
228 columns
.push_back(std::shared_ptr
<ExpiringColumn
>(
229 new ExpiringColumn(ColumnTypeMask::EXPIRATION_MASK
, e_index
,
230 e_timestamp
, sizeof(e_data
), e_data
, e_ttl
)));
231 columns_data_size
+= columns
[0]->Size();
233 char c_data
[4] = {'d', 'a', 't', 'a'};
235 int64_t c_timestamp
= 1494022807048;
236 columns
.push_back(std::shared_ptr
<Column
>(
237 new Column(0, c_index
, c_timestamp
, sizeof(c_data
), c_data
)));
238 columns_data_size
+= columns
[1]->Size();
241 int32_t t_local_deletion_time
= 1494022801;
242 int64_t t_marked_for_delete_at
= 1494022807043;
243 columns
.push_back(std::shared_ptr
<Tombstone
>(
244 new Tombstone(ColumnTypeMask::DELETION_MASK
,
245 t_index
, t_local_deletion_time
, t_marked_for_delete_at
)));
246 columns_data_size
+= columns
[2]->Size();
248 RowValue r
= RowValue(std::move(columns
), last_modified_time
);
250 EXPECT_EQ(r
.Size(), columns_data_size
+ 12);
251 EXPECT_EQ(r
.IsTombstone(), false);
252 EXPECT_EQ(r
.LastModifiedTime(), last_modified_time
);
254 // Verify the serialization.
256 dest
.reserve(r
.Size() * 2);
259 EXPECT_EQ(dest
.size(), r
.Size());
260 std::size_t offset
= 0;
261 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
),
262 std::numeric_limits
<int32_t>::max());
263 offset
+= sizeof(int32_t);
264 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
),
265 std::numeric_limits
<int64_t>::min());
266 offset
+= sizeof(int64_t);
268 // Column0: ExpiringColumn
269 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
),
270 ColumnTypeMask::EXPIRATION_MASK
);
271 offset
+= sizeof(int8_t);
272 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), e_index
);
273 offset
+= sizeof(int8_t);
274 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), e_timestamp
);
275 offset
+= sizeof(int64_t);
276 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), sizeof(e_data
));
277 offset
+= sizeof(int32_t);
278 EXPECT_TRUE(std::memcmp(e_data
, dest
.c_str() + offset
, sizeof(e_data
)) == 0);
279 offset
+= sizeof(e_data
);
280 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), e_ttl
);
281 offset
+= sizeof(int32_t);
284 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), 0);
285 offset
+= sizeof(int8_t);
286 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), c_index
);
287 offset
+= sizeof(int8_t);
288 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), c_timestamp
);
289 offset
+= sizeof(int64_t);
290 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), sizeof(c_data
));
291 offset
+= sizeof(int32_t);
292 EXPECT_TRUE(std::memcmp(c_data
, dest
.c_str() + offset
, sizeof(c_data
)) == 0);
293 offset
+= sizeof(c_data
);
295 // Column2: Tombstone
296 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
),
297 ColumnTypeMask::DELETION_MASK
);
298 offset
+= sizeof(int8_t);
299 EXPECT_EQ(Deserialize
<int8_t>(dest
.c_str(), offset
), t_index
);
300 offset
+= sizeof(int8_t);
301 EXPECT_EQ(Deserialize
<int32_t>(dest
.c_str(), offset
), t_local_deletion_time
);
302 offset
+= sizeof(int32_t);
303 EXPECT_EQ(Deserialize
<int64_t>(dest
.c_str(), offset
), t_marked_for_delete_at
);
305 // Verify the deserialization.
306 RowValue r1
= RowValue::Deserialize(dest
.c_str(), r
.Size());
307 EXPECT_EQ(r1
.Size(), columns_data_size
+ 12);
308 EXPECT_EQ(r1
.IsTombstone(), false);
309 EXPECT_EQ(r1
.LastModifiedTime(), last_modified_time
);
312 EXPECT_EQ(dest
.size(), 2 * r
.Size());
314 std::memcmp(dest
.c_str(), dest
.c_str() + r
.Size(), r
.Size()) == 0);
317 TEST(RowValueTest
, PurgeTtlShouldRemvoeAllColumnsExpired
) {
318 int64_t now
= time(nullptr);
320 auto row_value
= CreateTestRowValue({
321 CreateTestColumnSpec(kColumn
, 0, ToMicroSeconds(now
)),
322 CreateTestColumnSpec(kExpiringColumn
, 1, ToMicroSeconds(now
- kTtl
- 10)), //expired
323 CreateTestColumnSpec(kExpiringColumn
, 2, ToMicroSeconds(now
)), // not expired
324 CreateTestColumnSpec(kTombstone
, 3, ToMicroSeconds(now
))
327 bool changed
= false;
328 auto purged
= row_value
.RemoveExpiredColumns(&changed
);
329 EXPECT_TRUE(changed
);
330 EXPECT_EQ(purged
.columns_
.size(), 3);
331 VerifyRowValueColumns(purged
.columns_
, 0, kColumn
, 0, ToMicroSeconds(now
));
332 VerifyRowValueColumns(purged
.columns_
, 1, kExpiringColumn
, 2, ToMicroSeconds(now
));
333 VerifyRowValueColumns(purged
.columns_
, 2, kTombstone
, 3, ToMicroSeconds(now
));
335 purged
.RemoveExpiredColumns(&changed
);
336 EXPECT_FALSE(changed
);
339 TEST(RowValueTest
, ExpireTtlShouldConvertExpiredColumnsToTombstones
) {
340 int64_t now
= time(nullptr);
342 auto row_value
= CreateTestRowValue({
343 CreateTestColumnSpec(kColumn
, 0, ToMicroSeconds(now
)),
344 CreateTestColumnSpec(kExpiringColumn
, 1, ToMicroSeconds(now
- kTtl
- 10)), //expired
345 CreateTestColumnSpec(kExpiringColumn
, 2, ToMicroSeconds(now
)), // not expired
346 CreateTestColumnSpec(kTombstone
, 3, ToMicroSeconds(now
))
349 bool changed
= false;
350 auto compacted
= row_value
.ConvertExpiredColumnsToTombstones(&changed
);
351 EXPECT_TRUE(changed
);
352 EXPECT_EQ(compacted
.columns_
.size(), 4);
353 VerifyRowValueColumns(compacted
.columns_
, 0, kColumn
, 0, ToMicroSeconds(now
));
354 VerifyRowValueColumns(compacted
.columns_
, 1, kTombstone
, 1, ToMicroSeconds(now
- 10));
355 VerifyRowValueColumns(compacted
.columns_
, 2, kExpiringColumn
, 2, ToMicroSeconds(now
));
356 VerifyRowValueColumns(compacted
.columns_
, 3, kTombstone
, 3, ToMicroSeconds(now
));
358 compacted
.ConvertExpiredColumnsToTombstones(&changed
);
359 EXPECT_FALSE(changed
);
361 } // namespace cassandra
362 } // namespace rocksdb
364 int main(int argc
, char** argv
) {
365 ::testing::InitGoogleTest(&argc
, argv
);
366 return RUN_ALL_TESTS();