mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-03 13:37:04 +00:00
At the moment, various different subsystems use their different ideas of what a timeout_clock is. This makes it a bit harder to pass timeouts between them because although most are actually a lowres_clock, that is not guaranteed to be the case. As a matter of fact, the timeout for restricted reads is expressed as nanoseconds, which is not a valid duration in the lowres_clock. As a first step towards fixing this, we'll consolidate all of the existing timeout_clocks in one, now called db::timeout_clock. Other things that tend to be expressed in terms of that clock--like the fact that the maximum time_point means no timeout and a semaphore that wait()s with that resolution are also moved to the common header. In the upcoming patch we will fix the restricted reader timeouts to be expressed in terms of the new timeout_clock. Signed-off-by: Glauber Costa <glauber@scylladb.com>
283 lines
10 KiB
C++
283 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2017 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "tests/test-utils.hh"
|
|
|
|
#include <seastar/core/thread.hh>
|
|
|
|
#include "cell_locking.hh"
|
|
#include "mutation.hh"
|
|
#include "schema_builder.hh"
|
|
|
|
static schema_ptr make_schema()
|
|
{
|
|
return schema_builder("ks", "cf")
|
|
.with_column("pk", bytes_type, column_kind::partition_key)
|
|
.with_column("ck", bytes_type, column_kind::clustering_key)
|
|
.with_column("s1", bytes_type, column_kind::static_column)
|
|
.with_column("s2", bytes_type, column_kind::static_column)
|
|
.with_column("s3", bytes_type, column_kind::static_column)
|
|
.with_column("r1", bytes_type)
|
|
.with_column("r2", bytes_type)
|
|
.with_column("r3", bytes_type)
|
|
.build();
|
|
}
|
|
|
|
static schema_ptr make_alternative_schema()
|
|
{
|
|
return schema_builder("ks", "cf")
|
|
.with_column("pk", bytes_type, column_kind::partition_key)
|
|
.with_column("ck", bytes_type, column_kind::clustering_key)
|
|
.with_column("s0", bytes_type, column_kind::static_column)
|
|
.with_column("s1", bytes_type, column_kind::static_column)
|
|
.with_column("s2.5", bytes_type, column_kind::static_column)
|
|
.with_column("s3", bytes_type, column_kind::static_column)
|
|
.with_column("r0", bytes_type)
|
|
.with_column("r1", bytes_type)
|
|
.with_column("r2.5", bytes_type)
|
|
.with_column("r3", bytes_type)
|
|
.build();
|
|
}
|
|
|
|
static schema_ptr make_schema_disjoint_with_others()
|
|
{
|
|
return schema_builder("ks", "cf")
|
|
.with_column("pk", bytes_type, column_kind::partition_key)
|
|
.with_column("ck", bytes_type, column_kind::clustering_key)
|
|
.with_column("s8", bytes_type, column_kind::static_column)
|
|
.with_column("s9", bytes_type, column_kind::static_column)
|
|
.with_column("r8", bytes_type)
|
|
.with_column("r9", bytes_type)
|
|
.build();
|
|
}
|
|
|
|
static data_value empty_value = data_value(to_bytes(""));
|
|
|
|
static db::timeout_clock::time_point no_timeout {
|
|
db::timeout_clock::duration(std::numeric_limits<db::timeout_clock::duration::rep>::max())
|
|
};
|
|
|
|
static auto make_row(const sstring& key, std::initializer_list<sstring> cells) {
|
|
return std::pair<sstring, std::initializer_list<sstring>>(key, cells);
|
|
}
|
|
|
|
static mutation make_mutation(schema_ptr s, const sstring& pk, std::initializer_list<sstring> static_cells,
|
|
std::initializer_list<std::pair<sstring, std::initializer_list<sstring>>> clustering_cells)
|
|
{
|
|
auto m = mutation(partition_key::from_single_value(*s, to_bytes(pk)), s);
|
|
for (auto&& c : static_cells) {
|
|
m.set_static_cell(to_bytes(c), empty_value, api::new_timestamp());
|
|
}
|
|
for (auto&& r : clustering_cells) {
|
|
auto ck = clustering_key::from_single_value(*s, to_bytes(r.first));
|
|
for (auto&& c : r.second) {
|
|
m.set_clustered_cell(ck, to_bytes(c), empty_value, api::new_timestamp());
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_simple_locking_cells) {
|
|
return seastar::async([&] {
|
|
auto destroy = [] (auto) { };
|
|
|
|
auto s = make_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s, cl_stats);
|
|
|
|
auto m = make_mutation(s, "0", { "s1", "s3" }, {
|
|
make_row("one", { "r1", "r2" }),
|
|
make_row("two", { "r2", "r3" }),
|
|
});
|
|
|
|
auto l1 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout).get0();
|
|
auto f2 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout);
|
|
BOOST_REQUIRE(!f2.available());
|
|
|
|
destroy(std::move(l1));
|
|
destroy(f2.get0());
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_disjoint_mutations) {
|
|
return seastar::async([&] {
|
|
auto s = make_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s, cl_stats);
|
|
|
|
auto m1 = make_mutation(s, "0", { "s1" }, {
|
|
make_row("one", { "r1", "r2" }),
|
|
make_row("two", { "r3" }),
|
|
});
|
|
auto m2 = make_mutation(s, "0", { "s2" }, {
|
|
make_row("two", { "r1", "r2" }),
|
|
make_row("one", { "r3" }),
|
|
});
|
|
|
|
auto m3 = mutation(partition_key::from_single_value(*s, to_bytes("1")), s);
|
|
m3.partition() = m1.partition();
|
|
|
|
auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
|
|
auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
|
|
auto l3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout).get0();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_single_cell_overlap) {
|
|
return seastar::async([&] {
|
|
auto destroy = [] (auto) { };
|
|
|
|
auto s = make_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s, cl_stats);
|
|
|
|
auto m1 = make_mutation(s, "0", { "s1" }, {
|
|
make_row("one", { "r1", "r2" }),
|
|
make_row("two", { "r3" }),
|
|
});
|
|
auto m2 = make_mutation(s, "0", { "s1" }, {
|
|
make_row("two", { "r1", "r2" }),
|
|
make_row("one", { "r3" }),
|
|
});
|
|
auto m3 = make_mutation(s, "0", { "s2" }, {
|
|
make_row("two", { "r1" }),
|
|
make_row("one", { "r2", "r3" }),
|
|
});
|
|
|
|
auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
|
|
auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
|
|
BOOST_REQUIRE(!f2.available());
|
|
destroy(std::move(l1));
|
|
auto l2 = f2.get0();
|
|
auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
|
|
BOOST_REQUIRE(!f3.available());
|
|
destroy(std::move(l2));
|
|
auto l3 = f3.get0();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_schema_change) {
|
|
return seastar::async([&] {
|
|
auto destroy = [] (auto) { };
|
|
|
|
auto s1 = make_schema();
|
|
auto s2 = make_alternative_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s1, cl_stats);
|
|
|
|
auto m1 = make_mutation(s1, "0", { "s1", "s2", "s3"}, {
|
|
make_row("one", { "r1", "r2", "r3" }),
|
|
});
|
|
|
|
// disjoint with m1
|
|
auto m2 = make_mutation(s2, "0", { "s0", "s2.5"}, {
|
|
make_row("one", { "r0", "r2.5" }),
|
|
make_row("two", { "r1", "r3" }),
|
|
});
|
|
|
|
// overlaps with m1
|
|
auto m3 = make_mutation(s2, "0", { "s1" }, {
|
|
make_row("one", { "r1", "r3" }),
|
|
});
|
|
|
|
auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
|
|
|
|
destroy(std::move(m1));
|
|
destroy(std::move(s1));
|
|
cl.set_schema(s2);
|
|
|
|
auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
|
|
auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
|
|
BOOST_REQUIRE(!f3.available());
|
|
destroy(std::move(l1));
|
|
auto l3 = f3.get0();
|
|
|
|
auto s3 = make_schema_disjoint_with_others();
|
|
cl.set_schema(s3);
|
|
|
|
auto m4 = make_mutation(s3, "0", { "s8", "s9"}, {
|
|
make_row("one", { "r8", "r9" }),
|
|
make_row("two", { "r8", "r9" }),
|
|
});
|
|
auto l4 = cl.lock_cells(m4.decorated_key(), partition_cells_range(m4.partition()), no_timeout).get0();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_timed_out) {
|
|
return seastar::async([&] {
|
|
auto destroy = [] (auto) { };
|
|
|
|
auto s = make_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s, cl_stats);
|
|
|
|
auto m1 = make_mutation(s, "0", { "s1", "s2", "s3"}, {
|
|
make_row("one", { "r2", "r3" }),
|
|
});
|
|
auto m2 = make_mutation(s, "0", { }, {
|
|
make_row("one", { "r1", "r2" }),
|
|
});
|
|
|
|
auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
|
|
|
|
auto timeout = db::timeout_clock::now() - std::chrono::hours(1);
|
|
BOOST_REQUIRE_THROW(cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), timeout).get0(),
|
|
timed_out_error);
|
|
|
|
auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
|
|
BOOST_REQUIRE(!f2.available());
|
|
destroy(std::move(l1));
|
|
auto l2 = f2.get0();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_locker_stats) {
|
|
return seastar::async([&] {
|
|
auto destroy = [] (auto) { };
|
|
|
|
auto s = make_schema();
|
|
cell_locker_stats cl_stats;
|
|
cell_locker cl(s, cl_stats);
|
|
|
|
auto m1 = make_mutation(s, "0", { "s2", "s3" }, {
|
|
make_row("one", { "r1", "r2" }),
|
|
});
|
|
|
|
auto m2 = make_mutation(s, "0", { "s1", "s3" }, {
|
|
make_row("one", { "r2", "r3" }),
|
|
});
|
|
|
|
auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
|
|
BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 4);
|
|
BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);
|
|
|
|
auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
|
|
BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 5);
|
|
BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 1);
|
|
BOOST_REQUIRE(!f2.available());
|
|
|
|
destroy(std::move(l1));
|
|
destroy(f2.get0());
|
|
BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 8);
|
|
BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);
|
|
});
|
|
}
|