Compare commits

..

177 Commits

Author SHA1 Message Date
Yaron Kaikov
4ae9a56466 release: prepare for 4.0.11 2020-10-26 18:12:47 +02:00
Avi Kivity
0374c1d040 Update seastar submodule
* seastar 065a40b34a...748428930a (1):
  > append_challenged_posix_file_impl: allow destructing file with no queued work

Fixes #7285.
2020-10-19 15:06:24 +03:00
Botond Dénes
9cb0fe3b33 reader_permit: reader_resources: make true RAII class
Currently in all cases we first deduct the to-be-consumed resources,
then construct the `reader_resources` class to protect it (release it on
destruction). This is error prone as it relies on no exception being
thrown while constructing the `reader_resources`. Albeit the
`reader_resources` constructor is `noexcept` right now this might change
in the future and as the call sites relying on this are disconnected
from the declaration, the one modifying them might not notice.
To make this safe going forward, make the `reader_resources` a true RAII
class, consuming the units in its constructor and releasing them in its
destructor.

Refs: #7256

Tests: unit(dev)
Signed-off-by: Botond Dénes <bdenes@scylladb.com>
Message-Id: <20200922150625.1253798-1-bdenes@scylladb.com>
(cherry picked from commit a0107ba1c6)
Message-Id: <20200924081408.236353-1-bdenes@scylladb.com>
2020-10-19 15:05:13 +03:00
Takuya ASADA
a813ff4da2 install.sh: set LC_ALL=en_US.UTF-8 on python3 thunk
scylla-python3 causes segfault when non-default locale specified.
As workaround for this, we need to set LC_ALL=en_US.UTF_8 on python3 thunk.

Fixes #7408

Closes #7414

(cherry picked from commit ff129ee030)
2020-10-18 15:03:04 +03:00
Avi Kivity
d5936147f4 Merge "materialized views: Fix undefined behavior on base table schema changes" from Tomasz
"
The view_info object, which is attached to the schema object of the
view, contains a data structure called
"base_non_pk_columns_in_view_pk". This data structure contains column
ids of the base table so is valid only for a particular version of the
base table schema. This data structure is used by materialized view
code to interpret mutations of the base table, those coming from base
table writes, or reads of the base table done as part of view updates
or view building.

The base table schema version of that data structure must match the
schema version of the mutation fragments, otherwise we hit undefined
behavior. This may include aborts, exceptions, segfaults, or data
corruption (e.g. writes landing in the wrong column in the view).

Before this patch, we could get schema version mismatch here after the
base table was altered. That's because the view schema did not change
when the base table was altered.

Another problem was that view building was using the current table's schema
to interpret the fragments and invoke view building. That's incorrect for two
reasons. First, fragments generated by a reader must be accessed only using
the reader's schema. Second, base_non_pk_columns_in_view_pk of the recorded
view ptrs may not longer match the current base table schema, which is used
to generate the view updates.

Part of the fix is to extract base_non_pk_columns_in_view_pk into a
third entity called base_dependent_view_info, which changes both on
base table schema changes and view schema changes.

It is managed by a shared pointer so that we can take immutable
snapshots of it, just like with schema_ptr. When starting the view
update, the base table schema_ptr and the corresponding
base_dependent_view_info have to match. So we must obtain them
atomically, and base_dependent_view_info cannot change during update.

Also, whenever the base table schema changes, we must update
base_dependent_view_infos of all attached views (atomically) so that
it matches the base table schema.

Fixes #7061.

Tests:

  - unit (dev)
  - [v1] manual (reproduced using scylla binary and cqlsh)
"

* tag 'mv-schema-mismatch-fix-v2' of github.com:tgrabiec/scylla:
  db: view: Refactor view_info::initialize_base_dependent_fields()
  tests: mv: Test dropping columns from base table
  db: view: Fix incorrect schema access during view building after base table schema changes
  schema: Call on_internal_error() when out of range id is passed to column_at()
  db: views: Fix undefined behavior on base table schema changes
  db: views: Introduce has_base_non_pk_columns_in_view_pk()

(cherry picked from commit 3daa49f098)
2020-10-06 17:12:28 +03:00
Juliusz Stasiewicz
a3d3b4e185 tracing: Fix error on slow batches
`trace_keyspace_helper::make_slow_query_mutation_data` expected a
"query" key in its parameters, which does not appear in case of
e.g. batches of prepared statements. This is example of failing
`record.parameters`:
```
...{"query[0]" : "INSERT INTO ks.tbl (pk, i) values (?, ?);"},
{"query[1]" : "INSERT INTO ks.tbl (pk, i) values (?, ?);"}...
```

In such case Scylla recorded no trace and said:
```
ERROR 2020-09-28 10:09:36,696 [shard 3] trace_keyspace_helper - No
"query" parameter set for a session requesting a slow_query_log record
```

Fix here is to leave query empty if not found. The users can still
retrieve the query contents from existing info.

Fixes #5843

Closes #7293

(cherry picked from commit 0afa738a8f)
2020-10-04 18:05:00 +03:00
Tomasz Grabiec
4ca2576c98 Merge "evictable_reader: validate buffer on reader recreation" from Botond
This series backports the evictable reader validation patchset (merged
as 97c99ea9f to master) to 4.1.

I only had to do changes to the tests.

Tests: unit(dev), some exception safety tests are failing with or
without my patchset

Fixes: #7208

* https://github.com/denesb/scylla.git denesb/evictable-reader-validate-buffer/backport-4.1:
  mutation_reader_test: add unit test for evictable reader self-validation
  evictable_reader: validate buffer after recreation the underlying
  evictable_reader: update_next_position(): only use peek'd position on partition boundary
  mutation_reader_test: add unit test for evictable reader range tombstone trimming
  evictable_reader: trim range tombstones to the read clustering range
  position_in_partition_view: add position_in_partition_view before_key() overload
  flat_mutation_reader: add buffer() accessor

(cherry picked from commit 7f3ffbc1c8)
2020-10-02 11:52:57 +02:00
Tomasz Grabiec
e99a0c7b89 schema: Fix race in schema version recalculation leading to stale schema version in gossip
Migration manager installs several feature change listeners:

    if (this_shard_id() == 0) {
        _feature_listeners.push_back(_feat.cluster_supports_view_virtual_columns().when_enabled(update_schema));
        _feature_listeners.push_back(_feat.cluster_supports_digest_insensitive_to_expiry().when_enabled(update_schema));
        _feature_listeners.push_back(_feat.cluster_supports_cdc().when_enabled(update_schema));
        _feature_listeners.push_back(_feat.cluster_supports_per_table_partitioners().when_enabled(update_schema));
    }

They will call update_schema_version_and_announce() when features are enabled, which does this:

    return update_schema_version(proxy, features).then([] (utils::UUID uuid) {
        return announce_schema_version(uuid);
    });

So it first updates the schema version and then publishes it via
gossip in announce_schema_version(). It is possible that the
announce_schema_version() part of the first schema change will be
deferred and will execute after the other four calls to
update_schema_version_and_announce(). It will install the old schema
version in gossip instead of the more recent one.

The fix is to serialize schema digest calculation and publishing.

Fixes #7200

(cherry picked from commit 1a57d641d1)
2020-10-01 18:18:53 +02:00
Yaron Kaikov
f8c7605657 release: prepare for 4.0.10 2020-09-28 20:33:24 +03:00
Avi Kivity
7b9e33dcd4 Update seastar submodule
* seastar e87ce4941c...065a40b34a (1):
  > lz4_fragmented_compressor: Fix buffer requirements

Fixes #6925.
2020-09-23 12:07:11 +03:00
Yaron Kaikov
d86a31097a release: prepare for 4.0.9 2020-09-17 14:24:32 +03:00
Nadav Har'El
bd9d6f8e45 alternator: fix corruption of PutItem operation in case of contention
This patch fixes a bug noted in issue #7218 - where PutItem operations
sometimes lose part of the item's data - some attributes were lost,
and the name of other attributes replaced by empty strings. The problem
happened when the write-isolation policy was LWT and there was contention
of writes to the same partition (not necessarily the same item).

To use CAS (a.k.a. LWT), Alternator builds an alternator::rmw_operation
object with an apply() function which takes the old contents of the item
(if needed) and a timestamp, and builds a mutation that the CAS should
apply. In the case of the PutItem operation, we wrongly assumed that apply()
will be called only once - so as an optimization the strings saved in the
put_item_operation were moved into the returned mutation. But this
optimization is wrong - when there is contention, apply() may be called
again when the changed proposed by the previous one was not accepted by
the Paxos protocol.

The fix is to change the one place where put_item_operation *moved* strings
out of the saved operations into the mutations, to be a copy. But to prevent
this sort of bug from reoccuring in future code, this patch enlists the
compiler to help us verify that it can't happen: The apply() function is
marked "const" - it can use the information in the operation to build the
mutation, but it can never modify this information or move things out of it,
so it will be fine to call this function twice.

The single output field that apply() does write (_return_attributes) is
marked "mutable" to allow the const apply() to write to it anyway. Because
apply() might be called twice, it is important that if some apply()
implementation sometimes sets _return_attributes, then it must always
set it (even if to the default, empty, value) on every call to apply().

The const apply() means that the compiler verfies for us that I didn't
forget to fix additional wrong std::move()s. Additionally, a test I wrote
to easily reproduce issue #7218 (which I will submit as a dtest later)
passes after this fix.

Fixes #7218.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200916064906.333420-1-nyh@scylladb.com>
(cherry picked from commit 5e8bdf6877)
2020-09-16 23:05:23 +03:00
Benny Halevy
11ef23e97a test: cql_query_test: test_cache_bypass: use table stats
test is currently flaky since system reads can happen
in the background and disturb the global row cache stats.

Use the table's row_cache stats instead.

Fixes #6773

Test: cql_query_test.test_cache_bypass(dev, debug)

Credit-to: Botond Dénes <bdenes@scylladb.com>
Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
Message-Id: <20200811140521.421813-1-bhalevy@scylladb.com>
(cherry picked from commit 6deba1d0b4)
2020-09-16 18:20:30 +03:00
Asias He
2c0eac09ae migration_manager: Make sync_schema return error when node is down
sync_schema is supposed to make sure that this node knows about all
schema changes known by "nodes" that were made prior to this call.

Currently, when a node is down, the sync is sliently skipped.

To fix, add a flag to migration_task::run_may_throw to indicate that it
should fail if a node is down.

Fixes #4791

(cherry picked from commit 7ba821cbc0)
2020-09-16 16:01:44 +03:00
Dejan Mircevski
713a7269d0 cql3: Fix NULL reference in get_column_defs_for_filtering
There was a typo in get_column_defs_for_filtering(): it checked the
wrong pointer before dereferencing.  Add a test exposing the NULL
dereference and fix the typo.

Tests: unit (dev)

Fixes #7198.

Signed-off-by: Dejan Mircevski <dejan@scylladb.com>
(cherry picked from commit 9d02f10c71)
2020-09-16 15:47:09 +03:00
Avi Kivity
1724301d4d reconcilable_result_builder: don't aggrevate out-of-memory condition during recovery
Consider an unpaged query that consumes all of available memory, despite
fea5067dfa which limits them (perhaps the
user raised the limit, or this is a system query). Eventually we will see a
bad_alloc which will abort the query and destroy this reconcilable_result_builder.

During destruction, we first destroy _memory_accounter, and then _result.
Destroying _memory_accounter resumes some continuations which can then
allocate memory synchronously when increasing the task queue to accomodate
them. We will then crash. Had we not crashed, we would immediately afterwards
release _result, freeing all the memory that we would ever need.

Fix by making _result the last member, so it is freed first.

Fixes #7240.

(cherry picked from commit 9421cfded4)
2020-09-16 15:41:10 +03:00
Avi Kivity
9971f2f5db Merge "Fix repair stalls in get_sync_boundary and apply_rows_on_master_in_thread" from Asias
"
This path set fixes stalls in repair that are caused by std::list merge and clear operations during test_latency_read_with_nemesis test.

Fixes #6940
Fixes #6975
Fixes #6976
"

* 'fix_repair_list_stall_merge_clear_v2' of github.com:asias/scylla:
  repair: Fix stall in apply_rows_on_master_in_thread and apply_rows_on_follower
  repair: Use clear_gently in get_sync_boundary to avoid stall
  utils: Add clear_gently
  repair: Use merge_to_gently to merge two lists
  utils: Add merge_to_gently

(cherry picked from commit 4547949420)
2020-09-10 13:15:01 +03:00
Avi Kivity
ee328c22ca repair: apply_rows_on_follower(): remove copy of repair_rows list
We copy a list, which was reported to generate a 15ms stall.

This is easily fixed by moving it instead, which is safe since this is
the last use of the variable.

Fixes #7115.

(cherry picked from commit 6ff12b7f79)
2020-09-10 11:53:55 +03:00
Avi Kivity
3a9c9a8a12 Update seastar submodule
* seastar 861b7edd61...e87ce4941c (1):
  > core/reactor: complete_timers(): restore previous scheduling group

Fixes #7184.
2020-09-07 11:28:55 +03:00
Raphael S. Carvalho
c03445871a compaction: Prevent non-regular compaction from picking compacting SSTables
After 8014c7124, cleanup can potentially pick a compacting SSTable.
Upgrade and scrub can also pick a compacting SSTable.
The problem is that table::candidates_for_compaction() was badly named.
It misleads the user into thinking that the SSTables returned are perfect
candidates for compaction, but manager still need to filter out the
compacting SSTables from the returned set. So it's being renamed.

When the same SSTable is compacted in parallel, the strategy invariant
can be broken like overlapping being introduced in LCS, and also
some deletion failures as more than one compaction process would try
to delete the same files.

Let's fix scrub, cleanup and ugprade by calling the manager function
which gets the correct candidates for compaction.

Fixes #6938.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200811200135.25421-1-raphaelsc@scylladb.com>
(cherry picked from commit 11df96718a)
2020-09-06 18:41:12 +03:00
Takuya ASADA
565ac1b092 aws: update enhanced networking supported instance list
Sync enhanced networking supported instance list to latest one.

Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html

Fixes #6991

(cherry picked from commit 7cccb018b8)
2020-09-06 18:21:46 +03:00
Yaron Kaikov
7d1180b98f release: prepare for 4.0.8 2020-08-30 09:42:34 +03:00
Piotr Sarna
f258e6f6ee Merge 'counters: Fix filtering of counters' from Juliusz
Queries with `ALLOW FILTERING` and constraints on counter
values used to be rejected as "unimplemented". The reason
was a missing tri-comparator, which is added in this patch.

Fixes #5635

* jul-stas-5635-filtering-on-counters:
  cql/tests: Added test for filtering on counter columns
  counters: add comparator and remove `unimplemented` from restrictions

(cherry picked from commit c32faee657)
2020-08-27 18:42:30 +03:00
Avi Kivity
2708b0d664 Merge "repair: row_level: prevent deadlocks when repairing homogenous nodes" from Botond
"
This series backports the series "repair: row_level: prevent deadlocks
when repairing homogenous nodes" (merged as a9c7a1a86) to branch-4.1.
"

Fixes #6272

* 'repair-row-level-evictable-local-reader/branch-4.1' of https://github.com/denesb/scylla:
  repair: row_level: destroy reader on EOS or error
  repair: row_level: use evictable_reader for local reads
  mutation_reader: expose evictable_reader
  mutation_reader: evictable_reader: add auto_pause flag
  mutation_reader: make evictable_reader a flat_mutation_reader
  mutation_reader: s/inactive_shard_read/inactive_evictable_reader/
  mutation_reader: move inactive_shard_reader code up
  mutation_reader: fix indentation
  mutation_reader: shard_reader: extract remote_reader as evictable_reader
  mutation_reader: reader_lifecycle_policy: make semaphore() available early

(cherry picked from commit 59aa1834a7)
2020-08-27 17:44:27 +03:00
Asias He
e31ffbf2e6 compaction_manager: Avoid stall in perform_cleanup
The following stall was seen during a cleanup operation:

scylla: Reactor stalled for 16262 ms on shard 4.

| std::_MakeUniq<locator::tokens_iterator_impl>::__single_object std::make_unique<locator::tokens_iterator_impl, locator::tokens_iterator_impl&>(locator::tokens_iterator_impl&) at /usr/include/fmt/format.h:1158
|  (inlined by) locator::token_metadata::tokens_iterator::tokens_iterator(locator::token_metadata::tokens_iterator const&) at ./locator/token_metadata.cc:1602
| locator::simple_strategy::calculate_natural_endpoints(dht::token const&, locator::token_metadata&) const at simple_strategy.cc:?
|  (inlined by) locator::simple_strategy::calculate_natural_endpoints(dht::token const&, locator::token_metadata&) const at ./locator/simple_strategy.cc:56
| locator::abstract_replication_strategy::get_ranges(gms::inet_address, locator::token_metadata&) const at /usr/include/fmt/format.h:1158
| locator::abstract_replication_strategy::get_ranges(gms::inet_address) const at /usr/include/fmt/format.h:1158
| service::storage_service::get_ranges_for_endpoint(seastar::basic_sstring<char, unsigned int, 15u, true> const&, gms::inet_address const&) const at /usr/include/fmt/format.h:1158
| service::storage_service::get_local_ranges(seastar::basic_sstring<char, unsigned int, 15u, true> const&) const at /usr/include/fmt/format.h:1158
|  (inlined by) operator() at ./sstables/compaction_manager.cc:691
|  (inlined by) _M_invoke at /usr/include/c++/9/bits/std_function.h:286
| std::function<std::vector<seastar::lw_shared_ptr<sstables::sstable>, std::allocator<seastar::lw_shared_ptr<sstables::sstable> > > (table const&)>::operator()(table const&) const at /usr/include/fmt/format.h:1158
|  (inlined by) compaction_manager::rewrite_sstables(table*, sstables::compaction_options, std::function<std::vector<seastar::lw_shared_ptr<sstables::sstable>, std::allocator<seastar::lw_shared_ptr<sstables::sstable> > > (table const&)>) at ./sstables/compaction_manager.cc:604
| compaction_manager::perform_cleanup(table*) at /usr/include/fmt/format.h:1158

To fix, we furturize the function to get local ranges and sstables.

In addition, this patch removes the dependency to global storage_service object.

Fixes #6662

(cherry picked from commit 07e253542d)
2020-08-27 13:11:39 +03:00
Raphael S. Carvalho
801994e299 sstables: optimize procedure that checks if a sstable needs cleanup
needs_cleanup() returns true if a sstable needs cleanup.

Turns out it's very slow because it iterates through all the local
ranges for all sstables in the set, making its complexity:
	O(num_sstables * local_ranges)

We can optimize it by taking into account that abstract_replication_strategy
documents that get_ranges() will return a list of ranges that is sorted
and non-overlapping. Compaction for cleanup already takes advantage of that
when checking if a given partition can be actually purged.

So needs_cleanup() can be optimized into O(num_sstables * log(local_ranges)).

With num_sstables=1000, RF=3, then local_ranges=256(num_tokens)*3, it means
the max # of checks performed will go from 768000 to ~9584.

Fixes #6730.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200629171355.45118-2-raphaelsc@scylladb.com>
(cherry picked from commit cf352e7c14)
2020-08-27 13:11:37 +03:00
Raphael S. Carvalho
3b932078bf sstables: export needs_cleanup()
May be needed elsewhere, like in an unit test.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200629171355.45118-1-raphaelsc@scylladb.com>
(cherry picked from commit a9eebdc778)
2020-08-27 13:11:24 +03:00
Asias He
608f62a0e9 abstract_replication_strategy: Add get_ranges_in_thread
Add a version that runs inside a seastar thread. The benefit is that
get_ranges can yield to avoid stalls.

Refs #6662

(cherry picked from commit 94995acedb)
2020-08-27 13:10:32 +03:00
Asias He
d8619d3320 abstract_replication_strategy: Add get_ranges which takes token_metadata
It is useful when the caller wants to calculate ranges using a
custom token_metadata.

It will be used soon in do_rebuild_replace_with_repair for replace
operation.

Refs: #5482
(cherry picked from commit b640614aa6)
2020-08-27 13:10:26 +03:00
Asias He
4f0c99a187 gossip: Fix race between shutdown message handler and apply_state_locally
1. The node1 is shutdown
2. The node1 sends shutdown message to node2
3. The node2 receives gossip shutdown message but the handler yields
4. The node1 is restarted
5. The node1 sends new gossip endpoint_state to node2, node2 applies the state
   in apply_state_locally and calls gossiper::handle_major_state_change
   and then calls gossiper::mark_alive
6. The shutdown message handler in step 3 resumes and sets status of node1 to SHUTDOWN
7. The gossiper::mark_alive fiber in step 5 resumes and calls gossiper::real_mark_alive,
   node2 will skip to mark node1 as alive because the status of node1 is
   SHUTDOWN. As a result, node1 is alive but it is not marked as UP by node2.

To fix, we serialize the two operations.

Fixes #7032

(cherry picked from commit e6ceec1685)
2020-08-27 11:16:10 +03:00
Nadav Har'El
ada79df082 alternator test: configurable temporary directory
The test/alternator/run script creates a temporary directory for the Scylla
database in /tmp. The assumption was that this is the fastest disk (usually
even a ramdisk) on the test machine, and we didn't need anything else from
it.

But it turns out that on some systems, /tmp is actually a slow disk, so
this patch adds a way to configure the temporary directory - if the TMPDIR
environment variable exists, it is used instead of /tmp. As before this
patch, a temporary subdirectry is created in $TMPDIR, and this subdirectory
is automatically deleted when the test ends.

The test.py script already passes an appropriate TMPDIR (testlog/$mode),
which after this patch the Alternator test will use instead of /tmp.

Fixes #6750

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200713193023.788634-1-nyh@scylladb.com>
(cherry picked from commit 8e3be5e7d6)
2020-08-26 19:48:45 +03:00
Nadav Har'El
1935f2b480 alternator: fix order conditions on binary attributes
We implemented the order operators (LT, GT, LE, GE, BETWEEN) incorrectly
for binary attributes: DynamoDB requires that the bytes be treated as
unsigned for the purpose of order (so byte 128 is higher than 127), but
our implementation uses Scylla's "bytes" type which has signed bytes.

The solution is simple - we can continue to use the "bytes" type, but
we need to use its compare_unsigned() function, not its "<" operator.

This bug affected conditional operations ("Expected" and
"ConditionExpression") and also filters ("QueryFilter", "ScanFilter",
"FilterExpression"). The bug did *not* affect Query's key conditions
("KeyConditions", "KeyConditionExpression") because those already
used Scylla's key comparison functions - which correctly compare binary
blobs as unsigned bytes (in fact, this is why we have the
compare_unsigned() function).

The patch also adds tests that reproduce the bugs in conditional
operations, and show that the bug did not exist in key conditions.

Fixes #6573

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200603084257.394136-1-nyh@scylladb.com>
(cherry picked from commit f6b1f45d69)
Manyally removed tests in test_key_conditions.py which didn't exist in this branch.
2020-08-26 19:28:47 +03:00
Avi Kivity
44a76ed231 Merge "Unregister RPC verbs on stop" from Pavel E
"
There are 5 services, that register their RPC handlers in messaging
service, but quite a few of them unregister them on stop.

Unregistering is somewhat critical, not just because it makes the
code look clean, but also because unregistration does wait for the
message processing to complete, thus avoiding use-after-free's in
the handlers.

In particular, several handlers call service::get_schema_for_write()
which, in turn, may end up in service::maybe_sync() calling for
the local migration manager instance. All those handlers' processing
must be waited for before stopping the migration manager.

The set brings the RPC handlers unregistration in sync with the
registration part.

tests: unit (dev)
       dtest (dev: simple_boot_shutdown, repair)
       start-stop by hands (dev)
fixes: #6904
"

* 'br-rpc-unregister-verbs' of https://github.com/xemul/scylla:
  main: Add missing calls to unregister RPC hanlers
  messaging: Add missing per-service unregistering methods
  messaging: Add missing handlers unregistration helpers
  streaming: Do not use db->invoke_on_all in vain
  storage_proxy: Detach rpc unregistration from stop
  main: Shorten call to storage_proxy::init_messaging_service

(cherry picked from commit 01b838e291)
2020-08-26 14:42:40 +03:00
Raphael S. Carvalho
aeb49f4915 cql3/statements: verify that counter column cannot be added into non-counter table
A check, to validate that counter column cannot be added into non-counter table,
is missing for alter table statement. Validation is performed when building new
schema, but it's limited to checking that a schema will not contain both counter
and non-counter columns.

Due to lack of validation, the added counter column could be incorrectly
persisted to the schema, but this results in a crash when setting the new
schema to its table. On restart, it can be confirmed that the schema change
was indeed persisted when describing the table.
This problem is fixed by doing proper validation for the alter table statement,
which consists of making sure a new counter column cannot be added to a
non-counter table.

The test cdc_disallow_cdc_for_counters_test is adjusted because one of its tests
was built on the assumption that counter column can be added into a non-counter
table.

Fixes #7065.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200824155709.34743-1-raphaelsc@scylladb.com>
(cherry picked from commit 1c29f0a43d)
2020-08-25 18:46:01 +03:00
Gleb Natapov
8d6b35ad20 lwt: fix possible leak of "prune" counter
If get_schema_for_read() fails "prune" counter will not be decremented.
The patch fixes it by creating RAI object earlier. Also return releasing
of a mutation in release_mutation() which was dropped by mistake.

Fixes #6124

Message-Id: <20200405080233.GA22509@scylladb.com>
(cherry picked from commit e5f7ccc4c8)
2020-08-23 19:29:06 +03:00
Takuya ASADA
b123700ebe dist/debian: disable debuginfo compression on .deb
Since older binutils on some distribution does not able to handle
compressed debuginfo generated on Fedora, we need to disable it.
However, debian packager force debuginfo compression since debian/compat = 9,
we have to uncompress them after compressed automatically.

Fixes #6982

(cherry picked from commit 75c2362c95)
2020-08-23 19:03:13 +03:00
Botond Dénes
6786b521f9 scylla-gdb.py: find_db(): don't return current shard's database for shard=0
The `shard` parameter of `find_db()` is optional and is defaulted to
`None`. When missing, the current shard's database instance is returned.
The problem is that the if condition checking this uses `not shard`,
which also evaluates to `True` if `shard == 0`, resulting in returning
the current shard's database instance for shard 0. Change the condition
to `shard is None` to avoid this.

Fixes: #7016
Signed-off-by: Botond Dénes <bdenes@scylladb.com>
Message-Id: <20200812091546.1704016-1-bdenes@scylladb.com>
(cherry picked from commit 4cfab59eb1)
2020-08-23 18:56:39 +03:00
Botond Dénes
fda0d1ae8e table: get_sstables_by_partition_key(): don't make a copy of selected sstables
Currently we assign the reference to the vector of selected sstables to
`auto sst`. This makes a copy and we pass this local variable to
`do_for_each()`, which will result in a use-after-free if the latter
defers.
Fix by not making a copy and instead just keep the reference.

Fixes: #7060

Tests: unit(dev)
Signed-off-by: Botond Dénes <bdenes@scylladb.com>
Message-Id: <20200818091241.2341332-1-bdenes@scylladb.com>
(cherry picked from commit 78f94ba36a)
2020-08-19 00:02:22 +03:00
Yaron Kaikov
e7cffb978a release: prepare for 4.0.7 2020-08-17 00:38:43 +03:00
Benny Halevy
79a1c74921 db::commitlog: close file if wrapping failed
When I/O error (e.g. EMFILE / ENOSPC) happens we hit
an assert in ~append_challenged_posix_file_impl(): Assertion _closing_state == state::closed' failed.

Commit 6160b9017d add close on failure
of the lamda defined in allocate_segment_ex, but it doesn't handle an error
after the file is opened/created while it is wrapped with commitlog_file_extensions.

Refs #5657

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
Reviewed-by: Calle Wilund <calle@scylladb.com>
Message-Id: <20200414115231.298632-1-bhalevy@scylladb.com>
(cherry picked from commit 35892e4557)
2020-08-16 19:58:23 +03:00
Calle Wilund
3ee854f9fc cdc::log: Missing "preimage" check in row deletion pre-image
Fixes #6561

Pre-image generation in row deletion case only checked if we had a pre-image
result set row. But that can be from post-image. Also check actual existance
of the pre-image CK.
Message-Id: <20200608132804.23541-1-calle@scylladb.com>

(cherry picked from commit 5105e9f5e1)
2020-08-12 13:55:10 +03:00
Avi Kivity
2b65984d14 Merge "Fix GCC-10 related bugs and fix deletion of temporary garbage-collected sstables" from Raphael
"
Temporary garbage-collected SSTables, involved in the incremental
compaction process which can be enabled for LCS, were incorrectly
invalidating the cache when added to the set of SSTables. Also, those
same temporary SSTables could be incorrectly removed, causing deletion
warnings. The patchset "Don't invalidate row cache when adding GC
SSTable" fixes those two issues by using the SSTable replacement
mechanism, which is the correct method for replacing SSTables in the
set.
"

* 'backport_fix_issue_6275_for_branch_4_0' of github.com:raphaelsc/scylla:
  row_cache_alloc_stress_test: Make sure GCC can't delete a new
  tests: Wait for a few futures
  sstables/compaction: Don't invalidate row cache when adding GC SSTable to SSTable set
  sstables/compaction: Change meaning of compaction_completion_desc input and output fields
  sstables/compaction: Clean up code around garbage_collected_sstable_writer
  compaction: enhance compaction_descriptor with creator and replace function
2020-08-11 18:16:41 +03:00
Nadav Har'El
52d1099d09 Update Seastar submodule
> http: add "Expect: 100-continue" handling

Fixes #6844
2020-08-11 13:33:45 +03:00
Asias He
3a03906377 repair: Switch to btree_set for repair_hash.
In one of the longevity tests, we observed 1.3s reactor stall which came from
repair_meta::get_full_row_hashes_source_op. It traced back to a call to
std::unordered_set::insert() which triggered big memory allocation and
reclaim.

I measured std::unordered_set, absl::flat_hash_set, absl::node_hash_set
and absl::btree_set. The absl::btree_set was the only one that seastar
oversized allocation checker did not warn in my tests where around 300K
repair hashes were inserted into the container.

- unordered_set:
hash_sets=295634, time=333029199 ns

- flat_hash_set:
hash_sets=295634, time=312484711 ns

- node_hash_set:
hash_sets=295634, time=346195835 ns

- btree_set:
hash_sets=295634, time=341379801 ns

The btree_set is a bit slower than unordered_set but it does not have
huge memory allocation. I do not measure real difference of total time
to finish repair of the same dataset with unordered_set and btree_set.

To fix, switch to absl btree_set container.

Fixes #6190

(cherry picked from commit 67f6da6466)
(cherry picked from commit a27188886a)
2020-08-11 12:35:34 +03:00
Rafael Ávila de Espíndola
2395a240b4 build: Link with abseil
It is a pity we have to list so many libraries, but abseil doesn't
provide a .pc file.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
(cherry picked from commit 7d1f6725dd)

Ref #6190.
2020-08-11 12:35:32 +03:00
Rafael Ávila de Espíndola
d182c595a1 Add abseil as a submodule
This adds the https://abseil.io library as a submodule. The patch
series that follows needs a hash table that supports heterogeneous
lookup, and abseil has a really good hash table that supports that
(https://abseil.io/blog/20180927-swisstables).

The library is still not available in Fedora, but it is fairly easy to
use it directly from a submodule.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
(cherry picked from commit 383a9c6da9)

Ref #6190
2020-08-11 12:35:31 +03:00
Rafael Ávila de Espíndola
fe9c4611b3 cofigure: Don't overwrite seastar_cflags
The variable seastar_cflags was being used for flags passed to seastar
and for flags extracted from the seastar.pc file.

This introduces a new variable for the flags extracted from the
seastar.pc file.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
(cherry picked from commit 2ad09aefb6)

Ref #6190.
2020-08-11 12:35:28 +03:00
Calle Wilund
29df416720 database: Do not assert on replay positions if truncate does not flush
Fixes #6995

In c2c6c71 the assert on replay positions in flushed sstables discarded by
truncate was broken, by the fact that we no longer flush all sstables
unless auto snapshot is enabled.

This means the low_mark assertion does not hold, because we maybe/probably
never got around to creating the sstables that would hold said mark.

Note that the (old) change to not create sstables and then just delete
them is in itself good. But in that case we should not try to verify
the rp mark.

(cherry picked from commit 9620755c7f)
2020-08-10 23:28:00 +03:00
Nadav Har'El
1d3c00572c Update Seastar submodule with some backported fixes
Fixes #7008
  > futures_test: Don't use * on an optional without a value
  > net: Use offsetof instead of accessing a null pointer
  > allocator_test: Avoid undefined conversion
  > http: Don't use moved value
  > circular_buffer_fixed_capacity_test: Fix indentation
  > circular_buffer_fixed_capacity: Always mask indexes
  > rpc: Fix a use-after-return
2020-08-10 20:39:35 +03:00
Avi Kivity
9d6e2c5a71 Update seastar submodule
* seastar 4ee384e15f...2dbd81d5db (1):
  > memory: fix small aligned free memory corruption

Fixes #6831
2020-08-09 18:39:01 +03:00
Pavel Emelyanov
386741e3b7 storage_proxy_stats: Make get_ep_stat() noexcept
The .get_ep_stat(ep) call can throw when registering metrics (we have
issue for it, #5697). This is not expected by it callers, in particular
abstract_write_response_handler::timeout_cb breaks in the middle and
doesn't call the on_timeout() and the _proxy->remove_response_handler(),
which results in not removed and not released responce handler. In turn
not released response handler doesn't set the _ready future on which
response_wait() waits -> stuck.

Although the issue with .get_ep_stat() should be fixed, an exception in
it mustn't lead to deadlocks, so the fix is to make the get_ep_stat()
noexcept by catching the exception and returning a dummy stat object
instead to let caller(s) finish.

Fixes #5985
Tests: unit(dev)

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
Message-Id: <20200430163639.5242-1-xemul@scylladb.com>
(cherry picked from commit 513ce1e6a5)
2020-08-09 18:18:50 +03:00
Avi Kivity
d0fdc3960a Merge 'hinted handoff: fix commitlog memory leak' from Piotr D
"
When commitlog is recreated in hints manager, only shutdown() method is
called, but not release(). Because of that, some internal commitlog
objects (`segment_manager` and `segment`s) may be left pointing to each
other through shared_ptr reference cycles, which may result in memory
leak when the parent commitlog object is destroyed.

This PR prevents memory leaks that may happen this way by calling
release() after shutdown() from the hints manager.

Fixes: #6409, Fixes #6776
"

* piodul-fix-commitlog-memory-leak-in-hinted-handoff:
  hinted handoff: disable warnings about segments left on disk
  hinted handoff: release memory on commitlog termination

(cherry picked from commit 4c221855a1)
2020-08-09 17:26:17 +03:00
Tomasz Grabiec
4035cf4f9f thrift: Fix crash on unsorted column names in SlicePredicate
The column names in SlicePredicate can be passed in arbitrary order.
We converted them to clustering ranges in read_command preserving the
original order. As a result, the clustering ranges in read command may
appear out of order. This violates storage engine's assumptions and
lead to undefined behavior.

It was seen manifesting as a SIGSEGV or an abort in sstable reader
when executing a get_slice() thrift verb:

scylla: sstables/consumer.hh:476: seastar::future<> data_consumer::continuous_data_consumer<StateProcessor>::fast_forward_to(size_t, size_t) [with StateProcessor = sstables::data_consume_rows_context_m; size_t = long unsigned int]: Assertion `end >= _stream_position.position' failed.

Fixes #6486.

Tests:

   - added a new dtest to thrift_tests.py which reproduces the problem

Message-Id: <1596725657-15802-1-git-send-email-tgrabiec@scylladb.com>
(cherry picked from commit bfd129cffe)
2020-08-08 19:48:46 +03:00
Rafael Ávila de Espíndola
09367742b1 row_cache_alloc_stress_test: Make sure GCC can't delete a new
We want to test that a std::bad_alloc is thrown, but GCC 10 has a new
optimization (-fallocation-dce) that removes dead allocations.

This patch assigns the value returned by new to a global so that GCC
cannot delete it.

With this all tests in a dev build pass with GCC 10.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200424201531.225807-1-espindola@scylladb.com>
(cherry picked from commit 0d89bbd57f)
2020-08-07 16:49:33 -03:00
Rafael Ávila de Espíndola
a18ff57b29 tests: Wait for a few futures
GCC 10 now warns on these. This fixes the dev build with gcc 10.

backport note: remove unneeded change which is not compatible
with the branch in error_injection_test.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200424161006.17857-1-espindola@scylladb.com>
(cherry picked from commit 543a9ebd9b)
2020-08-07 16:32:12 -03:00
Raphael S. Carvalho
4734ba21a7 sstables/compaction: Don't invalidate row cache when adding GC SSTable to SSTable set
Garbage collected SSTable is incorrectly added to SSTable set with a function
that invalidates row cache. This problem is fixed by adding GC SStable
to set using mechanism which replaces old sstables with new sstables.

Also, adding GC SSTable to set in a separate call is not correct.
We should make sure that GC SSTable reaches the SSTable set at the same time
its respective old (input) SSTable is removed from the set, and that's done
using a single request call to table.

Fixes #5956.
Fixes #6275.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
(cherry picked from commit a214ccdf89)
2020-08-06 19:08:46 -03:00
Raphael S. Carvalho
425af4c543 sstables/compaction: Change meaning of compaction_completion_desc input and output fields
input_sstables is renamed to old_sstables and is about old SSTables that should be
deleted and removed from the SSTable set.
output_sstables is renamed to new_sstables and is about new SSTable that should be
added to the SSTable set, replacing the old ones.

This will allow us, for example, to add auxiliary SSTables to SSTable set using
the same call which replaces output SSTables by input SSTables in compaction.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
(cherry picked from commit 8f4458f1d5)
2020-08-06 18:51:21 -03:00
Raphael S. Carvalho
55f096d01b sstables/compaction: Clean up code around garbage_collected_sstable_writer
This cleanup allows us to get rid of the ugly compaction::create_new_sstable(),
and reduce complexity by getting rid of observable.

garbage_collected_sstable_writer::data is introduced to allow compaction to
directly communicate with the GC writer, which is stored in mutation_compaction,
making it unreachable after the compaction has started. By making compaction
store GC writer's data and using that same data to create g__c__s__w,
compaction is able to communicate with GC writer without the complexity of
observable utility. This move is important for the subsequent work which
will fix a couple of issues regarding management of GC SSTables.

[Backport note: there were a few conflicts as this patch was written after
interposer consumer, but the conflicts weren't hard to solve]

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
(cherry picked from commit cc5e0d8da8)
2020-08-06 18:01:12 -03:00
Glauber Costa
fc79da5912 compaction: enhance compaction_descriptor with creator and replace function
There are many differences between resharding and compaction that are
artificial, arising more from the way we ended up implementing it than
necessity. This patch attempts to pass the creator and replacer functions
through the compaction_descriptor.

There is a difference between the creator function for resharding and
regular compaction: resharding has to pass the shard number on behalf
of which the SSTable is created. However regular compactions can just
ignore this. No need to have a special path just for this.

After this is done, the constructor for the compaction object can be
greatly simplified. In further patches I intend to simplify it a bit
further, but some more cleanup has to happen first.

To make that happen we have to construct a compaction_descriptor object
inside the resharding function. This is temporary: resharding currently
works with a descriptor, but at some point that descriptor is lost and
broken into pieces to be passed to this function. The overarching goal
of this work is exactly to be able to keep that descriptor for as long
as possible, which should simplify things a lot.

Callers are patched, but there are plenty for sstable_datafile_test.cc.
For their benefit, a helper function is provided to keep the previous
signature (test only).

Signed-off-by: Glauber Costa <glauber@scylladb.com>
(cherry picked from commit e8801cd77b)
2020-08-06 17:45:40 -03:00
Yaron Kaikov
da9e7080ca release: prepare for 4.0.6 2020-08-06 14:18:11 +03:00
Takuya ASADA
01b0195c22 scylla_util.py: always use relocatable CLI tools
On some CLI tools, command options may different between latest version
vs older version.
To maximize compatibility of setup scripts, we should always use
relocatable CLI tools instead of distribution version of the tool.

Related #6954

(cherry picked from commit a19a62e6f6)
2020-08-03 10:42:14 +03:00
Takuya ASADA
d05b567a40 create-relocatable-package.py: add lsblk for relocatable CLI tools
We need latest version of lsblk that supported partition type UUID.

Fixes #6954

(cherry picked from commit 6ba2a6c42e)
2020-08-03 10:42:12 +03:00
Juliusz Stasiewicz
2c11efbbae aggregate_fcts: Use per-type comparators for dynamic types
For collections and UDTs the `MIN()` and `MAX()` functions are
generated on the fly. Until now they worked by comparing just the
byte representations of arguments.

This patch uses specific per-type comparators to provide semantically
sensible, dynamically created aggregates.

Fixes #6768

(cherry picked from commit 5b438e79be)
2020-08-03 10:26:28 +03:00
Calle Wilund
c60d71dc69 cql3::lists: Fix setter_by_uuid not handing null value
Fixes #6828

When using the scylla list index from UUID extension,
null values were not handled properly causing throws
from underlying layer.

(cherry picked from commit 3b74b9585f)
2020-08-03 10:20:28 +03:00
Takuya ASADA
79930048db scylla_post_install.sh: generate memory.conf for CentOS7
On CentOS7, systemd does not support percentage-based parameter.
To apply memory parameter on CentOS7, we need to override the parameter
in bytes, instead of percentage.

Fixes #6783

(cherry picked from commit 3a25e7285b)
2020-07-30 16:41:40 +03:00
Tomasz Grabiec
82b4f4a6c2 commitlog: Fix use-after-free on mutation object during replay
The mutation object may be freed prematurely during commitlog replay
in the schema upgrading path. We will hit the problem if the memtable
is full and apply_in_memory() needs to defer.

This will typically manifest as a segfault.

Fixes #6953

Introduced in 79935df

Tests:
  - manual using scylla binary. Reproduced the problem then verified the fix makes it go away

Message-Id: <1596044010-27296-1-git-send-email-tgrabiec@scylladb.com>
(cherry picked from commit 3486eba1ce)
2020-07-30 16:37:08 +03:00
Avi Kivity
5b99195d21 dist: debian: do not require root during package build
Debian package builds provide a root environment for the installation
scripts, since that's what typical installation scripts expect. To
avoid providing actual root, a "fakeroot" system is used where syscalls
are intercepted and any effect that requires root (like chown) is emulated.

However, fakeroot sporadically fails for us, aborting the package build.
Since our install scripts don't really require root (when operating in
the --packaging mode), we can just tell dpkg-buildpackage that we don't
need fakeroot. This ought to fix the sporadic failures.

As a side effect, package builds are faster.

Fixes #6655.

(cherry picked from commit b608af870b)
2020-07-29 16:03:53 +03:00
Takuya ASADA
edde256228 scylla_setup: skip boot partition
On GCE, /dev/sda14 reported as unused disk but it's BIOS boot partition,
should not use for scylla data partition, also cannot use for it since it's
too small.

It's better to exclude such partiotion from unsed disk list.

Fixes #6636

(cherry picked from commit d7de9518fe)
2020-07-29 09:51:05 +03:00
Asias He
3cf28ac18e repair: Fix race between create_writer and wait_for_writer_done
We saw scylla hit user after free in repair with the following procedure during tests:

- n1 and n2 in the cluster

- n2 ran decommission

- n2 sent data to n1 using repair

- n2 was killed forcely

- n1 tried to remove repair_meta for n1

- n1 hit use after free on repair_meta object

This was what happened on n1:

1) data was received -> do_apply_rows was called -> yield before create_writer() was called

2) repair_meta::stop() was called -> wait_for_writer_done() / do_wait_for_writer_done was called
   with _writer_done[node_idx] not engaged

3) step 1 resumed, create_writer() was called and _repair_writer object was referenced

4) repair_meta::stop() finished, repair_meta object and its member _repair_writer was destroyed

5) The fiber created by create_writer() at step 3 hit use after free on _repair_writer object

To fix, we should call wait_for_writer_done() after any pending
operations were done which were protected by repair_meta::_gate. This
prevents wait for writer done finishes before the writer is in the
process of being created.

Fixes: #6853
Fixes: #6868
Backports: 4.0, 4.1, 4.2
(cherry picked from commit e6f640441a)
2020-07-29 09:51:02 +03:00
Raphael S. Carvalho
58b65f61c0 sstable: index_reader: Make sure streams are all properly closed on failure
Turns out the fix f591c9c710 wasn't enough to make sure all input streams
are properly closed on failure.
It only closes the main input stream that belongs to context, but it misses
all the input streams that can be opened in the consumer for promote index
reading. Consumer stores a list of indexes, where each of them has its own
input stream. On failure, we need to make sure that every single one of
them is properly closed before destroying the indexes as that could cause
memory corruption due to read ahead.

Fixes #6924.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200727182214.377140-1-raphaelsc@scylladb.com>
(cherry picked from commit 0d70efa58e)
2020-07-29 09:50:48 +03:00
Yaron Kaikov
466cfb0ca6 release: prepare for 4.0.5 2020-07-28 09:13:02 +03:00
Raphael S. Carvalho
1cd6f50806 table: Fix Staging SSTables being incorrectly added or removed from the backlog tracker
Staging SSTables can be incorrectly added or removed from the backlog tracker,
after an ALTER TABLE or TRUNCATE, because the add and removal don't take
into account if the SSTable requires view building, so a Staging SSTable can
be added to the tracker after a ALTER table, or removed after a TRUNCATE,
even though not added previously, potentially causing the backlog to
become negative.

Fixes #6798.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200716180737.944269-1-raphaelsc@scylladb.com>
(cherry picked from commit b67066cae2)
2020-07-21 12:57:41 +03:00
Asias He
3f6fe7328a repair: Relax size check of get_row_diff and set_diff
In case a row hash conflict, a hash in set_diff will get more than one
row from get_row_diff.

For example,

Node1 (Repair master):
row1  -> hash1
row2  -> hash2
row3  -> hash3
row3' -> hash3

Node2 (Repair follower):
row1  -> hash1
row2  -> hash2

We will have set_diff = {hash3} between node1 and node2, while
get_row_diff({hash3}) will return two rows: row3 and row3'. And the
error below was observed:

   repair - Got error in row level repair: std::runtime_error
   (row_diff.size() != set_diff.size())

In this case, node1 should send both row3 and row3' to peer node
instead of fail the whole repair. Because node2 does not have row3 or
row3', otherwise node1 won't send row with hash3 to node1 in the first
place.

Refs: #6252
(cherry picked from commit a00ab8688f)
2020-07-15 14:49:29 +03:00
Hagit Segev
f9dd8608eb release: prepare for 4.0.4 2020-07-14 14:10:39 +03:00
Avi Kivity
24a80cbf47 Update seastar submodule
* seastar a73b92ff2e...4ee384e15f (2):
  > futures: Add a test for a broken promise in a parallel_for_each
  > future: Call set_to_broken_promise earlier

Fixes #6749 (probably)
2020-07-13 20:32:27 +03:00
Dmitry Kropachev
6e4edc97ad dist/common/scripts/scylla-housekeeping: wrap urllib.request with try ... except
We could hit "cannot serialize '_io.BufferedReader' object" when request get 404 error from the server
	Now you will get legit error message in the case.

	Fixes #6690

(cherry picked from commit de82b3efae)
2020-07-09 18:25:35 +03:00
Dejan Mircevski
81df28b6f3 cql/restrictions: Handle WHERE a>0 AND a<0
WHERE clauses with start point above the end point were handled
incorrectly.  When the slice bounds are transformed to interval
bounds, the resulting interval is interpreted as wrap-around (because
start > end), so it contains all values above 0 and all values below
0.  This is clearly incorrect, as the user's intent was to filter out
all possible values of a.

Fix it by explicitly short-circuiting to false when start > end.  Add
a test case.

Fixes #5799.

Tests: unit (dev)

Signed-off-by: Dejan Mircevski <dejan@scylladb.com>
(cherry picked from commit 921dbd0978)
2020-07-08 13:25:06 +03:00
Juliusz Stasiewicz
ea6620e9eb counters: Read the state under timeout
Counter update is a RMW operation. Until now the "Read" part was
not guarded by a timeout, which is changed in this patch.

Fixes #5069

(cherry picked from commit e04fd9f774)
2020-07-07 20:45:26 +03:00
Takuya ASADA
19be84dafd scylla_setup: don't add same disk device twice
We shouldn't accept adding same disk twice for RAID prompt.

Fixes #6711

(cherry picked from commit 835e76fdfc)
2020-07-07 13:08:36 +03:00
Pavel Emelyanov
2ff897d351 main: Keep feature_service for storage_proxy
Fixes #6250

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
Message-Id: <20200423165608.32419-1-xemul@scylladb.com>
(cherry picked from commit 98635b74a6)
2020-07-07 12:42:52 +03:00
Botond Dénes
8fc3300739 sstables: sstable_reader: fix read range upper bound calculation for reverse slices
The single-key sstable reader uses the clustering ranges from the slice
to determine the upper bound of the disk read-range using the index.
For this is simply uses the end bound of the last clustering ranges. For
reverse reads however the clustering ranges in the slice are in reverse
order, so this will in fact be the upper bound of the smallest range.
Depending on whether the distance between the clustering range is big
enough for the sstable reader to use the index to skip between them,
this will lead to either reading too little data or an assert failure.

This patch fixes the problematic function `get_slice_upper_bound()` to
consider reverse reads as well.

Initially I thought there will be more mishandling of reverse slices,
but actually `mutation_fragment_filter`, the component doing the actual
slicing of rows, is already reverse-slice aware.

A unit test which reproduces the assert failure is also added.

Fixes: #6171

Signed-off-by: Botond Dénes <bdenes@scylladb.com>
Message-Id: <20200507114956.271799-1-bdenes@scylladb.com>
(cherry picked from commit 791acc7f38)
2020-07-05 16:02:15 +03:00
Raphael S. Carvalho
d2ac7d4b18 compaction: Fix partition estimation with TWCS interposer
Max and min windows are microsecond timestamps, which should be divided
by window size in microseconds to properly estimate window count
based on provided mutation_source_metadata.

Found this problem after properly setting mutation_source_metadata with
min and max metadata on behalf of regular compaction.

Fixes #6214.
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200409194235.6004-2-raphaelsc@scylladb.com>
(cherry picked from commit 3edff36cd2)
2020-07-05 15:27:40 +03:00
Avi Kivity
61706a6789 Update seastar submodule
* seastar 0dc0fec831...a73b92ff2e (1):
  > rpc::compressor: Fix static init fiasco with names

Fixes #5963
2020-07-02 18:08:52 +03:00
Piotr Sarna
65aa531010 db: set gc grace period to 0 for local system tables
Local system tables from `system` namespace use LocalStrategy
replication, so they do not need to be concerned about gc grace
period. Some system tables already set gc grace period to 0,
but other ones, including system.large_partitions, did not.
That may result in millions of tombstones being needlessly
kept for these tables, which can cause read timeouts.

Fixes #6325
Tests: unit(dev), local(running cqlsh and playing with system tables)

(cherry picked from commit bf5f247bc5)
2020-07-01 13:13:57 +03:00
Benny Halevy
4bffd0f522 api: storage_service: serialize true_snapshot_size
Following up on 91b71a0b1a
We also need to serialize storage_service::true_snapshots_size
with snapshot-modifying operations.

It seems like it was assumed that get_snapshot_details
is done under run_snapshot_list_operation, but the one called
here is the table method, not the api::storage_service::get_snapshot_details.

Fixes #5603

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
Message-Id: <20200506115732.483966-1-bhalevy@scylladb.com>
(cherry picked from commit 682fb3acfd)
2020-07-01 13:09:43 +03:00
Rafael Ávila de Espíndola
9409fc7290 gms: Don't keep references to reallocated vector entries
These callbacks can block a seastar thread and the underlying vector
can be reallocated concurrently.

This is no different than if it was a plain std::vector and the
solution is similar: use values instead of references.

Fixes #6230

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200422182304.120906-1-espindola@scylladb.com>
(cherry picked from commit d8555513a9)
2020-07-01 12:58:56 +03:00
Pavel Solodovnikov
86faf1b3ca cql3: avoid using shared_ptr's in unrecognized_entity_exception
Using shared_ptr's in `unrecognized_entity_exception` can lead
to cross-cpu deletion of a pointer which will trigger an assert
`_cpu == std::this_thread::get_id()' when shared_ptr is disposed.

Copy `column_identifier` to the exception object and avoid using
an instance of `cql3::relation`: just get a string representation
from it since nothing more is used in associated exception
handling code.

Fixes: #6287
Tests: unit(dev, debug), dtest(lwt_destructive_ddl_test.py:LwtDestructiveDDLTest.test_rename_column)

Signed-off-by: Pavel Solodovnikov <pa.solodovnikov@scylladb.com>
Message-Id: <20200506155714.150497-1-pa.solodovnikov@scylladb.com>
(cherry picked from commit 1d3f9174c5)
2020-07-01 12:54:09 +03:00
Raphael S. Carvalho
426295bda9 compaction: Fix the 2x disk space requirement in SSTable upgrade
SSTable upgrade is requiring 2x the space of input SSTables because
we aren't releasing references of the SSTables that were already
upgraded. So if we're upgrading 1TB, it means that up to 2TB may be
required for the upgrade operation to succeed.

That can be fixed by moving all input SSTables when rewrite_sstables()
asks for the set of SSTables to be compacted, so allowing their space
to be released as soon as there is no longer any ref to them.

Spotted while auditting code.

Fixes #6682.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200619205701.92891-1-raphaelsc@scylladb.com>
(cherry picked from commit 52180f91d4)
2020-07-01 12:37:38 +03:00
Raphael S. Carvalho
c6fde0e562 cql3: don't reset default TTL when not explicitly specified in alter table statement
Any alter table statement that doesn't explicitly set the default time
to live will reset it to 0.

That can be very dangerous for time series use cases, which rely on
all data being eventually expired, and a default TTL of 0 means
data never being expired.

Fixes #5048.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200402211653.25603-1-raphaelsc@scylladb.com>
(cherry picked from commit 044f80b1b5)
2020-06-30 19:28:50 +03:00
Avi Kivity
d9f9e7455b Merge "Fix handling of decimals with negative scales" from Rafael
"
Before this series scylla would effectively infinite loop when, for
example, casting a decimal with a negative scale to float.

Fixes #6720
"

* 'espindola/fix-decimal-issue' of https://github.com/espindola/scylla:
  big_decimal: Add a test for a corner case
  big_decimal: Correctly handle negative scales
  big_decimal: Add a as_rational member function
  big_decimal: Move constructors out of line

(cherry picked from commit 3e2eeec83a)
2020-06-29 12:26:06 +03:00
Piotr Sarna
e95bcd0f8f alternator: fix propagating tags
Updating tags was erroneously done locally, which means that
the schema change was not propagated to other nodes.
The new code announces new schema globally.

Fixes #6513
Branches: 4.0,4.1
Tests: unit(dev)
       dtest(alternator_tests.AlternatorTest.test_update_condition_expression_and_write_isolation)
Message-Id: <3a816c4ecc33c03af4f36e51b11f195c231e7ce1.1592935039.git.sarna@scylladb.com>

(cherry picked from commit f4e8cfe03b)
2020-06-24 14:10:36 +03:00
Asias He
2ff6e2e122 streaming: Do not send end of stream in case of error
Current sender sends stream_mutation_fragments_cmd::end_of_stream to
receiver when an error is received from a peer node. To be safe, send
stream_mutation_fragments_cmd::error instead of
stream_mutation_fragments_cmd::end_of_stream to prevent end_of_stream to
be written into the sstable when a partition is not closed yet.

In addition, use mutation_fragment_stream_validator to valid the
mutation fragments emitted from the reader, e.g., check if
partition_start and partition_end are paired when the reader is done. If
not, fail the stream session and send
stream_mutation_fragments_cmd::error instead of
stream_mutation_fragments_cmd::end_of_stream to isolate the problematic
sstables on the sender node.

Refs: #6478
(cherry picked from commit a521c429e1)
2020-06-23 12:48:01 +03:00
Hagit Segev
1fcf38abd9 release: prepare for 4.0.3 2020-06-21 21:46:49 +03:00
Alejo Sanchez
3375b8b86c lwt: validate before constructing metadata
LWT batches conditions can't span multiple tables.
This was detected in batch_statement::validate() called in ::prepare().
But ::cas_result_set_metadata() was built in the constructor,
causing a bitset assert/crash in a reported scenario.
This patch moves validate() to the constructor before building metadata.

Closes #6332

Tested with https://github.com/scylladb/scylla-dtest/pull/1465

[avi: adjust spelling of exception message to 4.0 spelling]

Signed-off-by: Alejo Sanchez <alejo.sanchez@scylladb.com>
(cherry picked from commit d1521e6721)
2020-06-21 18:22:08 +03:00
Gleb Natapov
586546ab32 cql transport: do not log broken pipe error when a client closes its side of a connection abruptly
Fixes #5661

Message-Id: <20200615075958.GL335449@scylladb.com>
(cherry picked from commit 7ca937778d)
2020-06-21 13:09:10 +03:00
Amnon Heiman
e1d558cb01 api/storage_service.cc: stream result of token_range
The get token range API can become big which can cause large allocation
and stalls.

This patch replace the implementation so it would stream the results
using the http stream capabilities instead of serialization and sending
one big buffer.

Fixes #6297

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
(cherry picked from commit 7c4562d532)
2020-06-21 12:57:34 +03:00
Avi Kivity
b0a8f396b4 Update seastar submodule
* seastar 447aad8d78...0dc0fec831 (1):
  > membarrier: fix madvise(MADV_DONTNEED) failure and crash with --lock-memory

Fixes #6346.
2020-06-21 12:35:39 +03:00
Rafael Ávila de Espíndola
48e7ee374a configure: Reduce the dynamic linker path size
gdb has a SO_NAME_MAX_PATH_SIZE of 512, so we use that as the path
size.

Fixes: #6494

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200528202741.398695-2-espindola@scylladb.com>
(cherry picked from commit aa778ec152)
2020-06-21 12:27:19 +03:00
Piotr Sarna
3e85ecd1bd alternator: fix the return type of PutItem
Even if there are no attributes to return from PutItem requests,
we should return a valid JSON object, not an empty string.

Fixes #6568
Tests: unit(dev)

(cherry picked from commit 8fc3ca855e)
2020-06-21 12:21:30 +03:00
Piotr Sarna
930a4af8b3 alternator: fix returning UnprocessedKeys unconditionally
Client libraries (e.g. PynamoDB) expect the UnprocessedKeys
and UnprocessedItems attributes to appear in the response
unconditionally - it's hereby added, along with a simple test case.

Fixes #6569
Tests: unit(dev)

(cherry picked from commit 3aff52f56e)
2020-06-21 12:19:34 +03:00
Tomasz Grabiec
6a6d36058a row_cache: Fix undefined behavior on key linearization
This is relevant only when using partition or clustering keys which
have a representation in memory which is larger than 12.8 KB (10% of
LSA segment size).

There are several places in code (cache, background garbage
collection) which may need to linearize keys because of performing key
comparison, but it's not done safely:

 1) the code does not run with the LSA region locked, so pointers may
get invalidated on linearization if it needs to reclaim memory. This
is fixed by running the code inside an allocating section.

 2) LSA region is locked, but the scope of
with_linearized_managed_bytes() encloses the allocating section. If
allocating section needs to reclaim, linearization context will
contain invalidated pointers. The fix is to reorder the scopes so
that linearization context lives within an allocating section.

Example of 1 can be found in
range_populating_reader::handle_end_of_stream() where it performs a
lookup:

  auto prev = std::prev(it);
  if (prev->key().equal(*_cache._schema, *_last_key->_key)) {
     it->set_continuous(true);

but handle_end_of_stream() is not invoked under allocating section.

Example of 2 can be found in mutation_cleaner_impl::merge_some() where
it does:

  return with_linearized_managed_bytes([&] {
  ...
    return _worker_state->alloc_section(region, [&] {

Fixes #6637.
Refs #6108.

Tests:

  - unit (all)

Message-Id: <1592218544-9435-1-git-send-email-tgrabiec@scylladb.com>
(cherry picked from commit e81fc1f095)
2020-06-21 11:58:39 +03:00
Yaron Kaikov
ce57d0174d release: prepare for 4.0.2 2020-06-15 20:52:58 +03:00
Avi Kivity
cd11f210ad tools: toolchain: regenerate for gnutls 3.6.14
CVE-2020-13777.

Fixes #6627.

Toolchain source image registry disambiguated due to tighter podman defaults.
2020-06-15 07:58:31 +03:00
Calle Wilund
1e2e203cf0 gms::inet_address: Fix sign extension error in custom address formatting
Fixes #5808

Seems some gcc:s will generate the code as sign extending. Mine does not,
but this should be more correct anyhow.

Added small stringify test to serialization_test for inet_address

(cherry picked from commit a14a28cdf4)
2020-06-09 20:16:37 +03:00
Takuya ASADA
1a98c93a25 aws: update enhanced networking supported instance list
Sync enhanced networking supported instance list to latest one.

Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html

Fixes #6540

(cherry picked from commit 969c4258cf)
2020-06-09 16:02:27 +03:00
Calle Wilund
4f4845c94c commitlog_test: Ensure "when_over_disk_limit" reads segment list only once
Fixes #6195

test_commitlog_delete_when_over_disk_limit reads current segment list
in flush handler, to compare with result after allowing deletetion of
segement. However, it might be called more than once in rare cases,
because timing and us using rather small sizes.

Reading the list the second time however is not a good idea, because
it might just very well be exactly the same as what we read in the
test check code, and we actually overwrite the list we want to
check against. Because callback is on timer. And test is not.

Message-Id: <20200414114322.13268-1-calle@scylladb.com>
[ penberg: backported fix random failures in commitlog_test ]
(cherry picked from commit a62d75fed5)
2020-06-01 18:41:18 +03:00
Nadav Har'El
ef745e1ce7 alternator: fix support for bytes type in Query's KeyConditions
Our parsing of values in a KeyConditions paramter of Query was done naively.
As a result, we got bizarre error messages "condition not met: false" when
these values had incorrect type (this is issue #6490). Worse - the naive
conversion did not decode base64-encoded bytes value as needed, so
KeyConditions on bytes-typed keys did not work at all.

This patch fixes these bugs by using our existing utility function
get_key_from_typed_value(), which takes care of throwing sensible errors
when types don't match, and decoding base64 as needed.

Unfortunately, we didn't have test coverage for many of the KeyConditions
features including bytes keys, which is why this issue escaped detection.
A patch will follow with much more comprehensive tests for KeyConditions,
which also reproduce this issue and verify that it is fixed.

Refs #6490
Fixes #6495

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200524141800.104950-1-nyh@scylladb.com>
(cherry picked from commit 6b38126a8f)
2020-05-31 14:02:18 +03:00
Calle Wilund
ae32aa970a commitlog::read_log_file: Preserve subscription across reading
Fixes #6265

Return type for read_log_file was previously changed from
subscription to future<>, returning the previously returned
subscriptions result of done(). But it did not preserve the
subscription itself, which in turn will cause us to (in
work::stream), call back into a deleted object.

Message-Id: <20200422090856.5218-1-calle@scylladb.com>
(cherry picked from commit 525b283326)
2020-05-25 13:07:33 +03:00
Eliran Sinvani
a3eb12c5f1 Auth: return correct error code when role is not found
Scylla returns the wrong error code (0000 - server internal error)
in response to trying to do authentication/authorization operations
that involves a non-existing role.
This commit changes those cases to return error code 2200 (invalid
query) which is the correct one and also the one that Cassandra
returns.
Tests:
    Unit tests (Dev)
    All auth and auth_role dtests

(cherry picked from commit ce8cebe34801f0ef0e327a32f37442b513ffc214)

Fixes #6363.
2020-05-25 12:58:09 +03:00
Amnon Heiman
b5cedfc177 storage_service: get_range_to_address_map prevent use after free
The implementation of get_range_to_address_map has a default behaviour,
when getting an empty keypsace, it uses the first non-system keyspace
(first here is basically, just a keyspace).

The current implementation has two issues, first, it uses a reference to
a string that is held on a stack of another function. In other word,
there's a use after free that is not clear why we never hit.

The second, it calls get_non_system_keyspaces twice. Though this is not
a bug, it's redundant (get_non_system_keyspaces uses a loop, so calling
that function does have a cost).

This patch solves both issues, by chaning the implementation to hold a
string instead of a reference to a string.

Second, it stores the results from get_non_system_keyspaces and reuse
them it's more efficient and holds the returned values on the local
stack.

Fixes #6465

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
(cherry picked from commit 69a46d4179)
2020-05-25 12:48:26 +03:00
Hagit Segev
8d9bc57aca release: prepare for 4.0.1 2020-05-24 21:39:44 +03:00
Tomasz Grabiec
1cbda629a2 sstables: index_reader: Fix overflow when calculating promoted index end
When index file is larger than 4GB, offset calculation will overflow
uint32_t and _promoted_index_end will be too small.

As a result, promoted_index_size calculation will underflow and the
rest of the page will be interpretd as a promoted index.

The partitions which are in the remainder of the index page will not
be found by single-partition queries.

Data is not lost.

Introduced in 6c5f8e0eda.

Fixes #6040
Message-Id: <20200521174822.8350-1-tgrabiec@scylladb.com>

(cherry picked from commit a6c87a7b9e)
2020-05-24 09:45:55 +03:00
Rafael Ávila de Espíndola
baf0201a6e repair: Make sure sinks are always closed
In a recent next failure I got the following backtrace

    function=function@entry=0x270360 "seastar::rpc::sink_impl<Serializer, Out>::~sink_impl() [with Serializer = netw::serializer; Out = {repair_row_on_wire_with_cmd}]") at assert.c:101
    at ./seastar/include/seastar/core/shared_ptr.hh:463
    at repair/row_level.cc:2059

This patch changes a few functions to use finally to make sure the sink
is always closed.

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200515202803.60020-1-espindola@scylladb.com>
(cherry picked from commit 311fbe2f0a)

Ref #6414
2020-05-20 09:00:44 +03:00
Asias He
7dcffb963c repair: Fix race between write_end_of_stream and apply_rows
Consider: n1, n2, n1 is the repair master, n2 is the repair follower.

=== Case 1 ===
1) n1 sends missing rows {r1, r2} to n2
2) n2 runs apply_rows_on_follower to apply rows, e.g., {r1, r2}, r1
   is written to sstable, r2 is not written yet, r1 belongs to
   partition 1, r2 belongs to partition 2. It yields after row r1 is
   written.
   data: partition_start, r1
3) n1 sends repair_row_level_stop to n2 because error has happened on n1
4) n2 calls wait_for_writer_done() which in turn calls write_end_of_stream()
   data: partition_start, r1, partition_end
5) Step 2 resumes to apply the rows.
   data: partition_start, r1, partition_end, partition_end, partition_start, r2

=== Case 2 ===
1) n1 sends missing rows {r1, r2} to n2
2) n2 runs apply_rows_on_follower to apply rows, e.g., {r1, r2}, r1
   is written to sstable, r2 is not written yet, r1 belongs to partition
   1, r2 belongs to partition 2. It yields after partition_start for r2
   is written but before _partition_opened is set to true.
   data: partition_start, r1, partition_end, partition_start
3) n1 sends repair_row_level_stop to n2 because error has happened on n1
4) n2 calls wait_for_writer_done() which in turn calls write_end_of_stream().
   Since _partition_opened[node_idx] is false, partition_end is skipped,
   end_of_stream is written.
   data: partition_start, r1, partition_end, partition_start, end_of_stream

This causes unbalanced partition_start and partition_end in the stream
written to sstables.

To fix, serialize the write_end_of_stream and apply_rows with a semaphore.

Fixes: #6394
Fixes: #6296
Fixes: #6414
(cherry picked from commit b2c4d9fdbc)
2020-05-20 08:08:11 +03:00
Piotr Dulikowski
dcfaf4d035 hinted handoff: don't keep positions of old hints in rps_set
When sending hints from one file, rps_set field in send_one_file_ctx
keeps track of commitlog positions of hints that are being currently
sent, or have failed to be sent. At the end of the operation, if sending
of some hints failed, we will choose position of the earliest hint that
failed to be sent, and will retry sending that file later, starting from
that position. This position is stored in _last_not_complete_rp.

Usually, this set has a bounded size, because we impose a limit of at
most 128 hints being sent concurrently. Because we do not attempt to
send any more hints after a failure is detected, rps_set should not have
more than 128 elements at a time.

Due to a bug, commitlog positions of old hints (older than
gc_grace_seconds of the destination table) were inserted into rps_set
but not removed after checking their age. This could cause rps_set to
grow very large when replaying a file with old hints.

Moreover, if the file mixed expired and non-expired hints (which could
happen if it had hints to two tables with different gc_grace_seconds),
and sending of some non-expired hints failed, then positions of expired
hints could influence calculation _last_not_complete_rp, and more hints
than necessary would be resent on the next retry.

This simple patch removes commitlog position of a hint from rps_set when
it is detected to be too old.

Fixes #6422

(cherry picked from commit 85d5c3d5ee)
2020-05-20 08:06:04 +03:00
Piotr Dulikowski
f974a54cbd hinted handoff: remove discarded hint positions from rps_set
Related commit: 85d5c3d

When attempting to send a hint, an exception might occur that results in
that hint being discarded (e.g. keyspace or table of the hint was
removed).

When such an exception is thrown, position of the hint will already be
stored in rps_set. We are only allowed to retain positions of hints that
failed to be sent and needed to be retried later. Dropping a hint is not
an error, therefore its position should be removed from rps_set - but
current logic does not do that.

Because of that bug, hint files with many discardable hints might cause
rps_set to grow large when the file is replayed. Furthermore, leaving
positions of such hints in rps_set might cause more hints than necessary
to be re-sent if some non-discarded hints fail to be sent.

This commit fixes the problem by removing positions of discarded hints
from rps_set.

Fixes #6433

(cherry picked from commit 0c5ac0da98)
2020-05-20 08:03:44 +03:00
Piotr Sarna
30a96cc592 db, view: remove duplicate entries from pending endpoints
When generating view updates, an endpoint can appear both
as a primary paired endpoint for the view update, and as a pending
endpoint (due to range movements). In order not to generate
the same update twice for the same endpoint, the paired endpoint
is removed from the list of pending endpoints if present.

Fixes #5459
Tests: unit(dev),
       dtest(TestMaterializedViews.add_dc_during_mv_insert_test)

(cherry picked from commit 86b0dd81e3)
2020-05-17 19:09:58 +02:00
Avi Kivity
faf300382a Update seastar submodule
* seastar 8bc24f486a...447aad8d78 (1):
  > timer: add scheduling_group awareness

Fixes #6170.
2020-05-10 18:12:32 +03:00
Gleb Natapov
55400598ff storage_proxy: limit read repair only to replicas that answered during speculative reads
Speculative reader has more targets that needed for CL. In case there is
a digest mismatch the repair runs between all of them, but that violates
provided CL. The patch makes it so that repair runs only between
replicas that answered (there will be CL of them).

Fixes #6123

Reviewed-by: Glauber Costa <glauber@scylladb.com>
Message-Id: <20200402132245.GA21956@scylladb.com>
(cherry picked from commit 36a24bbb70)
2020-05-07 19:48:24 +03:00
Mike Goltsov
c177295bce fix error in fstrim service (scylla_util.py)
On Centos 7 machine:

fstrim.timer not enabled, only unmasked due scylla_fstrim_setup on installation
When trying run scylla-fstrim service manually you get error:

Traceback (most recent call last):
File "/opt/scylladb/scripts/libexec/scylla_fstrim", line 60, in <module>
main()
File "/opt/scylladb/scripts/libexec/scylla_fstrim", line 44, in main
cfg = parse_scylla_dirs_with_default(conf=args.config)
File "/opt/scylladb/scripts/scylla_util.py", line 484, in parse_scylla_dirs_with_default
if key not in y or not y[k]:
NameError: name 'k' is not defined

It caused by error in scylla_util.py

Fixes #6294.

(cherry picked from commit 068bb3a5bf)
2020-05-07 19:45:35 +03:00
Hagit Segev
d95aa77b62 release: prepare for 4.0.0 2020-05-05 18:58:39 +03:00
Pekka Enberg
fe54009855 scripts/jobs: Keep memory reserve when calculating parallelism
The "jobs" script is used to determine the amount of compilation
parallelism on a machine. It attempts to ensure each GCC process has at
least 4 GB of memory per core. However, in the worst case scenario, we
could end up having the GCC processes take up all the system memory,
forcin swapping or OOM killer to kick in. For example, on a 4 core
machine with 16 GB of memory, this worst case scenario seems easy to
trigger in practice.

Fix up the problem by keeping a 1 GB of memory reserve for other
processes and calculating parallelism based on that.

Message-Id: <20200423082753.31162-1-penberg@scylladb.com>
(cherry picked from commit 7304a795e5)
2020-05-04 19:01:14 +03:00
Piotr Sarna
bbe82236be clocks-impl: switch to thread-safe time conversion
std::gmtime() has a sad property of using a global static buffer
for returning its value. This is not thread-safe, so its usage
is replaced with gmtime_r, which can accept a local buffer.
While no regressions where observed in this particular area of code,
a similar bug caused failures in alternator, so it's better to simply
replace all std::gmtime calls with their thread-safe counterpart.

Message-Id: <39e91c74de95f8313e6bb0b12114bf12c0e79519.1588589151.git.sarna@scylladb.com>
(cherry picked from commit 05ec95134a)
2020-05-04 17:14:28 +03:00
Piotr Sarna
abd73cab78 alternator: fix signature timestamps
Generating timestamps for auth signatures used a non-thread-safe
::gmtime function instead of thread-safe ::gmtime_r.

Tests: unit(dev)
Fixes #6345

(cherry picked from commit fb7fa7f442)
2020-05-04 17:05:39 +03:00
Nadav Har'El
8fd7cf5cd1 alternator test: drastically reduce time to boot Scylla
The alternator test, test/alternator/run, runs Scylla and runs the
various tests against it. Before this patch, just booting Scylla took
about 26 seconds (for a dev build, on my laptop). This patch reduces
this delay to less than one second!

It turns out that almost the entire delay was artificial, two periods
of 12 seconds "waiting for the gossip to settle", which are completely
unnecessary in the one-node cluster used in the Alternator test.
So a simple "--skip-wait-for-gossip-to-settle 0" parameter eliminates
these long delays completely.

Amusingly, the Scylla boot is now so fast, that I had to change a "sleep 2"
in the test script to "sleep 1", because 2 seconds is now much more than
it takes to boot Scylla :-)

Fixes #6310.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200428145035.22894-1-nyh@scylladb.com>
(cherry picked from commit ff5615d59d)
2020-05-04 16:10:27 +03:00
Alejo Sanchez
dd88b2dd18 utils: error injection allocate string for remote invoke
Allocate string before sending to other shards.

Reported by Pavel Solodovnikov.

Refs #3295 (closed)

Tests: unit ({dev})

Signed-off-by: Alejo Sanchez <alejo.sanchez@scylladb.com>
Message-Id: <20200328204454.1326514-2-alejo.sanchez@scylladb.com>
(cherry picked from commit e5a2ba32b9)

Ref #6342.
2020-05-03 19:33:34 +03:00
Hagit Segev
eee4c00e29 release: prepare for 4.0.rc3 2020-05-01 00:46:40 +03:00
Avi Kivity
85071ceeb1 Merge 'Fix hang in multishard_writer' from Asias
"
This series fix hang in multishard_writer when error happens. It contains
- multishard_writer: Abort the queue attached to consumers when producer fails
- repair: Fix hang when the writer is dead

Fixes #6241
Refs: #6248
"

* asias-stream_fix_multishard_writer_hang:
  repair: Fix hang when the writer is dead
  mutation_writer_test: Add test_multishard_writer_producer_aborts
  multishard_writer: Abort the queue attached to consumers when producer fails

(cherry picked from commit 8925e00e96)
2020-04-30 19:32:12 +03:00
Asias He
4cf201fc24 config: Do not enable repair based node operations by default
Give it some more time to mature. Use the old stream plan based node
operations by default.

Fixes: #6305
Backports: 4.0
(cherry picked from commit b8ac10c451)
2020-04-30 17:57:55 +03:00
Raphael S. Carvalho
c6ad5cf556 api/service: fix segfault when taking a snapshot without keyspace specified
If no keyspace is specified when taking snapshot, there will be a segfault
because keynames is unconditionally dereferenced. Let's return an error
because a keyspace must be specified when column families are specified.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20200427195634.99940-1-raphaelsc@scylladb.com>
(cherry picked from commit 02e046608f)

Fixes #6336.
2020-04-30 12:49:13 +03:00
Piotr Sarna
51e3e6c655 Update seastar submodule
* seastar 251bc8f2...8bc24f48 (1):
  > http: make headers case-insensitive

Fixes #6319
2020-04-30 08:18:01 +02:00
Nadav Har'El
8ac6579b30 test.py: run Alternator test with the correct Scylla binary
The Alternator test's run script, test/alternator/run, runs Scylla.
By default, it chooses the last built Scylla executable build/*/scylla.

However, test.py has a "mode" option, that should be able to choose which
build mode to run. Before this patch, this mode option wasn't honored by
the Alternator test, so a "test.py alternator/run" would run the same
Scylla binary (the one last built) three times, instead of running each
of the three build modes.

We fix this in this patch: test.py now passes the "SCYLLA" environment
variable to the test/alternator/run script, indicating the location of the
Scylla binary with the appropriate build mode. The script already supported
this environment variable to override its default choice of Scylla binary.

In test.py, we add to the run_test() function an optional "env" parameter
which can be used to pass additional environment variables to the test.

Fixes #6286

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200427131958.28248-1-nyh@scylladb.com>
(cherry picked from commit 858a12755b)
2020-04-28 16:19:07 +03:00
Piotr Sarna
3744e66244 alternator: fix integer overflow warning in token generation
When generating tokens for parallel scan, debug mode undefined behavior
sanitizer complained that integer overflow sometimes happens when
multiplying two big values - delta and segment number.
In order to mitigate this warning, the multiplication is now split
into two smaller ones, and the generated machine code remains
identical (verified on gcc and clang via compiler explorer).

Fixes #6280
Tests: unit(dev)

(cherry picked from commit e17c237feb)
2020-04-28 16:15:31 +03:00
Piotr Sarna
d3bf349484 alternator: allow parallel scan
Parallel scans can be performed by providing Segment and TotalSegments
attributes to Scan request, which can be used to split the work among
many workers.
This test makes the parallel scan test succeed, so the xfail is removed.

Fixes #5059

(cherry picked from commit dbb9574aa2)
2020-04-28 16:07:43 +03:00
Nadav Har'El
3e6a8ba5bd test/alternator: increase timeout on Scylla boot
The Alternator test boots Scylla to test against it. We set an arbitrary
timeout for this boot to succeed: 100 seconds. This 100 seconds is
significantly more than 25 seconds it takes on my laptop, and I though
we'll never reach it. But it turns out that in some setups - running the
very slow debug build on slow and overcommitted nodes - 100 seconds is
not enough.

So this patch doubles the timeout to 200 seconds.

Note that this "200 seconds" is just a timeout, and doesn't affect normal
runs: Both a successful boot and a failed boot are recognized as soon as
they happen, and we never unnecessarily wait the entire 200 seconds.

Fixes #6271.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200422193920.17079-1-nyh@scylladb.com>
(cherry picked from commit 92e36c5df5)
2020-04-28 16:04:12 +03:00
Nadav Har'El
5f1785b9cf alternator: use RF=3 even if some nodes are temporarily down
Alternator is supposed to use RF=3 for new tables. Only when the cluster is
smaller than 3 nodes do we use RF=1 (and warn about it) - this is useful for
testing.

However, our implementation incorrectly tested the number of *live* nodes in
the cluster instead of the total number of nodes. As a result, if a 3-node
cluster had one node down, and a new table was created, it was created with
RF=1, and immediately could not be written because when RF=1, any node down
means part of the data is unavailable.

This patch fixes this: The total number of nodes in the cluster - not the
number of live nodes - is consulted. The three-node-cluster-with-a-dead-node
setup above creates the table with RF=3, and it can be written because two
living nodes out of three are enough when RF=3 and we do quorum writes and
reads.

We have a dtest to reproduce this bug (and its fix), and it's also easy to
reproduce manually by starting a 3-node cluster, killing one of the nodes,
and then running "pytests". Before this patch, the tests can create tables
but then fail to write to them. After this patch, the test succeed on the
same cluster with the dead node.

Fixes #6267

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200422182035.15106-2-nyh@scylladb.com>
(cherry picked from commit 1f75efb556)
2020-04-28 15:52:06 +03:00
Nadav Har'El
e1fd6cf989 gossiper: add convenience function for getting number of nodes
The gossiper has a convenience functions get_up_endpoint_count() and
get_down_endpoint_count(), but strangely no function to get the total
number. Even though it's easy to calculate the total by summing up their
result it is inefficient and also incovenient because of of these
functions returns a future.

So let's add another function, get_all_endpoint_count(), to get the
total number of nodes. We will use this function in the next patch.

Signed-off-by: Nadav Har'El <n...@scylladb.com>
Message-Id: <20200422182035.15106-1-nyh@scylladb.com>
(cherry picked from commit 08c39bde1a)
2020-04-28 15:51:37 +03:00
Piotr Sarna
b7328ff1e4 alternator: implement ScanIndexForward
The ScanIndexForward parameter is now fully implemented
and can accept ScanIndexForward=false in order to query
the partitions in reverse clustering order.
Note that reading partition slices in reverse order is less
efficient than forward scans and may put a strain on memory
usage, especially for large partitions, since the whole partition
is currently fetched in order to be reversed.

Fixes #5153

(cherry picked from commit 09e4f3b917)
2020-04-28 15:30:01 +03:00
Avi Kivity
602ed43ac7 Update seastar submodule
* seastar 76260705ef...251bc8f25d (1):
  > http server: fix "Date" header format

Fixes #6253.
2020-04-26 19:30:08 +03:00
Tomasz Grabiec
c42c91c5bb Merge "Drop only learnt value on PRUNE" from Gleb
It is unsafe to remove entire row, so only drop learn value from
system.paxos table.

Fixes: #6154
(cherry picked from commit e648e314e5)
2020-04-21 18:30:12 +03:00
Avi Kivity
cf017b320a test: alternator: configure scylla for test environment in terms of cpu and disk
Currently, the alternator tests configure scylla to use all the
logical cores in the host system, but only 1GB of RAM. This can lead
to a small amount of memory per core.

It also uses the default disk configuration, which is safe, but can be
very slow on mechanical or non-enterprise disks.

Change to use a fixed --smp 2 configuration, and add --overprovisioned
for maximum flexibility (no spinning). Use --unsafe-bypass-fsync
for faster performance on non-enterprise or mechanical disks, assuming
that the test data is not important.

Fixes #6251.
Message-Id: <20200420154112.123386-1-avi@scylladb.com>

(cherry picked from commit 2482e53de9)
2020-04-21 18:25:28 +03:00
Hagit Segev
89e79023ae release: prepare for 4.0.rc2 2020-04-21 16:26:09 +03:00
Nadav Har'El
bc67da1a21 alternator-test: comment out an error-path test that doesn't work on newer boto3
Unfortunately, the boto3 library doen't allow us to check some of the
input error cases because it unnecessarily tests its input instead of
just passing it to Alternator and allowing Alternator to report the error.
In this patch we comment out a test case which used to work fine - i.e.,
the error was reported by Alternator - until recent changes to boto3
made it catch the problem without passing it to Alternator :-(

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200330190521.19526-2-nyh@scylladb.com>
(cherry picked from commit fe6cecb26d)
2020-04-21 07:19:54 +02:00
Botond Dénes
0c7643f1fe schema: schema(): use std::stable_sort() to sort key columns
When multiple key columns (clustering or partition) are passed to
the schema constructor, all having the same column id, the expectation
is that these columns will retain the order in which they were passed to
`schema_builder::with_column()`. Currently however this is not
guaranteed as the schema constructor sort key columns by column id with
`std::sort()`, which doesn't guarantee that equally comparing elements
retain their order. This can be an issue for indexes, the schemas of
which are built independently on each node. If there is any room for
variance between for the key column order, this can result in different
nodes having incompatible schemas for the same index.
The fix is to use `std::stable_sort()` which guarantees that the order
of equally comparing elements won't change.

This is a suspected cause of #5856, although we don't have hard proof.

Fixes: #5856
Signed-off-by: Botond Dénes <bdenes@scylladb.com>
[avi: upgraded "Refs" to "Fixes", since we saw that std::sort() becomes
      unstable at 17 elements, and the failing schema had a
      clustering key with 23 elements]
Message-Id: <20200417121848.1456817-1-bdenes@scylladb.com>
(cherry picked from commit a4aa753f0f)
2020-04-19 18:18:45 +03:00
Rafael Ávila de Espíndola
c563234f40 dht: Use get_random_number<uint64_t> instead of int64_t in token::get_random_token
I bisect the opposite change in
9c202b52da as the cause of issue 6193. I
don't know why. Maybe get_random_number<signed_type> is buggy?

In any case, reverting to uint64_t solves the issue.

Fixes #6193

Signed-off-by: Rafael Ávila de Espíndola <espindola@scylladb.com>
Message-Id: <20200418001611.440733-1-espindola@scylladb.com>
(cherry picked from commit f3fd466156)
2020-04-19 16:20:40 +03:00
Nadav Har'El
77b7a48a02 alternator: remove mentions of experimental status of LWT
Since commit 9948f548a5, the LWT no longer
requires an "experimental" flag, so Alternator documents and scripts
which referred to the need for enabling experimental LWT, are fixed here
to no longer do that.

Fixes #6118.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200405143237.12693-1-nyh@scylladb.com>
(cherry picked from commit d9d50362af)
2020-04-19 15:10:32 +03:00
Piotr Sarna
b2b1bfb159 alternator: fix failure on incorrect table name with no indexes
If a table name is not found, it may still exist as a local index,
but the check tried to fetch a local index name regardless if it was
present in the request, which was a nullptr dereference bug.

Fixes #6161
Tests: alternator-test(local, remote)
Message-Id: <428c21e94f6c9e450b1766943677613bd46cbc68.1586347130.git.sarna@scylladb.com>

(cherry picked from commit 123edfc10c)
2020-04-19 15:07:25 +03:00
Nadav Har'El
d72cbe37aa docs/alternator/alternator.md: fix typos
Fix a couple of typos in the Alternator documentation.
Fixes scylladb/scylla-doc-issues#280
Fixes scylladb/scylla-doc-issues#281

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200419091900.23030-1-nyh@scylladb.com>
(cherry picked from commit 7e7c688946)
2020-04-19 15:03:22 +03:00
Nadav Har'El
9f7b560771 docs, alternator: alternator.md cleanup
Clean up the alternator.md document, by:

* Updating out-of-date information that outstayed its welcome.
* When Scylla does have a feature but it's just not supported via the
  DynamoDB API (e.g., CDC and on-demand backups) mention that.
* Remove mention of Alternator being experimental and users should not
  store important data on it :-)
* Miscellaneous cleanups.

Fixes #6179.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200412094641.27186-1-nyh@scylladb.com>
(cherry picked from commit 606ae0744c)
2020-04-19 15:00:53 +03:00
Nadav Har'El
06af9c028c alternator-test: make Alternator tests runnable from test.py
To make the tests in alternator-test runnable by test.py, we need to
move the directory alternator-test/ to test/alternator, because test.py
only looks for tests in subdirectories of test/. Then, we need to create
a test/alternator/suite.yaml saying that this test directory is of type
"Run", i.e., it has a single run script "run" which runs all its tests.

The "run" script had to be slightly modified to be aware of its new
location relative to the source directory.

To run the Alternator tests from test.py, do:

	./test.py --mode dev alternator

Note that in this version, the "--mode" has no effect - test/alternator/run
always runs the latest compiled Scylla, regardless of the chosen mode.

The Alternator tests can still be run manually and individually against
a running Scylla or DynamoDB as before - just go to the test/alternator
directory (instead of alternator-test previously) and run "pytest" with
the desired parameters.

Fixes #6046

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 4e2bf28b84)
2020-04-19 11:19:15 +03:00
Nadav Har'El
c74ab3ae80 test.py: add xunit XML output file for "Run" tests
Assumes that "Run" tests can take the --junit-xml=<path> option, and
pass it to ask the test to generate an XML summary of the run to a file
like testlog/dev/xml/run.1.xunit.xml.

This option is honored by the Alternator tests.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 0cccb5a630)
2020-04-19 11:19:06 +03:00
Nadav Har'El
32cd3a070a test.py: add new test type "Run"
This patch adds a new test type, "Run". A test subdirectory of type "Run"
has a script called "run" which is expected to run all the tests in that
directory.

This will be used, in the next patch, by the Alternator functional tests.
These tests indeed have a "run" script, which runs Scylla and then runs
*all* of Alternator's tests, finishing fairly quickly (in less than a
minute). All of that will become one test.py test.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 0ae3136900)
2020-04-19 11:18:01 +03:00
Nadav Har'El
bb1554f09e test.py: flag for aborting tests with SIGTERM, not SIGKILL
Today, if test.py is interrupted with SIGINT or SIGTERM, the ongoing test
is killed with SIGKILL. Some types of tests - such as Alternator's test -
may depend on being killed politely (e.g., with SIGTERM) to clean up
files.

We cannot yet change the signal to SIGTERM for all tests, because Seastar
tests often don't deal well with signals, but we can at least add a flag
that certain test types - that know they can be killed gently - will use.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 36e44972f1)
2020-04-19 11:17:51 +03:00
Nadav Har'El
2037d7550e alternator-test: change "run" script to pick random IP address
Before this patch, the Alternator tests "run" script ran Scylla on a fixed
listening address, 127.0.0.1. There is a problem that there might be other
concurrent runs of Scylla using the same IP address - e.g., CCM (used by
dtest) uses exactly this IP address for its first node.

Luckily, Linux's loopback device actually allows us to pick any of over
a million addresses in 127.0.0.0/8 to listen on - we don't need to use
127.0.0.1 specifically. So the code in this patch picks an address in
127.1.*.*, so it cannot collide with CCM (which uses 127.0.0.* for up to
255 nodes). Moreover, the last two bytes of the listen address are picked
based on the process ID of the run script; This allows multiple copies
of this script to run concurrently - in case anybody wishes to do that.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 24fcc0c0ff)
2020-04-19 11:17:39 +03:00
Nadav Har'El
c320c3f6da install-dependencies.sh: add dependencies for Alternator tests
To run Alternator tests, only two additional dependencies need to be added to
install-dependencies.sh: pytest, and python3-boto3. We also need
python3-cassandra-driver, but this dependency is already listed.

This patch only updates the dependencies for Fedora, which is what we need
for dbuild and our Jenkins setups.

Tested by building a new dbuild docker image and verifying that the
Alternator tests pass.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
[avi: update toolchain image; note this upgrades gcc to 9.3.1]
Message-Id: <20200330181128.18582-1-nyh@scylladb.com>
(cherry picked from commit 8627ae42a6)
2020-04-19 11:17:07 +03:00
Nadav Har'El
0ed70944aa alternator-test: run: use the Python driver, not cqlsh
The "run" script for the Alternator tests needs to set a system table for
authentication credentials, so we can test this feature.
So far we did this with cqlsh, but cqlsh isn't always installed on build
machines. But install-dependencies.sh already installs the Cassandra driver
for Python, so it makes more sense to use that, so this patch switches to
use it.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200331131522.28056-1-nyh@scylladb.com>
(cherry picked from commit 55f02c00f2)
2020-04-19 11:16:54 +03:00
Nadav Har'El
89f860d409 alternator-test: add "--url" option to choose Alternator's URL
The "--aws" and "--local" test options chooses between two useful default
URLs - Amazon's, or http://localhost:8000 for a local installation.
However, sometimes one wants to run Scylla on a different IP address or
port, so in this patch we add a "--url" option to choose a specific URL to
connect to. For example, "--url http://127.1.2.3:1234".

We will later use this option in the alternator-test/run script, to pick
a random IP address on which to run Scylla, and then run the test against
this address.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
(cherry picked from commit 1aec4baa51)
2020-04-19 11:13:13 +03:00
Piotr Sarna
0819d221f4 test: add cases for empty paging state for index queries
In order to check regressions related to #6136 and similar issues,
test cases for handling paging state with empty partition/clustering
key pair are added.

(cherry picked from commit 88913e9d44)
2020-04-19 10:35:26 +03:00
Piotr Sarna
53f47d4e67 cql3: fix generating base keys from empty index paging state
An empty partition/clustering key pair is a valid state of the
query paging state. Unfortunately, recent attempts at debugging
a flaky test resulted in introducing an assertion which breaks
when trying to generate a key from such a pair.
In order to keep the assertion (since it still makes sense in its
scope), but at the same time translate empty keys properly,
empty keys are now explicitly processed at the beginning of the
function.
This behaviour was 100% reproducible in a secondary index dtest below.

Fixes #6134
Refs #5856
Tests: unit(dev),
       dtest(TestSecondaryIndexes.test_truncate_base)

(cherry picked from commit 45751ee24f)
2020-04-19 10:35:09 +03:00
Kamil Braun
21ad12669a sstables: freeze types nested in collection types in legacy sstables
Some legacy `mc` SSTables (created in Scylla 3.0) may contain incorrect
serialization headers, which don't wrap frozen UDTs nested inside collections
with the FrozenType<...> tag. When reading such SSTable,
Scylla would detect a mismatch between the schema saved in schema
tables (which correctly wraps UDTs in the FrozenType<...> tag) and the schema
from the serialization header (which doesn't have these tags).

SSTables created in Scylla versions 3.1 and above, in particular in
Scylla versions that contain this commit, create correct serialization
headers (which wrap UDTs in the FrozenType<...> tag).

This commit does two things:
1. for all SSTables created after this commit, include a new feature
   flag, CorrectUDTsInCollections, presence of which implies that frozen
   UDTs inside collections have the FrozenType<...> tag.
2. when reading a Scylla SSTable without the feature flag, we assume that UDTs
   nested inside collections are always frozen, even if they don't have
   the tag. This assumption is safe to be made, because at the time of
   this commit, Scylla does not allow non-frozen (multi-cell) types inside
   collections or UDTs, and because of point 1 above.

There is one edge case not covered: if we don't know whether the SSTable
comes from Scylla or from C*. In that case we won't make the assumption
described in 2. Therefore, if we get a mismatch between schema and
serialization headers of a table which we couldn't confirm to come from
Scylla, we will still reject the table. If any user encounters such an
issue (unlikely), we will have to use another solution, e.g. using a
separate tool to rewrite the SSTable.

Fixes #6130.

(cherry picked from commit 3d811e2f95)
2020-04-17 09:11:53 +03:00
Kamil Braun
c812359383 sstables: move definition of column_translation::state::build to a .cc file
Ref #6130
2020-04-17 09:11:38 +03:00
Piotr Sarna
1bd79705fb alternator: use partition tombstone if there's no clustering key
As @tgrabiec helpfully pointed out, creating a row tombstone
for a table which does not have a clustering key in its schema
creates something that looks like an open-ended range tombstone.
That's problematic for KA/LA sstable formats, which are incapable
of writing such tombstones, so a workaround is provided
in order to allow using KA/LA in alternator.

Fixes #6035

(cherry picked from commit 0a2d7addc0)
2020-04-16 12:01:51 +03:00
Avi Kivity
7e2ef386cc Update seastar submodule
* seastar 92c488706...76260705e (1):
  > rpc: always shutdown socket when stopping a client

Fixes #6060.
2020-04-16 10:56:31 +03:00
Avi Kivity
51bad7e72c Point seastar submodule at scylla-seastar.git branch-4.0
This allows us to backport seastar patches to Scylla 4.0.
2020-04-16 10:10:40 +03:00
Asias He
0379d0c031 repair: Send reason for node operations
Since 956b092012 (Merge "Repair based node
operation" from Asias), repair is used by other node operations like
bootstrap, decommission and so on.

Send the reason for the repair, so that we can handle the materialized
view update correctly according to the reason of the operation. We want
to trigger the view update only if the repair is used by repair
operation. Otherwise, the view table will be handled twice, 1) when the
view table is synced using repair 2) when the base table is synced using
repair and view table update is triggered.

Fixes #5930
Fixes #5998

(cherry picked from commit 066934f7c4)
2020-04-16 10:06:17 +03:00
Gleb Natapov
a8ef820f27 lwt: fix cas_now_pruning counter
Due to c&p error cas_now_pruning counter is increased instead of
decreased after an operation completes. Fix it.

Fixes #6116

Message-Id: <20200401142859.GA16953@scylladb.com>
(cherry picked from commit 4d9d226596)
2020-04-06 13:06:11 +02:00
Yaron Kaikov
9908f009a4 release: prepare for 4.0.rc1 2020-04-06 10:22:45 +03:00
Pavel Emelyanov
48d8a075b4 main: Do not destroy token_metadata
The storage_proxy instances hold references to token_metadata ones and
leave unwaited futures continuing to its query_partition_key_range_concurrent
method.

The latter is called from do_query so it's not that easy to find
out who is leaking. Keep the tokens not freed for a while.

Fixes: #6093
Test: manual start-stop

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
Message-Id: <20200402183538.9674-1-xemul@scylladb.com>
(cherry picked from commit 86296ba557)
2020-04-05 13:47:57 +03:00
Konstantin Osipov
e3ddd607bc lwt: remove Paxos from experimental list
Always enable lightweight transactions. Remove the check for the command
line switch from the feature service, assuming LWT is always enabled.

Remove the check for LWT from Alternator.

Note that in order for the cluster to work with LWT, all nodes need
to support it.

Rename LWT to UNUSED in db/config.hh, to keep accepting lwt keyword in
--experimental-features command line option, but do nothing with it.

Changes in v2:
* remove enable_lwt feature flag, it's always there

Closes #6102

test: unit (dev, debug)
Message-Id: <20200401071149.41921-1-kostja@scylladb.com>
(cherry picked from commit 9948f548a5)
2020-04-05 08:56:42 +03:00
Piotr Jastrzebski
511773d466 token: relax the condition of the sanity check
When we switched token representation to int64_t
we added some sanity checks that byte representation
is always 8 bytes long.

It turns out that for token_kind::before_all_keys and
token_kind::after_all_keys bytes can sometimes be empty
because for those tokens they are just ignored. The check
introduced with the change is too strict and sometimes
throws the exception for tokens before/after all keys
created with empty bytes.

This patch relaxes the condition of the check and always
uses 0 as value of _data for special before/after all keys
tokens.

Fixes #6131

Tests: unit(dev, sct)

Signed-off-by: Piotr Jastrzebski <piotr@scylladb.com>
(cherry picked from commit a15b32c9d9)
2020-04-04 20:19:10 +03:00
Gleb Natapov
121cd383fa lwt: remove entries from system.paxos table after successful learn stage
The learning stage of PAXOS protocol leaves behind an entry in
system.paxos table with the last learned value (which can be large). In
case not all participants learned it successfully next round on the same
key may complete the learning using this info. But if all nodes learned
the value the entry does not serve useful purpose any longer.

The patch adds another round, "prune", which is executed in background
(limited to 1000 simultaneous instances) and removes the entry in
case all nodes replied successfully to the "learn" round.  It uses the
ballot's timestamp to do the deletion, so not to interfere with the
next round. Since deletion happens very close to previous writes it will
likely happen in memtable and will never reach sstable, so that reduces
memtable flush and compaction overhead.

Fixes #5779

Message-Id: <20200330154853.GA31074@scylladb.com>
(cherry picked from commit 8a408ac5a8)
2020-04-02 15:36:52 +02:00
Gleb Natapov
90639f48e5 lwt: rename "in_progress_ballot" cell to "promise" in system.paxos table
The value that is stored in "in_progress_ballot" cell is the value of
promised ballot, so call the cell accordingly to avoid confusion
especially as we have a notion of "in progress" proposal in the code
which is not the same as in_progress_ballot here.

We can still do it without care about backwards compatibility since LWT
is still marked as experimental.

Fixes #6087.

Message-Id: <20200326095758.GA10219@scylladb.com>
(cherry picked from commit b3db6f5b04)
2020-04-02 15:36:49 +02:00
Calle Wilund
8d029a04aa db::commitlog: Don't write trailing zero block unless needed
Fixes #5899

When terminating (closing) a segment, we write a trailing block
of zero so reader can have an empty region after last used chunk
as end marker. This is due to using recycled, pre-allocated
segments with potentially non-zero data extending over the point
where we are ending the segment (i.e. we are not fully filling
the segment due to a huge mutation or similar).

However, if we reach end of segment writing the final block
(typically many small mutations), the file will end naturally
after the data written, and any trailing zero block would in fact
just extend the file further. While this will only happen once per
segment recycled (independent on how many times it is recycled),
it is still both slightly breaking the disk usage contract and
also potentially causing some disk stalls due to metadata changes
(though of course very infrequent).

We should only write trailing zero if we are below the max_size
file size when terminating

Adds a small size check to commitlog test to verify size bounds.
(Which breaks without the patch)

v2:
- Fix test to take into account that files might be deleted
  behind our backs.
v3:
- Fix test better, by doing verification _before_ segments are
  queued for delete.

Message-Id: <20200226121601.15347-2-calle@scylladb.com>
Message-Id: <20200324100235.23982-1-calle@scylladb.com>
(cherry picked from commit 9fee712d62)
2020-03-31 14:22:20 +03:00
Asias He
67995db899 gossip: Add an option to force gossip generation
Consider 3 nodes in the cluster, n1, n2, n3 with gossip generation
number g1, g2, g3.

n1, n2, n3 running scylla version with commit
0a52ecb6df (gossip: Fix max generation
drift measure)

One year later, user wants the upgrade n1,n2,n3 to a new version

when n3 does a rolling restart with a new version, n3 will use a
generation number g3'. Because g3' - g2 > MAX_GENERATION_DIFFERENCE and
g3' - g1 > MAX_GENERATION_DIFFERENCE, so g1 and g2 will reject n3's
gossip update and mark g3 as down.

Such unnecessary marking of node down can cause availability issues.
For example:

DC1: n1, n2
DC2: n3, n4

When n3 and n4 restart, n1 and n2 will mark n3 and n4 as down, which
causes the whole DC2 to be unavailable.

To fix, we can start the node with a gossip generation within
MAX_GENERATION_DIFFERENCE difference for the new node.

Once all the nodes run the version with commit
0a52ecb6df, the option is no logger
needed.

Fixes #5164

(cherry picked from commit 743b529c2b)
2020-03-30 12:36:20 +02:00
Yaron Kaikov
282cd0df7c dist/docker: Update SCYLLA_REPO_URL and VERSION defaults
Update the SCYLLA_REPO_URL and VERSION defaults to point to the latest
unstable 4.0 version. This will be used if someone runs "docker build"
locally. For the releases, the release pipelines will pass the stable
version repository URL and a specific release version.
2020-03-26 09:54:44 +02:00
Nadav Har'El
ce58994d30 sstable: default to LA format instead of KA format
Over the years, Scylla updated the sstable format from the KA format to
the LA format, and most recently to the MC format. On a mixed cluster -
as occurs during a rolling upgrade - we want all the nodes, even new ones,
to write sstables in the format preferred by the old version. The thinking
is that if the upgrade fails, and we want to downgrade all nodes back to
the older version, we don't want to lose data because we already have
too-new sstables.

So the current code starts by selecting the oldest format we ever had - KA,
and only switching this choice to LA and MC after we verify that all the
nodes in the cluster support these newer formats.

But before an agreement is reached on the new format, sstables may already
be created in the antique KA format. This is usually harmless - we can
read this format just fine. However, the KA format has a problem that it is
unable to represent table names or keyspaces with the "-" character in them,
because this character is used to separate the keyspace and table names in
the file name. For CQL, a "-" is not allowed anyway in keyspace or table
names; But for Alternator, this character is allowed - and if a KA table
happens to be created by accident (before the LA or MC formats are chosen),
it cannot be read again during boot, and Scylla cannot reboot.

The solution that this patch takes is to change Scylla's default sstable
format to LA (and, as before, if the entire cluster agrees, the newer MC
format will be used). From now on, new KA tables will never be written.
But we still fully support *reading* the KA format - this is important in
case some very old sstables never underwent compaction.

The old code had, confusingly, two places where the default KA format
was chosen. This patch fixes is so the new default (LA) is specified in
only one place.

Fixes #6071.

Signed-off-by: Nadav Har'El <nyh@scylladb.com>
Message-Id: <20200324232607.4215-2-nyh@scylladb.com>
(cherry picked from commit 91aba40114)
2020-03-25 13:27:51 +01:00
Yaron Kaikov
78f5afec30 release: prepare for 4.0.rc0 2020-03-24 23:33:23 +02:00
1669 changed files with 4031 additions and 11997 deletions

3
.gitmodules vendored
View File

@@ -6,6 +6,9 @@
path = swagger-ui
url = ../scylla-swagger-ui
ignore = dirty
[submodule "xxHash"]
path = xxHash
url = ../xxHash
[submodule "libdeflate"]
path = libdeflate
url = ../libdeflate

View File

@@ -1,7 +1,5 @@
This project includes code developed by the Apache Software Foundation (http://www.apache.org/),
especially Apache Cassandra.
It includes files from https://github.com/antonblanchard/crc32-vpmsum (author Anton Blanchard <anton@au.ibm.com>, IBM).
It also includes files from https://github.com/antonblanchard/crc32-vpmsum (author Anton Blanchard <anton@au.ibm.com>, IBM).
These files are located in utils/arch/powerpc/crc32-vpmsum. Their license may be found in licenses/LICENSE-crc32-vpmsum.TXT.
It includes modified code from https://gitbox.apache.org/repos/asf?p=cassandra-dtest.git (owned by The Apache Software Foundation)

View File

@@ -1,7 +1,7 @@
#!/bin/sh
PRODUCT=scylla
VERSION=4.1.11
VERSION=4.0.11
if test -f version
then

View File

@@ -129,7 +129,7 @@ future<std::string> get_key_from_roles(cql3::query_processor& qp, std::string us
auth::meta::roles_table::qualified_name(), auth::meta::roles_table::role_col_name);
auto cl = auth::password_authenticator::consistency_for_user(username);
auto& timeout = auth::internal_distributed_timeout_config();
auto timeout = auth::internal_distributed_timeout_config();
return qp.execute_internal(query, cl, timeout, {sstring(username)}, true).then_wrapped([username = std::move(username)] (future<::shared_ptr<cql3::untyped_result_set>> f) {
auto res = f.get0();
auto salted_hash = std::optional<sstring>();

View File

@@ -141,11 +141,6 @@ struct nonempty : public size_check {
// Check that array has the expected number of elements
static void verify_operand_count(const rjson::value* array, const size_check& expected, const rjson::value& op) {
if (!array && expected(0)) {
// If expected() allows an empty AttributeValueList, it is also fine
// that it is missing.
return;
}
if (!array || !array->IsArray()) {
throw api_error("ValidationException", "With ComparisonOperator, AttributeValueList must be given and an array");
}

View File

@@ -187,25 +187,6 @@ static schema_ptr get_table(service::storage_proxy& proxy, const rjson::value& r
}
}
static std::tuple<bool, std::string_view, std::string_view> try_get_internal_table(std::string_view table_name) {
size_t it = table_name.find(executor::INTERNAL_TABLE_PREFIX);
if (it != 0) {
return {false, "", ""};
}
table_name.remove_prefix(executor::INTERNAL_TABLE_PREFIX.size());
size_t delim = table_name.find_first_of('.');
if (delim == std::string_view::npos) {
return {false, "", ""};
}
std::string_view ks_name = table_name.substr(0, delim);
table_name.remove_prefix(ks_name.size() + 1);
// Only internal keyspaces can be accessed to avoid leakage
if (!is_internal_keyspace(sstring(ks_name))) {
return {false, "", ""};
}
return {true, ks_name, table_name};
}
// get_table_or_view() is similar to to get_table(), except it returns either
// a table or a materialized view from which to read, based on the TableName
// and optional IndexName in the request. Only requests like Query and Scan
@@ -215,17 +196,6 @@ static std::pair<schema_ptr, table_or_view_type>
get_table_or_view(service::storage_proxy& proxy, const rjson::value& request) {
table_or_view_type type = table_or_view_type::base;
std::string table_name = get_table_name(request);
auto [is_internal_table, internal_ks_name, internal_table_name] = try_get_internal_table(table_name);
if (is_internal_table) {
try {
return { proxy.get_db().local().find_schema(sstring(internal_ks_name), sstring(internal_table_name)), type };
} catch (no_such_column_family&) {
throw api_error("ResourceNotFoundException",
format("Requested resource not found: Internal table: {}.{} not found", internal_ks_name, internal_table_name));
}
}
std::string keyspace_name = executor::KEYSPACE_NAME_PREFIX + table_name;
const rjson::value* index_name = rjson::find(request, "IndexName");
std::string orig_table_name;
@@ -573,61 +543,24 @@ static bool validate_legal_tag_chars(std::string_view tag) {
return std::all_of(tag.begin(), tag.end(), &is_legal_tag_char);
}
static const std::unordered_set<std::string_view> allowed_write_isolation_values = {
"f", "forbid", "forbid_rmw",
"a", "always", "always_use_lwt",
"o", "only_rmw_uses_lwt",
"u", "unsafe", "unsafe_rmw",
};
static void validate_tags(const std::map<sstring, sstring>& tags) {
static const std::unordered_set<std::string_view> allowed_values = {
"f", "forbid", "forbid_rmw",
"a", "always", "always_use_lwt",
"o", "only_rmw_uses_lwt",
"u", "unsafe", "unsafe_rmw",
};
auto it = tags.find(rmw_operation::WRITE_ISOLATION_TAG_KEY);
if (it != tags.end()) {
std::string_view value = it->second;
if (allowed_write_isolation_values.count(value) == 0) {
elogger.warn("Allowed values count {} {}", value, allowed_values.count(value));
if (allowed_values.count(value) == 0) {
throw api_error("ValidationException",
format("Incorrect write isolation tag {}. Allowed values: {}", value, allowed_write_isolation_values));
format("Incorrect write isolation tag {}. Allowed values: {}", value, allowed_values));
}
}
}
static rmw_operation::write_isolation parse_write_isolation(std::string_view value) {
if (!value.empty()) {
switch (value[0]) {
case 'f':
return rmw_operation::write_isolation::FORBID_RMW;
case 'a':
return rmw_operation::write_isolation::LWT_ALWAYS;
case 'o':
return rmw_operation::write_isolation::LWT_RMW_ONLY;
case 'u':
return rmw_operation::write_isolation::UNSAFE_RMW;
}
}
// Shouldn't happen as validate_tags() / set_default_write_isolation()
// verify allow only a closed set of values.
return rmw_operation::default_write_isolation;
}
// This default_write_isolation is always overwritten in main.cc, which calls
// set_default_write_isolation().
rmw_operation::write_isolation rmw_operation::default_write_isolation =
rmw_operation::write_isolation::LWT_ALWAYS;
void rmw_operation::set_default_write_isolation(std::string_view value) {
if (value.empty()) {
throw std::runtime_error("When Alternator is enabled, write "
"isolation policy must be selected, using the "
"'--alternator-write-isolation' option. "
"See docs/alternator/alternator.md for instructions.");
}
if (allowed_write_isolation_values.count(value) == 0) {
throw std::runtime_error(format("Invalid --alternator-write-isolation "
"setting '{}'. Allowed values: {}.",
value, allowed_write_isolation_values));
}
default_write_isolation = parse_write_isolation(value);
}
// FIXME: Updating tags currently relies on updating schema, which may be subject
// to races during concurrent updates of the same table. Once Scylla schema updates
// are fixed, this issue will automatically get fixed as well.
@@ -735,25 +668,10 @@ future<executor::request_return_type> executor::list_tags_of_resource(client_sta
return make_ready_future<executor::request_return_type>(make_jsonable(std::move(ret)));
}
static future<> wait_for_schema_agreement(db::timeout_clock::time_point deadline) {
return do_until([deadline] {
if (db::timeout_clock::now() > deadline) {
throw std::runtime_error("Unable to reach schema agreement");
}
return service::get_local_migration_manager().have_schema_agreement();
}, [] {
return seastar::sleep(500ms);
});
}
future<executor::request_return_type> executor::create_table(client_state& client_state, tracing::trace_state_ptr trace_state, service_permit permit, rjson::value request) {
_stats.api_operations.create_table++;
elogger.trace("Creating table {}", request);
std::string table_name = get_table_name(request);
if (table_name.find(INTERNAL_TABLE_PREFIX) == 0) {
return make_ready_future<request_return_type>(api_error("ValidationException",
format("Prefix {} is reserved for accessing internal tables", INTERNAL_TABLE_PREFIX)));
}
std::string keyspace_name = executor::KEYSPACE_NAME_PREFIX + table_name;
const rjson::value& attribute_definitions = request["AttributeDefinitions"];
@@ -933,7 +851,7 @@ future<executor::request_return_type> executor::create_table(client_state& clien
}
return create_keyspace(keyspace_name).then([this, table_name, request = std::move(request), schema, view_builders = std::move(view_builders)] () mutable {
return futurize_invoke([&] { return _mm.announce_new_column_family(schema, false); }).then([this, table_info = std::move(request), schema, view_builders = std::move(view_builders)] () mutable {
return futurize_apply([&] { return _mm.announce_new_column_family(schema, false); }).then([this, table_info = std::move(request), schema, view_builders = std::move(view_builders)] () mutable {
return parallel_for_each(std::move(view_builders), [schema] (schema_builder builder) {
return service::get_local_migration_manager().announce_new_view(view_ptr(builder.build()));
}).then([this, table_info = std::move(table_info), schema] () mutable {
@@ -941,9 +859,7 @@ future<executor::request_return_type> executor::create_table(client_state& clien
if (rjson::find(table_info, "Tags")) {
f = add_tags(_mm, _proxy, schema, table_info);
}
return f.then([] {
return wait_for_schema_agreement(db::timeout_clock::now() + 10s);
}).then([table_info = std::move(table_info), schema] () mutable {
return f.then([table_info = std::move(table_info), schema] () mutable {
rjson::value status = rjson::empty_object();
supplement_table_info(table_info, *schema);
rjson::set(status, "TableDescription", std::move(table_info));
@@ -1183,6 +1099,13 @@ static lw_shared_ptr<query::read_command> previous_item_read_command(schema_ptr
return ::make_lw_shared<query::read_command>(schema->id(), schema->version(), partition_slice, query::max_partitions);
}
static lw_shared_ptr<query::read_command> read_nothing_read_command(schema_ptr schema) {
// Note that because this read-nothing command has an empty slice,
// storage_proxy::query() returns immediately - without any networking.
auto partition_slice = query::partition_slice({}, {}, {}, query::partition_slice::option_set());
return ::make_lw_shared<query::read_command>(schema->id(), schema->version(), partition_slice, query::max_partitions);
}
static dht::partition_range_vector to_partition_ranges(const schema& schema, const partition_key& pk) {
return dht::partition_range_vector{dht::partition_range(dht::decorate_key(schema, pk))};
}
@@ -1228,10 +1151,10 @@ rmw_operation::rmw_operation(service::storage_proxy& proxy, rjson::value&& reque
// the request).
}
std::optional<mutation> rmw_operation::apply(foreign_ptr<lw_shared_ptr<query::result>> qr, const query::partition_slice& slice, api::timestamp_type ts) {
if (qr->row_count()) {
std::optional<mutation> rmw_operation::apply(query::result& qr, const query::partition_slice& slice, api::timestamp_type ts) {
if (qr.row_count()) {
auto selection = cql3::selection::selection::wildcard(_schema);
auto previous_item = describe_item(_schema, slice, *selection, *qr, {});
auto previous_item = describe_item(_schema, slice, *selection, qr, {});
return apply(std::make_unique<rjson::value>(std::move(previous_item)), ts);
} else {
return apply(std::unique_ptr<rjson::value>(), ts);
@@ -1242,9 +1165,22 @@ rmw_operation::write_isolation rmw_operation::get_write_isolation_for_schema(sch
const auto& tags = get_tags_of_table(schema);
auto it = tags.find(WRITE_ISOLATION_TAG_KEY);
if (it == tags.end() || it->second.empty()) {
return default_write_isolation;
// By default, fall back to always enforcing LWT
return write_isolation::LWT_ALWAYS;
}
switch (it->second[0]) {
case 'f':
return write_isolation::FORBID_RMW;
case 'a':
return write_isolation::LWT_ALWAYS;
case 'o':
return write_isolation::LWT_RMW_ONLY;
case 'u':
return write_isolation::UNSAFE_RMW;
default:
// In case of an incorrect tag, fall back to the safest option: LWT_ALWAYS
return write_isolation::LWT_ALWAYS;
}
return parse_write_isolation(it->second);
}
// shard_for_execute() checks whether execute() must be called on a specific
@@ -1265,7 +1201,7 @@ std::optional<shard_id> rmw_operation::shard_for_execute(bool needs_read_before_
// find the appropriate shard to run it on:
auto token = dht::get_token(*_schema, _pk);
auto desired_shard = service::storage_proxy::cas_shard(*_schema, token);
if (desired_shard == this_shard_id()) {
if (desired_shard == engine().cpu_id()) {
return {};
}
return desired_shard;
@@ -1290,7 +1226,7 @@ future<executor::request_return_type> rmw_operation::execute(service::storage_pr
stats& stats) {
if (needs_read_before_write) {
if (_write_isolation == write_isolation::FORBID_RMW) {
throw api_error("ValidationException", "Read-modify-write operations are disabled by 'forbid_rmw' write isolation policy. Refer to https://github.com/scylladb/scylla/blob/master/docs/alternator/alternator.md#write-isolation-policies for more information.");
throw api_error("ValidationException", "Read-modify-write operations not supported");
}
stats.reads_before_write++;
if (_write_isolation == write_isolation::UNSAFE_RMW) {
@@ -1320,7 +1256,7 @@ future<executor::request_return_type> rmw_operation::execute(service::storage_pr
auto selection = cql3::selection::selection::wildcard(schema());
auto read_command = needs_read_before_write ?
previous_item_read_command(schema(), _ck, selection) :
nullptr;
read_nothing_read_command(schema());
return proxy.cas(schema(), shared_from_this(), read_command, to_partition_ranges(*schema(), _pk),
{timeout, std::move(permit), client_state, trace_state},
db::consistency_level::LOCAL_SERIAL, db::consistency_level::LOCAL_QUORUM, timeout, timeout).then([this, read_command] (bool is_applied) mutable {
@@ -1572,7 +1508,7 @@ public:
put_or_delete_item_cas_request(schema_ptr s, std::vector<put_or_delete_item>&& b) :
schema(std::move(s)), _mutation_builders(std::move(b)) { }
virtual ~put_or_delete_item_cas_request() = default;
virtual std::optional<mutation> apply(foreign_ptr<lw_shared_ptr<query::result>> qr, const query::partition_slice& slice, api::timestamp_type ts) override {
virtual std::optional<mutation> apply(query::result& qr, const query::partition_slice& slice, api::timestamp_type ts) override {
std::optional<mutation> ret;
for (const put_or_delete_item& mutation_builder : _mutation_builders) {
// We assume all these builders have the same partition.
@@ -1589,8 +1525,9 @@ public:
static future<> cas_write(service::storage_proxy& proxy, schema_ptr schema, dht::decorated_key dk, std::vector<put_or_delete_item>&& mutation_builders,
service::client_state& client_state, tracing::trace_state_ptr trace_state, service_permit permit) {
auto timeout = default_timeout();
auto read_command = read_nothing_read_command(schema);
auto op = seastar::make_shared<put_or_delete_item_cas_request>(schema, std::move(mutation_builders));
return proxy.cas(schema, op, nullptr, to_partition_ranges(dk),
return proxy.cas(schema, op, read_command, to_partition_ranges(dk),
{timeout, std::move(permit), client_state, trace_state},
db::consistency_level::LOCAL_SERIAL, db::consistency_level::LOCAL_QUORUM,
timeout, timeout).discard_result();
@@ -1666,7 +1603,7 @@ static future<> do_batch_write(service::storage_proxy& proxy,
return parallel_for_each(std::move(key_builders), [&proxy, &client_state, &stats, trace_state, ssg, permit = std::move(permit)] (auto& e) {
stats.write_using_lwt++;
auto desired_shard = service::storage_proxy::cas_shard(*e.first.schema, e.first.dk.token());
if (desired_shard == this_shard_id()) {
if (desired_shard == engine().cpu_id()) {
return cas_write(proxy, e.first.schema, e.first.dk, std::move(e.second), client_state, trace_state, permit);
} else {
stats.shard_bounce_for_lwt++;
@@ -2979,12 +2916,10 @@ static future<executor::request_return_type> do_query(schema_ptr schema,
auto regular_columns = boost::copy_range<query::column_id_vector>(
schema->regular_columns() | boost::adaptors::transformed([] (const column_definition& cdef) { return cdef.id; }));
auto static_columns = boost::copy_range<query::column_id_vector>(
schema->static_columns() | boost::adaptors::transformed([] (const column_definition& cdef) { return cdef.id; }));
auto selection = cql3::selection::selection::wildcard(schema);
query::partition_slice::option_set opts = selection->get_query_options();
opts.add(custom_opts);
auto partition_slice = query::partition_slice(std::move(ck_bounds), std::move(static_columns), std::move(regular_columns), opts);
auto partition_slice = query::partition_slice(std::move(ck_bounds), {}, std::move(regular_columns), opts);
auto command = ::make_lw_shared<query::read_command>(schema->id(), schema->version(), partition_slice, query::max_partitions);
auto query_state_ptr = std::make_unique<service::query_state>(client_state, trace_state, std::move(permit));

View File

@@ -50,7 +50,6 @@ public:
stats _stats;
static constexpr auto ATTRS_COLUMN_NAME = ":attrs";
static constexpr auto KEYSPACE_NAME_PREFIX = "alternator_";
static constexpr std::string_view INTERNAL_TABLE_PREFIX = ".scylla.alternator.";
executor(service::storage_proxy& proxy, service::migration_manager& mm, smp_service_group ssg)
: _proxy(proxy), _mm(mm), _ssg(ssg) {}

View File

@@ -123,7 +123,7 @@ protected:
std::string print(const rjson::value& value) {
string_buffer buffer;
guarded_yieldable_json_handler<writer, false> writer(buffer, 78);
guarded_yieldable_json_handler<writer, false> writer(buffer, 39);
value.Accept(writer);
return std::string(buffer.GetString());
}
@@ -133,7 +133,7 @@ rjson::value copy(const rjson::value& value) {
}
rjson::value parse(std::string_view str) {
guarded_yieldable_json_handler<document, false> d(78);
guarded_yieldable_json_handler<document, false> d(39);
d.Parse(str.data(), str.size());
if (d.HasParseError()) {
throw rjson::error(format("Parsing JSON failed: {}", GetParseError_En(d.GetParseError())));
@@ -143,7 +143,7 @@ rjson::value parse(std::string_view str) {
}
rjson::value parse_yieldable(std::string_view str) {
guarded_yieldable_json_handler<document, true> d(78);
guarded_yieldable_json_handler<document, true> d(39);
d.Parse(str.data(), str.size());
if (d.HasParseError()) {
throw rjson::error(format("Parsing JSON failed: {}", GetParseError_En(d.GetParseError())));

View File

@@ -63,10 +63,6 @@ public:
static write_isolation get_write_isolation_for_schema(schema_ptr schema);
static write_isolation default_write_isolation;
public:
static void set_default_write_isolation(std::string_view mode);
protected:
// The full request JSON
rjson::value _request;
@@ -111,7 +107,7 @@ public:
// "mutable" above so that apply() can still write to it.
virtual std::optional<mutation> apply(std::unique_ptr<rjson::value> previous_item, api::timestamp_type ts) const = 0;
// Convert the above apply() into the signature needed by cas_request:
virtual std::optional<mutation> apply(foreign_ptr<lw_shared_ptr<query::result>> qr, const query::partition_slice& slice, api::timestamp_type ts) override;
virtual std::optional<mutation> apply(query::result& qr, const query::partition_slice& slice, api::timestamp_type ts) override;
virtual ~rmw_operation() = default;
schema_ptr schema() const { return _schema; }
const rjson::value& request() const { return _request; }

View File

@@ -121,7 +121,7 @@ struct to_json_visitor {
}
// default
void operator()(const abstract_type& t) const {
rjson::set_with_string_name(deserialized, type_ident, rjson::parse(to_json_string(t, bytes(bv))));
rjson::set_with_string_name(deserialized, type_ident, rjson::parse(t.to_string(bytes(bv))));
}
};
@@ -153,9 +153,7 @@ std::string type_to_string(data_type type) {
};
auto it = types.find(type);
if (it == types.end()) {
// fall back to string, in order to be able to present
// internal Scylla types in a human-readable way
return "S";
throw std::runtime_error(format("Unknown type {}", type->name()));
}
return it->second;
}
@@ -207,11 +205,8 @@ rjson::value json_key_column_value(bytes_view cell, const column_definition& col
auto s = to_json_string(*decimal_type, bytes(cell));
return rjson::from_string(s);
} else {
// Support for arbitrary key types is useful for parsing values of virtual tables,
// which can involve any type supported by Scylla.
// In order to guarantee that the returned type is parsable by alternator clients,
// they are represented simply as strings.
return rjson::from_string(column.type->to_string(bytes(cell)));
// We shouldn't get here, we shouldn't see such key columns.
throw std::runtime_error(format("Unexpected key type: {}", column.type->name()));
}
}

View File

@@ -69,7 +69,7 @@ class api_handler : public handler_base {
public:
api_handler(const std::function<future<executor::request_return_type>(std::unique_ptr<request> req)>& _handle) : _f_handle(
[this, _handle](std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
return seastar::futurize_invoke(_handle, std::move(req)).then_wrapped([this, rep = std::move(rep)](future<executor::request_return_type> resf) mutable {
return seastar::futurize_apply(_handle, std::move(req)).then_wrapped([this, rep = std::move(rep)](future<executor::request_return_type> resf) mutable {
if (resf.failed()) {
// Exceptions of type api_error are wrapped as JSON and
// returned to the client as expected. Other types of
@@ -409,19 +409,15 @@ future<> server::init(net::inet_address addr, std::optional<uint16_t> port, std:
_http_server.set_content_length_limit(server::content_length_limit);
_http_server.listen(socket_address{addr, *port}).get();
_enabled_servers.push_back(std::ref(_http_server));
slogger.info("Alternator HTTP server listening on {} port {}", addr, *port);
}
if (https_port) {
set_routes(_https_server._routes);
_https_server.set_content_length_limit(server::content_length_limit);
_https_server.set_tls_credentials(creds->build_reloadable_server_credentials([](const std::unordered_set<sstring>& files, std::exception_ptr ep) {
if (ep) {
slogger.warn("Exception loading {}: {}", files, ep);
} else {
slogger.info("Reloaded {}", files);
}
}).get0());
_https_server.set_tls_credentials(creds->build_server_credentials());
_https_server.listen(socket_address{addr, *https_port}).get();
_enabled_servers.push_back(std::ref(_https_server));
slogger.info("Alternator HTTPS server listening on {} port {}", addr, *https_port);
}
} catch (...) {
slogger.error("Failed to set up Alternator HTTP server on {} port {}, TLS port {}: {}",

View File

@@ -380,54 +380,16 @@
"operations":[
{
"method":"GET",
"summary":"check if the auto_compaction property is enabled for a given table",
"summary":"check if the auto compaction disabled",
"type":"boolean",
"nickname":"get_auto_compaction",
"nickname":"is_auto_compaction_disabled",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The table name in keyspace:name format",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
},
{
"method":"POST",
"summary":"Enable table auto compaction",
"type":"void",
"nickname":"enable_auto_compaction",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The table name in keyspace:name format",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
},
{
"method":"DELETE",
"summary":"Disable table auto compaction",
"type":"void",
"nickname":"disable_auto_compaction",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The table name in keyspace:name format",
"description":"The column family name in keyspace:name format",
"required":true,
"allowMultiple":false,
"type":"string",

View File

@@ -208,11 +208,9 @@ void set_cache_service(http_context& ctx, routes& r) {
});
cs::get_row_capacity.set(r, [&ctx] (std::unique_ptr<request> req) {
return ctx.db.map_reduce0([](database& db) -> uint64_t {
return db.row_cache_tracker().region().occupancy().used_space();
}, uint64_t(0), std::plus<uint64_t>()).then([](const int64_t& res) {
return make_ready_future<json::json_return_type>(res);
});
return map_reduce_cf(ctx, uint64_t(0), [](const column_family& cf) {
return cf.get_row_cache().get_cache_tracker().region().occupancy().used_space();
}, std::plus<uint64_t>());
});
cs::get_row_hits.set(r, [&ctx] (std::unique_ptr<request> req) {
@@ -253,19 +251,15 @@ void set_cache_service(http_context& ctx, routes& r) {
cs::get_row_size.set(r, [&ctx] (std::unique_ptr<request> req) {
// In origin row size is the weighted size.
// We currently do not support weights, so we use num entries instead
return ctx.db.map_reduce0([](database& db) -> uint64_t {
return db.row_cache_tracker().partitions();
}, uint64_t(0), std::plus<uint64_t>()).then([](const int64_t& res) {
return make_ready_future<json::json_return_type>(res);
});
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
return cf.get_row_cache().partitions();
}, std::plus<uint64_t>());
});
cs::get_row_entries.set(r, [&ctx] (std::unique_ptr<request> req) {
return ctx.db.map_reduce0([](database& db) -> uint64_t {
return db.row_cache_tracker().partitions();
}, uint64_t(0), std::plus<uint64_t>()).then([](const int64_t& res) {
return make_ready_future<json::json_return_type>(res);
});
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
return cf.get_row_cache().partitions();
}, std::plus<uint64_t>());
});
cs::get_counter_capacity.set(r, [] (std::unique_ptr<request> req) {

View File

@@ -804,14 +804,14 @@ void set_column_family(http_context& ctx, routes& r) {
cf::get_cas_propose.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, req->param["name"], utils::estimated_histogram(0), [](column_family& cf) {
return cf.get_stats().estimated_cas_accept;
return cf.get_stats().estimated_cas_propose;
},
utils::estimated_histogram_merge, utils_json::estimated_histogram());
});
cf::get_cas_commit.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, req->param["name"], utils::estimated_histogram(0), [](column_family& cf) {
return cf.get_stats().estimated_cas_learn;
return cf.get_stats().estimated_cas_commit;
},
utils::estimated_histogram_merge, utils_json::estimated_histogram());
});
@@ -839,26 +839,11 @@ void set_column_family(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(res);
});
cf::get_auto_compaction.set(r, [&ctx] (const_req req) {
const utils::UUID& uuid = get_uuid(req.param["name"], ctx.db.local());
column_family& cf = ctx.db.local().find_column_family(uuid);
return !cf.is_auto_compaction_disabled_by_user();
});
cf::enable_auto_compaction.set(r, [&ctx](std::unique_ptr<request> req) {
return foreach_column_family(ctx, req->param["name"], [](column_family &cf) {
cf.enable_auto_compaction();
}).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
cf::disable_auto_compaction.set(r, [&ctx](std::unique_ptr<request> req) {
return foreach_column_family(ctx, req->param["name"], [](column_family &cf) {
cf.disable_auto_compaction();
}).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
cf::is_auto_compaction_disabled.set(r, [] (const_req req) {
// FIXME
// currently auto compaction is disable
// it should be changed when it would have an API
return true;
});
cf::get_built_indexes.set(r, [&ctx](std::unique_ptr<request> req) {

View File

@@ -37,9 +37,8 @@ void set_error_injection(http_context& ctx, routes& r) {
sstring injection = req->param["injection"];
bool one_shot = req->get_query_param("one_shot") == "True";
auto& errinj = utils::get_local_injector();
return errinj.enable_on_all(injection, one_shot).then([] {
return make_ready_future<json::json_return_type>(json::json_void());
});
errinj.enable_on_all(injection, one_shot);
return make_ready_future<json::json_return_type>(json::json_void());
});
hf::get_enabled_injections_on_all.set(r, [](std::unique_ptr<request> req) {
@@ -52,16 +51,14 @@ void set_error_injection(http_context& ctx, routes& r) {
sstring injection = req->param["injection"];
auto& errinj = utils::get_local_injector();
return errinj.disable_on_all(injection).then([] {
return make_ready_future<json::json_return_type>(json::json_void());
});
errinj.disable_on_all(injection);
return make_ready_future<json::json_return_type>(json::json_void());
});
hf::disable_on_all.set(r, [](std::unique_ptr<request> req) {
auto& errinj = utils::get_local_injector();
return errinj.disable_on_all().then([] {
return make_ready_future<json::json_return_type>(json::json_void());
});
errinj.disable_on_all();
return make_ready_future<json::json_return_type>(json::json_void());
});
}

View File

@@ -85,23 +85,6 @@ static auto wrap_ks_cf(http_context &ctx, ks_cf_func f) {
};
}
future<> set_tables_autocompaction(http_context& ctx, const sstring &keyspace, std::vector<sstring> tables, bool enabled) {
if (tables.empty()) {
tables = map_keys(ctx.db.local().find_keyspace(keyspace).metadata().get()->cf_meta_data());
}
return ctx.db.invoke_on_all([keyspace, tables, enabled] (database& db) {
return parallel_for_each(tables, [&db, keyspace, enabled](const sstring& table) mutable {
column_family& cf = db.find_column_family(keyspace, table);
if (enabled) {
cf.enable_auto_compaction();
} else {
cf.disable_auto_compaction();
}
return make_ready_future<>();
});
});
}
void set_storage_service(http_context& ctx, routes& r) {
ss::local_hostid.set(r, [](std::unique_ptr<request> req) {
return db::system_keyspace::get_local_host_id().then([](const utils::UUID& id) {
@@ -661,7 +644,7 @@ void set_storage_service(http_context& ctx, routes& r) {
ss::set_trace_probability.set(r, [](std::unique_ptr<request> req) {
auto probability = req->get_query_param("probability");
return futurize_invoke([probability] {
return futurize<json::json_return_type>::apply([probability] {
double real_prob = std::stod(probability.c_str());
return tracing::tracing::tracing_instance().invoke_on_all([real_prob] (auto& local_tracing) {
local_tracing.set_trace_probability(real_prob);
@@ -716,19 +699,19 @@ void set_storage_service(http_context& ctx, routes& r) {
});
ss::enable_auto_compaction.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto keyspace = validate_keyspace(ctx, req->param);
auto tables = split_cf(req->get_query_param("cf"));
return set_tables_autocompaction(ctx, keyspace, tables, true).then([]{
return make_ready_future<json::json_return_type>(json_void());
});
auto column_family = req->get_query_param("cf");
return make_ready_future<json::json_return_type>(json_void());
});
ss::disable_auto_compaction.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto keyspace = validate_keyspace(ctx, req->param);
auto tables = split_cf(req->get_query_param("cf"));
return set_tables_autocompaction(ctx, keyspace, tables, false).then([]{
return make_ready_future<json::json_return_type>(json_void());
});
auto column_family = req->get_query_param("cf");
return make_ready_future<json::json_return_type>(json_void());
});
ss::deliver_hints.set(r, [](std::unique_ptr<request> req) {

View File

@@ -22,7 +22,6 @@
#include "api/api-doc/system.json.hh"
#include "api/api.hh"
#include <seastar/core/reactor.hh>
#include <seastar/http/exception.hh>
#include "log.hh"

View File

@@ -65,16 +65,16 @@ static future<> create_metadata_table_if_missing_impl(
std::string_view cql,
::service::migration_manager& mm) {
static auto ignore_existing = [] (seastar::noncopyable_function<future<>()> func) {
return futurize_invoke(std::move(func)).handle_exception_type([] (exceptions::already_exists_exception& ignored) { });
return futurize_apply(std::move(func)).handle_exception_type([] (exceptions::already_exists_exception& ignored) { });
};
auto& db = qp.db();
auto parsed_statement = cql3::query_processor::parse_statement(cql);
auto& parsed_cf_statement = static_cast<cql3::statements::raw::cf_statement&>(*parsed_statement);
auto parsed_statement = static_pointer_cast<cql3::statements::raw::cf_statement>(
cql3::query_processor::parse_statement(cql));
parsed_cf_statement.prepare_keyspace(meta::AUTH_KS);
parsed_statement->prepare_keyspace(meta::AUTH_KS);
auto statement = static_pointer_cast<cql3::statements::create_table_statement>(
parsed_cf_statement.prepare(db, qp.get_cql_stats())->statement);
parsed_statement->prepare(db, qp.get_cql_stats())->statement);
const auto schema = statement->get_cf_meta_data(qp.db());
const auto uuid = generate_legacy_id(schema->ks_name(), schema->cf_name());
@@ -92,7 +92,7 @@ future<> create_metadata_table_if_missing(
cql3::query_processor& qp,
std::string_view cql,
::service::migration_manager& mm) noexcept {
return futurize_invoke(create_metadata_table_if_missing_impl, table_name, qp, cql, mm);
return futurize_apply(create_metadata_table_if_missing_impl, table_name, qp, cql, mm);
}
future<> wait_for_schema_agreement(::service::migration_manager& mm, const database& db, seastar::abort_source& as) {

View File

@@ -27,10 +27,9 @@
#include <seastar/core/future.hh>
#include <seastar/core/abort_source.hh>
#include <seastar/util/noncopyable_function.hh>
#include <seastar/core/seastar.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/resource.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/smp.hh>
#include "log.hh"
#include "seastarx.hh"
@@ -62,7 +61,7 @@ extern const sstring AUTH_PACKAGE_NAME;
template <class Task>
future<> once_among_shards(Task&& f) {
if (this_shard_id() == 0u) {
if (engine().cpu_id() == 0u) {
return f();
}

View File

@@ -51,7 +51,7 @@ extern "C" {
#include <boost/algorithm/string/join.hpp>
#include <boost/range.hpp>
#include <seastar/core/seastar.hh>
#include <seastar/core/reactor.hh>
#include "auth/authenticated_user.hh"
#include "auth/common.hh"

View File

@@ -48,7 +48,7 @@
#include <optional>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <seastar/core/seastar.hh>
#include <seastar/core/reactor.hh>
#include "auth/authenticated_user.hh"
#include "auth/common.hh"
@@ -230,7 +230,7 @@ future<authenticated_user> password_authenticator::authenticate(
// obsolete prepared statements pretty quickly.
// Rely on query processing caching statements instead, and lets assume
// that a map lookup string->statement is not gonna kill us much.
return futurize_invoke([this, username, password] {
return futurize_apply([this, username, password] {
static const sstring query = format("SELECT {} FROM {} WHERE {} = ?",
SALTED_HASH,
meta::roles_table::qualified_name(),

View File

@@ -419,7 +419,7 @@ future<> create_role(
return make_ready_future<>();
}
return futurize_invoke(
return futurize_apply(
&validate_authentication_options_are_supported,
options,
ser.underlying_authenticator().supported_options()).then([&ser, name, &options] {
@@ -443,7 +443,7 @@ future<> alter_role(
return make_ready_future<>();
}
return futurize_invoke(
return futurize_apply(
&validate_authentication_options_are_supported,
options,
ser.underlying_authenticator().supported_options()).then([&ser, name, &options] {

View File

@@ -158,7 +158,7 @@ public:
}
virtual future<authenticated_user> get_authenticated_user() const {
return futurize_invoke([this] {
return futurize_apply([this] {
return _sasl->get_authenticated_user().handle_exception([](auto ep) {
try {
std::rethrow_exception(ep);

View File

@@ -176,7 +176,7 @@ public:
return make_ready_future<>();
}
virtual future<> fast_forward_to(position_range pr, db::timeout_clock::time_point timeout) override {
return make_exception_future<>(make_backtraced_exception_ptr<std::bad_function_call>());
throw std::bad_function_call();
}
};

View File

@@ -1,65 +0,0 @@
/*
* Copyright (C) 2020 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 "cdc_partitioner.hh"
#include "dht/token.hh"
#include "schema.hh"
#include "sstables/key.hh"
#include "utils/class_registrator.hh"
#include "cdc/generation.hh"
#include "keys.hh"
static const sstring cdc_partitioner_name = "com.scylladb.dht.CDCPartitioner";
namespace cdc {
const sstring cdc_partitioner::name() const {
return cdc_partitioner_name;
}
static dht::token to_token(int64_t value) {
return dht::token(dht::token::kind::key, value);
}
static dht::token to_token(bytes_view key) {
// Key should be 16 B long, of which first 8 B are used for token calculation
if (key.size() != 2*sizeof(int64_t)) {
return dht::minimum_token();
}
return to_token(stream_id::token_from_bytes(key));
}
dht::token
cdc_partitioner::get_token(const sstables::key_view& key) const {
return to_token(bytes_view(key));
}
dht::token
cdc_partitioner::get_token(const schema& s, partition_key_view key) const {
auto exploded_key = key.explode(s);
return to_token(exploded_key[0]);
}
using registry = class_registrator<dht::i_partitioner, cdc_partitioner>;
static registry registrator(cdc_partitioner_name);
static registry registrator_short_name("CDCPartitioner");
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright (C) 2020 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/>.
*/
#pragma once
#include <seastar/core/sstring.hh>
#include "bytes.hh"
#include "dht/i_partitioner.hh"
class schema;
class partition_key_view;
namespace sstables {
class key_view;
}
namespace cdc {
struct cdc_partitioner final : public dht::i_partitioner {
cdc_partitioner() = default;
virtual const sstring name() const override;
virtual dht::token get_token(const schema& s, partition_key_view key) const override;
virtual dht::token get_token(const sstables::key_view& key) const override;
};
}

View File

@@ -80,7 +80,7 @@ bool stream_id::operator<(const stream_id& o) const {
return _value < o._value;
}
static int64_t bytes_to_int64(bytes_view b, size_t offset) {
static int64_t bytes_to_int64(const bytes& b, size_t offset) {
assert(b.size() >= offset + sizeof(int64_t));
int64_t res;
std::copy_n(b.begin() + offset, sizeof(int64_t), reinterpret_cast<int8_t *>(&res));
@@ -88,17 +88,13 @@ static int64_t bytes_to_int64(bytes_view b, size_t offset) {
}
int64_t stream_id::first() const {
return token_from_bytes(_value);
return bytes_to_int64(_value, 0);
}
int64_t stream_id::second() const {
return bytes_to_int64(_value, sizeof(int64_t));
}
int64_t stream_id::token_from_bytes(bytes_view b) {
return bytes_to_int64(b, 0);
}
const bytes& stream_id::to_bytes() const {
return _value;
}
@@ -123,110 +119,176 @@ const std::vector<token_range_description>& topology_description::entries() cons
return _entries;
}
static stream_id create_stream_id(dht::token t) {
static stream_id make_random_stream_id() {
static thread_local std::mt19937_64 rand_gen(std::random_device().operator()());
static thread_local std::uniform_int_distribution<int64_t> rand_dist(std::numeric_limits<int64_t>::min());
return {dht::token::to_int64(t), rand_dist(rand_gen)};
return {rand_dist(rand_gen), rand_dist(rand_gen)};
}
class topology_description_generator final {
const db::config& _cfg;
const std::unordered_set<dht::token>& _bootstrap_tokens;
const locator::token_metadata& _token_metadata;
const gms::gossiper& _gossiper;
// Compute a set of tokens that split the token ring into vnodes
auto get_tokens() const {
auto tokens = _token_metadata.sorted_tokens();
auto it = tokens.insert(
tokens.end(), _bootstrap_tokens.begin(), _bootstrap_tokens.end());
std::sort(it, tokens.end());
std::inplace_merge(tokens.begin(), it, tokens.end());
tokens.erase(std::unique(tokens.begin(), tokens.end()), tokens.end());
return tokens;
/* Given:
* 1. a set of tokens which split the token ring into token ranges (vnodes),
* 2. information on how each token range is distributed among its owning node's shards
* this function tries to generate a set of CDC stream identifiers such that for each
* shard and vnode pair there exists a stream whose token falls into this
* vnode and is owned by this shard.
*
* It then builds a cdc::topology_description which maps tokens to these
* found stream identifiers, such that if token T is owned by shard S in vnode V,
* it gets mapped to the stream identifier generated for (S, V).
*/
// Run in seastar::async context.
topology_description generate_topology_description(
const db::config& cfg,
const std::unordered_set<dht::token>& bootstrap_tokens,
const locator::token_metadata& token_metadata,
const gms::gossiper& gossiper) {
if (bootstrap_tokens.empty()) {
throw std::runtime_error(
"cdc: bootstrap tokens is empty in generate_topology_description");
}
// Fetch sharding parameters for a node that owns vnode ending with this.end
// Returns <shard_count, ignore_msb> pair.
std::pair<size_t, uint8_t> get_sharding_info(dht::token end) const {
if (_bootstrap_tokens.count(end) > 0) {
return {smp::count, _cfg.murmur3_partitioner_ignore_msb_bits()};
auto tokens = token_metadata.sorted_tokens();
tokens.insert(tokens.end(), bootstrap_tokens.begin(), bootstrap_tokens.end());
std::sort(tokens.begin(), tokens.end());
tokens.erase(std::unique(tokens.begin(), tokens.end()), tokens.end());
std::vector<token_range_description> entries(tokens.size());
int spots_to_fill = 0;
for (size_t i = 0; i < tokens.size(); ++i) {
auto& entry = entries[i];
entry.token_range_end = tokens[i];
if (bootstrap_tokens.count(entry.token_range_end) > 0) {
entry.streams.resize(smp::count);
entry.sharding_ignore_msb = cfg.murmur3_partitioner_ignore_msb_bits();
} else {
auto endpoint = _token_metadata.get_endpoint(end);
auto endpoint = token_metadata.get_endpoint(entry.token_range_end);
if (!endpoint) {
throw std::runtime_error(
format("Can't find endpoint for token {}", end));
throw std::runtime_error(format("Can't find endpoint for token {}", entry.token_range_end));
}
auto sc = get_shard_count(*endpoint, gossiper);
entry.streams.resize(sc > 0 ? sc : 1);
entry.sharding_ignore_msb = get_sharding_ignore_msb(*endpoint, gossiper);
}
spots_to_fill += entry.streams.size();
}
auto schema = schema_builder("fake_ks", "fake_table")
.with_column("stream_id", bytes_type, column_kind::partition_key)
.build();
auto quota = std::chrono::seconds(spots_to_fill / 2000 + 1);
auto start_time = std::chrono::system_clock::now();
// For each pair (i, j), 0 <= i < streams.size(), 0 <= j < streams[i].size(),
// try to find a stream (stream[i][j]) such that the token of this stream will get mapped to this stream
// (refer to the comments above topology_description's definition to understand how it describes the mapping).
// We find the streams by randomly generating them and checking into which pairs they get mapped.
// NOTE: this algorithm is temporary and will be replaced after per-table-partitioner feature gets merged in.
repeat([&] {
for (int i = 0; i < 500; ++i) {
auto stream_id = make_random_stream_id();
auto token = dht::get_token(*schema, stream_id.to_partition_key(*schema));
// Find the token range into which our stream_id's token landed.
auto it = std::lower_bound(tokens.begin(), tokens.end(), token);
auto& entry = entries[it != tokens.end() ? std::distance(tokens.begin(), it) : 0];
auto shard_id = dht::shard_of(entry.streams.size(), entry.sharding_ignore_msb, token);
assert(shard_id < entry.streams.size());
if (!entry.streams[shard_id].is_set()) {
--spots_to_fill;
entry.streams[shard_id] = stream_id;
}
}
if (!spots_to_fill) {
return stop_iteration::yes;
}
auto now = std::chrono::system_clock::now();
auto passed = std::chrono::duration_cast<std::chrono::seconds>(now - start_time);
if (passed > quota) {
return stop_iteration::yes;
}
return stop_iteration::no;
}).get();
if (spots_to_fill) {
// We were not able to generate stream ids for each (token range, shard) pair.
// For each range that has a stream, for each shard for this range that doesn't have a stream,
// use the stream id of the next shard for this range.
// For each range that doesn't have any stream,
// use streams of the first range to the left which does have a stream.
cdc_log.warn("Generation of CDC streams failed to create streams for some (vnode, shard) pair."
" This can lead to worse performance.");
stream_id some_stream;
size_t idx = 0;
for (; idx < entries.size(); ++idx) {
for (auto s: entries[idx].streams) {
if (s.is_set()) {
some_stream = s;
break;
}
}
if (some_stream.is_set()) {
break;
}
}
assert(idx != entries.size() && some_stream.is_set());
// Iterate over all ranges in the clockwise direction, starting with the one we found a stream for.
for (size_t off = 0; off < entries.size(); ++off) {
auto& ss = entries[(idx + off) % entries.size()].streams;
int last_set_stream_idx = ss.size() - 1;
while (last_set_stream_idx > -1 && !ss[last_set_stream_idx].is_set()) {
--last_set_stream_idx;
}
if (last_set_stream_idx == -1) {
cdc_log.warn(
"CDC wasn't able to generate any stream for vnode ({}, {}]. We'll use another vnode's streams"
" instead. This might lead to inconsistencies.",
tokens[(idx + off + entries.size() - 1) % entries.size()], tokens[(idx + off) % entries.size()]);
ss[0] = some_stream;
last_set_stream_idx = 0;
}
some_stream = ss[last_set_stream_idx];
// Replace 'unset' stream ids with indexes below last_set_stream_idx
for (int s_idx = last_set_stream_idx - 1; s_idx > -1; --s_idx) {
if (ss[s_idx].is_set()) {
some_stream = ss[s_idx];
} else {
ss[s_idx] = some_stream;
}
}
// Replace 'unset' stream ids with indexes above last_set_stream_idx
for (int s_idx = ss.size() - 1; s_idx > last_set_stream_idx; --s_idx) {
if (ss[s_idx].is_set()) {
some_stream = ss[s_idx];
} else {
ss[s_idx] = some_stream;
}
}
auto sc = get_shard_count(*endpoint, _gossiper);
return {sc > 0 ? sc : 1, get_sharding_ignore_msb(*endpoint, _gossiper)};
}
}
token_range_description create_description(dht::token start, dht::token end) const {
token_range_description desc;
desc.token_range_end = end;
auto [shard_count, ignore_msb] = get_sharding_info(end);
desc.streams.reserve(shard_count);
desc.sharding_ignore_msb = ignore_msb;
dht::sharder sharder(shard_count, ignore_msb);
for (size_t shard_idx = 0; shard_idx < shard_count; ++shard_idx) {
auto t = dht::find_first_token_for_shard(sharder, start, end, shard_idx);
desc.streams.push_back(create_stream_id(t));
}
return desc;
}
public:
topology_description_generator(
const db::config& cfg,
const std::unordered_set<dht::token>& bootstrap_tokens,
const locator::token_metadata& token_metadata,
const gms::gossiper& gossiper)
: _cfg(cfg)
, _bootstrap_tokens(bootstrap_tokens)
, _token_metadata(token_metadata)
, _gossiper(gossiper)
{
if (_bootstrap_tokens.empty()) {
throw std::runtime_error(
"cdc: bootstrap tokens is empty in generate_topology_description");
}
}
/*
* Generate a set of CDC stream identifiers such that for each shard
* and vnode pair there exists a stream whose token falls into this vnode
* and is owned by this shard. It is sometimes not possible to generate
* a CDC stream identifier for some (vnode, shard) pair because not all
* shards have to own tokens in a vnode. Small vnode can be totally owned
* by a single shard. In such case, a stream identifier that maps to
* end of the vnode is generated.
*
* Then build a cdc::topology_description which maps tokens to generated
* stream identifiers, such that if token T is owned by shard S in vnode V,
* it gets mapped to the stream identifier generated for (S, V).
*/
// Run in seastar::async context.
topology_description generate() const {
const auto tokens = get_tokens();
std::vector<token_range_description> vnode_descriptions;
vnode_descriptions.reserve(tokens.size());
vnode_descriptions.push_back(
create_description(tokens.back(), tokens.front()));
for (size_t idx = 1; idx < tokens.size(); ++idx) {
vnode_descriptions.push_back(
create_description(tokens[idx - 1], tokens[idx]));
}
return {std::move(vnode_descriptions)};
}
};
return {std::move(entries)};
}
bool should_propose_first_generation(const gms::inet_address& me, const gms::gossiper& g) {
auto my_host_id = g.get_host_id(me);
@@ -259,7 +321,7 @@ db_clock::time_point make_new_cdc_generation(
bool for_testing) {
assert(!bootstrap_tokens.empty());
auto gen = topology_description_generator(cfg, bootstrap_tokens, tm, g).generate();
auto gen = generate_topology_description(cfg, bootstrap_tokens, tm, g);
// Begin the race.
auto ts = db_clock::now() + (
@@ -273,7 +335,12 @@ db_clock::time_point make_new_cdc_generation(
std::optional<db_clock::time_point> get_streams_timestamp_for(const gms::inet_address& endpoint, const gms::gossiper& g) {
auto streams_ts_string = g.get_application_state_value(endpoint, gms::application_state::CDC_STREAMS_TIMESTAMP);
cdc_log.trace("endpoint={}, streams_ts_string={}", endpoint, streams_ts_string);
return gms::versioned_value::cdc_streams_timestamp_from_string(streams_ts_string);
if (streams_ts_string.empty()) {
return {};
}
return db_clock::time_point(db_clock::duration(std::stoll(streams_ts_string)));
}
// Run inside seastar::async context.

View File

@@ -77,7 +77,6 @@ public:
const bytes& to_bytes() const;
partition_key to_partition_key(const schema& log_schema) const;
static int64_t token_from_bytes(bytes_view);
};
/* Describes a mapping of tokens to CDC streams in a token range.
@@ -130,7 +129,7 @@ bool should_propose_first_generation(const gms::inet_address& me, const gms::gos
*/
future<db_clock::time_point> get_local_streams_timestamp();
/* Generate a new set of CDC streams and insert it into the distributed cdc_generations table.
/* Generate a new set of CDC streams and insert it into the distributed cdc_topology_description table.
* Returns the timestamp of this new generation.
*
* Should be called when starting the node for the first time (i.e., joining the ring).
@@ -159,9 +158,9 @@ db_clock::time_point make_new_cdc_generation(
std::optional<db_clock::time_point> get_streams_timestamp_for(const gms::inet_address& endpoint, const gms::gossiper&);
/* Inform CDC users about a generation of streams (identified by the given timestamp)
* by inserting it into the cdc_streams table.
* by inserting it into the cdc_description table.
*
* Assumes that the cdc_generations table contains this generation.
* Assumes that the cdc_topology_description table contains this generation.
*
* Returning from this function does not mean that the table update was successful: the function
* might run an asynchronous task in the background.

View File

@@ -239,8 +239,7 @@ public:
future<std::tuple<std::vector<mutation>, lw_shared_ptr<cdc::operation_result_tracker>>> augment_mutation_call(
lowres_clock::time_point timeout,
std::vector<mutation>&& mutations,
tracing::trace_state_ptr tr_state,
db::consistency_level write_cl
tracing::trace_state_ptr tr_state
);
template<typename Iter>
@@ -391,7 +390,6 @@ bytes log_data_column_deleted_elements_name_bytes(const bytes& column_name) {
static schema_ptr create_log_schema(const schema& s, std::optional<utils::UUID> uuid) {
schema_builder b(s.ks_name(), log_name(s.cf_name()));
b.with_partitioner("com.scylladb.dht.CDCPartitioner");
b.set_comment(sprint("CDC log for %s.%s", s.ks_name(), s.cf_name()));
b.with_column(log_meta_column_name_bytes("stream_id"), bytes_type, column_kind::partition_key);
b.with_column(log_meta_column_name_bytes("time"), timeuuid_type, column_kind::clustering_key);
@@ -401,9 +399,9 @@ static schema_ptr create_log_schema(const schema& s, std::optional<utils::UUID>
auto add_columns = [&] (const schema::const_iterator_range_type& columns, bool is_data_col = false) {
for (const auto& column : columns) {
auto type = column.type;
if (is_data_col && type->is_multi_cell()) {
if (is_data_col) {
type = visit(*type, make_visitor(
// non-frozen lists are represented as map<timeuuid, value_type>. Otherwise we cannot express delta
// lists are represented as map<timeuuid, value_type>. Otherwise we cannot express delta
[] (const list_type_impl& type) -> data_type {
return map_type_impl::get_instance(type.name_comparator(), type.value_comparator(), false);
},
@@ -412,6 +410,7 @@ static schema_ptr create_log_schema(const schema& s, std::optional<utils::UUID>
return type.freeze();
}
));
type = type->freeze();
}
b.with_column(log_data_column_name_bytes(column.name()), type);
if (is_data_col) {
@@ -716,19 +715,6 @@ private:
const column_definition& _op_col;
const column_definition& _ttl_col;
ttl_opt _cdc_ttl_opt;
/**
* #6070
* When mutation splitting was added, non-atomic column assignments were broken
* into two invocation of transform. This means the second (actual data assignment)
* does not know about the tombstone in first one -> postimage is created as if
* we were _adding_ to the collection, not replacing it.
*
* Not pretty, but to handle this we use the knowledge that we always get
* invoked in timestamp order -> tombstone first, then assign.
* So we simply keep track of non-atomic columns deleted across calls
* and filter out preimage data post this.
*/
std::unordered_set<const column_definition*> _non_atomic_column_deletes;
clustering_key set_pk_columns(const partition_key& pk, api::timestamp_type ts, bytes decomposed_tuuid, int batch_no, mutation& m) const {
const auto log_ck = clustering_key::from_exploded(
@@ -830,18 +816,18 @@ public:
// TODO: is pre-image data based on query enough. We only have actual column data. Do we need
// more details like tombstones/ttl? Probably not but keep in mind.
std::tuple<mutation, stats::part_type_set> transform(const mutation& m, const cql3::untyped_result_set* rs, api::timestamp_type ts, bytes tuuid, int& batch_no) {
std::tuple<mutation, stats::part_type_set> transform(const mutation& m, const cql3::untyped_result_set* rs, api::timestamp_type ts, bytes tuuid, int& batch_no) const {
auto stream_id = _ctx._cdc_metadata.get_stream(ts, m.token());
mutation res(_log_schema, stream_id.to_partition_key(*_log_schema));
const auto preimage = _schema->cdc_options().preimage();
const auto postimage = _schema->cdc_options().postimage();
stats::part_type_set touched_parts;
auto& p = m.partition();
if (p.partition_tombstone()) {
// Partition deletion
touched_parts.set<stats::part_type::PARTITION_DELETE>();
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
auto log_ck = set_pk_columns(m.key(), ts, tuuid, 0, res);
set_operation(log_ck, ts, operation::partition_delete, res);
++batch_no;
} else if (!p.row_tombstones().empty()) {
// range deletion
touched_parts.set<stats::part_type::RANGE_TOMBSTONE>();
@@ -863,30 +849,37 @@ public:
}
};
{
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
set_bound(log_ck, rt.start);
const auto start_operation = rt.start_kind == bound_kind::incl_start
? operation::range_delete_start_inclusive
: operation::range_delete_start_exclusive;
set_operation(log_ck, ts, start_operation, res);
++batch_no;
}
{
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
set_bound(log_ck, rt.end);
const auto end_operation = rt.end_kind == bound_kind::incl_end
? operation::range_delete_end_inclusive
: operation::range_delete_end_exclusive;
set_operation(log_ck, ts, end_operation, res);
++batch_no;
}
}
} else {
// should be insert, update or deletion
auto process_cells = [&](const row& r, column_kind ckind, const clustering_key& log_ck, std::optional<clustering_key> pikey, const cql3::untyped_result_set_row* pirow, std::optional<clustering_key> poikey) -> std::optional<gc_clock::duration> {
if (postimage && !poikey) {
poikey = set_pk_columns(m.key(), ts, tuuid, ++batch_no, res);
set_operation(*poikey, ts, operation::post_image, res);
}
std::optional<gc_clock::duration> ttl;
std::unordered_set<column_id> columns_assigned;
r.for_each_cell([&](column_id id, const atomic_cell_or_collection& cell) {
auto& cdef = _schema->column_at(ckind, id);
auto* dst = _log_schema->get_column_definition(log_data_column_name_bytes(cdef.name()));
auto has_pirow = pirow && pirow->has(cdef.name_as_text());
bool is_column_delete = true;
bytes_opt value;
bytes_opt deleted_elements = std::nullopt;
@@ -1007,30 +1000,29 @@ public:
}
}
bytes_opt prev = get_preimage_col_value(cdef, pirow);
if (is_column_delete) {
res.set_cell(log_ck, log_data_column_deleted_name_bytes(cdef.name()), data_value(true), ts, _cdc_ttl_opt);
}
if (value) {
res.set_cell(log_ck, *dst, atomic_cell::make_live(*dst->type, ts, *value, _cdc_ttl_opt));
}
if (prev && pikey) {
bytes_opt prev;
if (has_pirow) {
prev = get_preimage_col_value(cdef, pirow);
assert(std::addressof(res.partition().clustered_row(*_log_schema, *pikey)) != std::addressof(res.partition().clustered_row(*_log_schema, log_ck)));
assert(pikey->explode() != log_ck.explode());
res.set_cell(*pikey, *dst, atomic_cell::make_live(*dst->type, ts, *prev, _cdc_ttl_opt));
}
if (is_column_delete) {
res.set_cell(log_ck, log_data_column_deleted_name_bytes(cdef.name()), data_value(true), ts, _cdc_ttl_opt);
if (!cdef.is_atomic()) {
_non_atomic_column_deletes.insert(&cdef);
}
// don't merge with pre-image iff column delete
prev = std::nullopt;
}
if (value) {
res.set_cell(log_ck, *dst, atomic_cell::make_live(*dst->type, ts, *value, _cdc_ttl_opt));
}
if (poikey) {
if (postimage) {
// keep track of actually assigning this already
columns_assigned.emplace(id);
// don't merge with pre-image iff column delete
if (is_column_delete) {
prev = std::nullopt;
}
if (cdef.is_atomic() && !is_column_delete && value) {
res.set_cell(*poikey, *dst, atomic_cell::make_live(*dst->type, ts, *value, _cdc_ttl_opt));
} else if (!cdef.is_atomic() && (value || (deleted_elements && prev))) {
@@ -1043,10 +1035,10 @@ public:
});
// fill in all columns not already processed. Note that column nulls are also marked.
if (poikey && pirow) {
if (postimage && pirow) {
for (auto& cdef : _schema->columns(ckind)) {
if (!columns_assigned.count(cdef.id)) {
auto v = get_preimage_col_value(cdef, pirow);
auto v = pirow->get_view_opt(cdef.name_as_text());
if (v) {
auto dst = _log_schema->get_column_definition(log_data_column_name_bytes(cdef.name()));
res.set_cell(*poikey, *dst, atomic_cell::make_live(*dst->type, ts, *v, _cdc_ttl_opt));
@@ -1065,18 +1057,16 @@ public:
if (rs && !rs->empty()) {
// For static rows, only one row from the result set is needed
pirow = &rs->front();
}
if (preimage && pirow) {
pikey = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
pikey = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
set_operation(*pikey, ts, operation::pre_image, res);
pirow = &rs->front();
++batch_no;
}
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
if (postimage) {
poikey = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
poikey = set_pk_columns(m.key(), ts, tuuid, ++batch_no, res);
set_operation(*poikey, ts, operation::post_image, res);
}
@@ -1087,6 +1077,7 @@ public:
if (ttl) {
set_ttl(log_ck, ts, *ttl, res);
}
++batch_no;
} else {
touched_parts.set_if<stats::part_type::CLUSTERING_ROW>(!p.clustered_rows().empty());
for (const rows_entry& r : p.clustered_rows()) {
@@ -1107,21 +1098,19 @@ public:
}
}
if (match) {
pikey = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
set_operation(*pikey, ts, operation::pre_image, res);
pirow = &utr;
++batch_no;
break;
}
}
}
if (preimage && pirow) {
pikey = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
set_operation(*pikey, ts, operation::pre_image, res);
}
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
auto log_ck = set_pk_columns(m.key(), ts, tuuid, batch_no, res);
if (postimage) {
poikey = set_pk_columns(m.key(), ts, tuuid, batch_no++, res);
poikey = set_pk_columns(m.key(), ts, tuuid, ++batch_no, res);
set_operation(*poikey, ts, operation::post_image, res);
}
@@ -1131,7 +1120,7 @@ public:
auto cdef = _log_schema->get_column_definition(log_data_column_name_bytes(column.name()));
res.set_cell(log_ck, *cdef, atomic_cell::make_live(*column.type, ts, bytes_view(ck_value[pos]), _cdc_ttl_opt));
if (pikey) {
if (pirow) {
assert(pirow->has(column.name_as_text()));
res.set_cell(*pikey, *cdef, atomic_cell::make_live(*column.type, ts, bytes_view(ck_value[pos]), _cdc_ttl_opt));
}
@@ -1150,8 +1139,8 @@ public:
for (const column_definition& column: _schema->regular_columns()) {
assert(pirow->has(column.name_as_text()));
auto& cdef = *_log_schema->get_column_definition(log_data_column_name_bytes(column.name()));
auto value = get_preimage_col_value(column, pirow);
res.set_cell(*pikey, cdef, atomic_cell::make_live(*column.type, ts, bytes_view(*value), _cdc_ttl_opt));
auto value = get_preimage_col_value(column, pirow);
res.set_cell(*pikey, cdef, atomic_cell::make_live(*column.type, ts, bytes_view(value), _cdc_ttl_opt));
}
}
} else {
@@ -1168,6 +1157,7 @@ public:
}
}
set_operation(log_ck, ts, cdc_op, res);
++batch_no;
}
}
}
@@ -1175,13 +1165,7 @@ public:
return std::make_tuple(std::move(res), touched_parts);
}
bytes_opt get_preimage_col_value(const column_definition& cdef, const cql3::untyped_result_set_row *pirow) {
/**
* #6070 - see comment for _non_atomic_column_deletes
*/
if (!pirow || !pirow->has(cdef.name_as_text()) || _non_atomic_column_deletes.count(&cdef)) {
return std::nullopt;
}
static bytes get_preimage_col_value(const column_definition& cdef, const cql3::untyped_result_set_row *pirow) {
return cdef.is_atomic()
? pirow->get_blob(cdef.name_as_text())
: visit(*cdef.type, make_visitor(
@@ -1210,7 +1194,7 @@ public:
future<lw_shared_ptr<cql3::untyped_result_set>> pre_image_select(
service::client_state& client_state,
db::consistency_level write_cl,
db::consistency_level cl,
const mutation& m)
{
auto& p = m.partition();
@@ -1291,10 +1275,7 @@ public:
auto partition_slice = query::partition_slice(std::move(bounds), std::move(static_columns), std::move(regular_columns), std::move(opts));
auto command = ::make_lw_shared<query::read_command>(_schema->id(), _schema->version(), partition_slice, row_limit);
const auto select_cl = adjust_cl(write_cl);
try {
return _ctx._proxy.query(_schema, std::move(command), std::move(partition_ranges), select_cl, service::storage_proxy::coordinator_query_options(default_timeout(), empty_service_permit(), client_state)).then(
return _ctx._proxy.query(_schema, std::move(command), std::move(partition_ranges), cl, service::storage_proxy::coordinator_query_options(default_timeout(), empty_service_permit(), client_state)).then(
[s = _schema, partition_slice = std::move(partition_slice), selection = std::move(selection)] (service::storage_proxy::coordinator_query_result qr) -> lw_shared_ptr<cql3::untyped_result_set> {
cql3::selection::result_set_builder builder(*selection, gc_clock::now(), cql_serialization_format::latest());
query::result_view::consume(*qr.query_result, partition_slice, cql3::selection::result_set_builder::visitor(builder, *s, *selection));
@@ -1304,25 +1285,6 @@ public:
}
return make_lw_shared<cql3::untyped_result_set>(*result_set);
});
} catch (exceptions::unavailable_exception& e) {
// `query` can throw `unavailable_exception`, which is seen by clients as ~ "NoHostAvailable".
// So, we'll translate it to a `read_failure_exception` with custom message.
cdc_log.debug("Preimage: translating a (read) `unavailable_exception` to `request_execution_exception` - {}", e);
throw exceptions::read_failure_exception("CDC preimage query could not achieve the CL.",
e.consistency, e.alive, 0, e.required, false);
}
}
/** For preimage query use the same CL as for base write, except for CLs ANY and ALL. */
static db::consistency_level adjust_cl(db::consistency_level write_cl) {
if (write_cl == db::consistency_level::ANY) {
return db::consistency_level::ONE;
} else if (write_cl == db::consistency_level::ALL || write_cl == db::consistency_level::SERIAL) {
return db::consistency_level::QUORUM;
} else if (write_cl == db::consistency_level::LOCAL_SERIAL) {
return db::consistency_level::LOCAL_QUORUM;
}
return write_cl;
}
};
@@ -1338,7 +1300,7 @@ transform_mutations(std::vector<mutation>& muts, decltype(muts.size()) batch_siz
} // namespace cdc
future<std::tuple<std::vector<mutation>, lw_shared_ptr<cdc::operation_result_tracker>>>
cdc::cdc_service::impl::augment_mutation_call(lowres_clock::time_point timeout, std::vector<mutation>&& mutations, tracing::trace_state_ptr tr_state, db::consistency_level write_cl) {
cdc::cdc_service::impl::augment_mutation_call(lowres_clock::time_point timeout, std::vector<mutation>&& mutations, tracing::trace_state_ptr tr_state) {
// we do all this because in the case of batches, we can have mixed schemas.
auto e = mutations.end();
auto i = std::find_if(mutations.begin(), e, [](const mutation& m) {
@@ -1353,8 +1315,8 @@ cdc::cdc_service::impl::augment_mutation_call(lowres_clock::time_point timeout,
mutations.reserve(2 * mutations.size());
return do_with(std::move(mutations), service::query_state(service::client_state::for_internal_calls(), empty_service_permit()), operation_details{},
[this, timeout, i, tr_state = std::move(tr_state), write_cl] (std::vector<mutation>& mutations, service::query_state& qs, operation_details& details) {
return transform_mutations(mutations, 1, [this, &mutations, timeout, &qs, tr_state = tr_state, &details, write_cl] (int idx) mutable {
[this, timeout, i, tr_state = std::move(tr_state)] (std::vector<mutation>& mutations, service::query_state& qs, operation_details& details) {
return transform_mutations(mutations, 1, [this, &mutations, timeout, &qs, tr_state = tr_state, &details] (int idx) mutable {
auto& m = mutations[idx];
auto s = m.schema();
@@ -1370,7 +1332,7 @@ cdc::cdc_service::impl::augment_mutation_call(lowres_clock::time_point timeout,
// iff a batch contains several modifications to the same table. Otoh, batch is rare(?)
// so this is premature.
tracing::trace(tr_state, "CDC: Selecting preimage for {}", m.decorated_key());
f = trans.pre_image_select(qs.get_client_state(), write_cl, m).then_wrapped([this] (future<lw_shared_ptr<cql3::untyped_result_set>> f) {
f = trans.pre_image_select(qs.get_client_state(), db::consistency_level::LOCAL_QUORUM, m).then_wrapped([this] (future<lw_shared_ptr<cql3::untyped_result_set>> f) {
auto& cdc_stats = _ctxt._proxy.get_cdc_stats();
cdc_stats.counters_total.preimage_selects++;
if (f.failed()) {
@@ -1382,7 +1344,7 @@ cdc::cdc_service::impl::augment_mutation_call(lowres_clock::time_point timeout,
tracing::trace(tr_state, "CDC: Preimage not enabled for the table, not querying current value of {}", m.decorated_key());
}
return f.then([trans = std::move(trans), &mutations, idx, tr_state = std::move(tr_state), &details] (lw_shared_ptr<cql3::untyped_result_set> rs) mutable {
return f.then([trans = std::move(trans), &mutations, idx, tr_state = std::move(tr_state), &details] (lw_shared_ptr<cql3::untyped_result_set> rs) {
auto& m = mutations[idx];
auto& s = m.schema();
details.had_preimage |= s->cdc_options().preimage();
@@ -1427,6 +1389,6 @@ bool cdc::cdc_service::needs_cdc_augmentation(const std::vector<mutation>& mutat
}
future<std::tuple<std::vector<mutation>, lw_shared_ptr<cdc::operation_result_tracker>>>
cdc::cdc_service::augment_mutation_call(lowres_clock::time_point timeout, std::vector<mutation>&& mutations, tracing::trace_state_ptr tr_state, db::consistency_level write_cl) {
return _impl->augment_mutation_call(timeout, std::move(mutations), std::move(tr_state), write_cl);
cdc::cdc_service::augment_mutation_call(lowres_clock::time_point timeout, std::vector<mutation>&& mutations, tracing::trace_state_ptr tr_state) {
return _impl->augment_mutation_call(timeout, std::move(mutations), std::move(tr_state));
}

View File

@@ -91,8 +91,7 @@ public:
future<std::tuple<std::vector<mutation>, lw_shared_ptr<operation_result_tracker>>> augment_mutation_call(
lowres_clock::time_point timeout,
std::vector<mutation>&& mutations,
tracing::trace_state_ptr tr_state,
db::consistency_level write_cl
tracing::trace_state_ptr tr_state
);
bool needs_cdc_augmentation(const std::vector<mutation>&) const;
};

View File

@@ -22,7 +22,7 @@
#pragma once
#include "seastar/core/file.hh"
#include "seastar/core/seastar.hh"
#include "seastar/core/reactor.hh"
#include "utils/disk-error-handler.hh"
#include "seastarx.hh"
@@ -147,7 +147,7 @@ inline open_checked_directory(const io_error_handler& error_handler,
sstring name)
{
return do_io_check(error_handler, [&] {
return open_directory(name).then([&] (file f) {
return engine().open_directory(name).then([&] (file f) {
return make_ready_future<file>(make_checked_file(error_handler, f));
});
});

View File

@@ -140,9 +140,6 @@ public:
uint64_t adjust_partition_estimate(const mutation_source_metadata& ms_meta, uint64_t partition_estimate);
reader_consumer make_interposer_consumer(const mutation_source_metadata& ms_meta, reader_consumer end_consumer);
// Returns whether or not interposer consumer is used by a given strategy.
bool use_interposer_consumer() const;
};
// Creates a compaction_strategy object from one of the strategies available.

View File

@@ -27,9 +27,6 @@
#include "schema.hh"
#include "sstables/version.hh"
//FIXME: de-inline methods and define this as static in a .cc file.
extern logging::logger compound_logger;
//
// This header provides adaptors between the representation used by our compound_type<>
// and representation used by Origin.
@@ -340,9 +337,8 @@ public:
class iterator : public std::iterator<std::input_iterator_tag, const component_view> {
bytes_view _v;
component_view _current;
bool _strict_mode = true;
private:
void do_read_current() {
void read_current() {
size_type len;
{
if (_v.empty()) {
@@ -358,23 +354,11 @@ public:
_v.remove_prefix(len);
_current = component_view(std::move(value), to_eoc(read_simple<eoc_type>(_v)));
}
void read_current() {
try {
do_read_current();
} catch (marshal_exception&) {
if (_strict_mode) {
on_internal_error(compound_logger, std::current_exception());
} else {
throw;
}
}
}
public:
struct end_iterator_tag {};
// In strict-mode de-serialization errors will invoke `on_internal_error()`.
iterator(const bytes_view& v, bool is_compound, bool is_static, bool strict_mode = true)
: _v(v), _strict_mode(strict_mode) {
iterator(const bytes_view& v, bool is_compound, bool is_static)
: _v(v) {
if (is_static) {
_v.remove_prefix(2);
}
@@ -388,7 +372,6 @@ public:
iterator(end_iterator_tag) : _v(nullptr, 0) {}
public:
iterator& operator++() {
read_current();
return *this;
@@ -404,9 +387,6 @@ public:
const value_type* operator->() const { return &_current; }
bool operator!=(const iterator& i) const { return _v.begin() != i._v.begin(); }
bool operator==(const iterator& i) const { return _v.begin() == i._v.begin(); }
friend class composite;
friend class composite_view;
};
iterator begin() const {
@@ -575,21 +555,6 @@ public:
return composite::is_static(_bytes, _is_compound);
}
bool is_valid() const {
try {
auto it = composite::iterator(_bytes, _is_compound, is_static(), false);
const auto end = composite::iterator(composite::iterator::end_iterator_tag());
size_t s = 0;
for (; it != end; ++it) {
auto& c = *it;
s += c.first.size() + sizeof(composite::size_type) + sizeof(composite::eoc_type);
}
return s == _bytes.size();
} catch (marshal_exception&) {
return false;
}
}
explicit operator bytes_view() const {
return _bytes;
}

View File

@@ -253,11 +253,11 @@ modes = {
},
'release': {
'cxxflags': '',
'cxx_ld_flags': '-O3 -Wstack-usage=%s' % (1024*13),
'cxx_ld_flags': '-O3 -Wstack-usage=%s' % (1024*29),
},
'dev': {
'cxxflags': '-DSEASTAR_ENABLE_ALLOC_FAILURE_INJECTION -DSCYLLA_ENABLE_ERROR_INJECTION',
'cxx_ld_flags': '-O1 -Wstack-usage=%s' % (1024*21),
'cxx_ld_flags': '-O1 -Wstack-usage=%s' % (1024*29),
},
'sanitize': {
'cxxflags': '-DDEBUG -DDEBUG_LSA_SANITIZER -DSCYLLA_ENABLE_ERROR_INJECTION',
@@ -419,7 +419,6 @@ perf_tests = set([
apps = set([
'scylla',
'test/tools/cql_repl',
'tools/scylla_types',
])
tests = scylla_tests | perf_tests
@@ -440,7 +439,6 @@ arg_parser.add_argument('--so', dest='so', action='store_true',
help='Build shared object (SO) instead of executable')
arg_parser.add_argument('--mode', action='append', choices=list(modes.keys()), dest='selected_modes')
arg_parser.add_argument('--with', dest='artifacts', action='append', choices=all_artifacts, default=[])
arg_parser.add_argument('--with-seastar', action='store', dest='seastar_path', default='seastar', help='Path to Seastar sources')
arg_parser.add_argument('--cflags', action='store', dest='user_cflags', default='',
help='Extra flags for the C++ compiler')
arg_parser.add_argument('--ldflags', action='store', dest='user_ldflags', default='',
@@ -471,6 +469,8 @@ arg_parser.add_argument('--tests-debuginfo', action='store', dest='tests_debugin
help='Enable(1)/disable(0)compiler debug information generation for tests')
arg_parser.add_argument('--python', action='store', dest='python', default='python3',
help='Python3 path')
add_tristate(arg_parser, name='hwloc', dest='hwloc', help='hwloc support')
add_tristate(arg_parser, name='xen', dest='xen', help='Xen support')
arg_parser.add_argument('--split-dwarf', dest='split_dwarf', action='store_true', default=False,
help='use of split dwarf (https://gcc.gnu.org/wiki/DebugFission) to speed up linking')
arg_parser.add_argument('--enable-gcc6-concepts', dest='gcc6_concepts', action='store_true', default=False,
@@ -541,7 +541,6 @@ scylla_core = (['database.cc',
'sstables/compaction_strategy.cc',
'sstables/size_tiered_compaction_strategy.cc',
'sstables/leveled_compaction_strategy.cc',
'sstables/time_window_compaction_strategy.cc',
'sstables/compaction_manager.cc',
'sstables/integrity_checked_file_impl.cc',
'sstables/prepended_input_stream.cc',
@@ -550,7 +549,6 @@ scylla_core = (['database.cc',
'transport/event_notifier.cc',
'transport/server.cc',
'transport/messages/result_message.cc',
'cdc/cdc_partitioner.cc',
'cdc/log.cc',
'cdc/split.cc',
'cdc/generation.cc',
@@ -789,7 +787,6 @@ scylla_core = (['database.cc',
'utils/like_matcher.cc',
'utils/error_injection.cc',
'mutation_writer/timestamp_based_splitting_writer.cc',
'mutation_writer/shard_based_splitting_writer.cc',
'lua.cc',
] + [Antlr3Grammar('cql3/Cql.g')] + [Thrift('interface/cassandra.thrift', 'Cassandra')]
)
@@ -901,7 +898,6 @@ scylla_tests_dependencies = scylla_core + idls + scylla_tests_generic_dependenci
'test/lib/cql_assertions.cc',
'test/lib/result_set_assertions.cc',
'test/lib/mutation_source_test.cc',
'test/lib/sstable_utils.cc',
'test/lib/data_model.cc',
'test/lib/exception_utils.cc',
'test/lib/random_schema.cc',
@@ -910,8 +906,6 @@ scylla_tests_dependencies = scylla_core + idls + scylla_tests_generic_dependenci
deps = {
'scylla': idls + ['main.cc', 'release.cc', 'build_id.cc'] + scylla_core + api + alternator + redis,
'test/tools/cql_repl': idls + ['test/tools/cql_repl.cc'] + scylla_core + scylla_tests_generic_dependencies,
#FIXME: we don't need all of scylla_core here, only the types module, need to modularize scylla_core.
'tools/scylla_types': idls + ['tools/scylla_types.cc'] + scylla_core,
}
pure_boost_tests = set([
@@ -959,9 +953,11 @@ tests_not_using_seastar_test_framework = set([
'test/perf/perf_hash',
'test/perf/perf_mutation',
'test/perf/perf_row_cache_update',
'test/perf/perf_sstable',
'test/unit/lsa_async_eviction_test',
'test/unit/lsa_sync_eviction_test',
'test/unit/row_cache_alloc_stress_test',
'test/unit/row_cache_stress_test',
'test/manual/sstable_scan_footprint_test',
]) | pure_boost_tests
@@ -983,10 +979,13 @@ perf_tests_seastar_deps = [
for t in perf_tests:
deps[t] = [t + '.cc'] + scylla_tests_dependencies + perf_tests_seastar_deps
deps['test/boost/sstable_test'] += ['test/lib/normalizing_reader.cc']
deps['test/boost/sstable_datafile_test'] += ['test/lib/normalizing_reader.cc']
deps['test/boost/mutation_reader_test'] += ['test/lib/dummy_sharder.cc' ]
deps['test/boost/multishard_combining_reader_as_mutation_source_test'] += ['test/lib/dummy_sharder.cc' ]
deps['test/boost/sstable_test'] += ['test/lib/sstable_utils.cc', 'test/lib/normalizing_reader.cc']
deps['test/boost/sstable_datafile_test'] += ['test/lib/sstable_utils.cc', 'test/lib/normalizing_reader.cc']
deps['test/boost/sstable_resharding_test'] += ['test/lib/sstable_utils.cc' ]
deps['test/boost/mutation_reader_test'] += ['test/lib/sstable_utils.cc', 'test/lib/dummy_partitioner.cc' ]
deps['test/boost/multishard_combining_reader_as_mutation_source_test'] += ['test/lib/sstable_utils.cc', 'test/lib/dummy_partitioner.cc' ]
deps['test/boost/sstable_mutation_test'] += ['test/lib/sstable_utils.cc']
deps['test/boost/sstable_conforms_to_mutation_source_test'] += ['test/lib/sstable_utils.cc']
deps['test/boost/bytes_ostream_test'] = [
"test/boost/bytes_ostream_test.cc",
@@ -1236,11 +1235,11 @@ def configure_seastar(build_dir, mode):
if args.alloc_failure_injector:
seastar_cmake_args += ['-DSeastar_ALLOC_FAILURE_INJECTION=ON']
seastar_cmd = ['cmake', '-G', 'Ninja', os.path.relpath(args.seastar_path, seastar_build_dir)] + seastar_cmake_args
seastar_cmd = ['cmake', '-G', 'Ninja', os.path.relpath('seastar', seastar_build_dir)] + seastar_cmake_args
cmake_dir = seastar_build_dir
if args.dpdk:
# need to cook first
cmake_dir = args.seastar_path # required by cooking.sh
cmake_dir = 'seastar' # required by cooking.sh
relative_seastar_build_dir = os.path.join('..', seastar_build_dir) # relative to seastar/
seastar_cmd = ['./cooking.sh', '-i', 'dpdk', '-d', relative_seastar_build_dir, '--'] + seastar_cmd[4:]
@@ -1336,12 +1335,10 @@ libs = ' '.join([maybe_static(args.staticyamlcpp, '-lyaml-cpp'), '-latomic', '-l
' -lstdc++fs', ' -lcrypt', ' -lcryptopp', ' -lpthread',
maybe_static(args.staticboost, '-lboost_date_time -lboost_regex -licuuc'), ])
pkgconfig_libs = [
'libxxhash',
]
xxhash_dir = 'xxHash'
args.user_cflags += ' ' + ' '.join([pkg_config(lib, '--cflags') for lib in pkgconfig_libs])
libs += ' ' + ' '.join([pkg_config(lib, '--libs') for lib in pkgconfig_libs])
if not os.path.exists(xxhash_dir) or not os.listdir(xxhash_dir):
raise Exception(xxhash_dir + ' is empty. Run "git submodule update --init".')
if not args.staticboost:
args.user_cflags += ' -DBOOST_TEST_DYN_LINK'
@@ -1364,7 +1361,7 @@ args.user_cflags += '-I abseil'
user_cflags = args.user_cflags + ' -fvisibility=hidden'
user_ldflags = args.user_ldflags + ' -fvisibility=hidden'
if args.staticcxx:
user_ldflags += " -static-libstdc++"
user_ldflags += " -static-libgcc -static-libstdc++"
if args.staticthrift:
thrift_libs = "-Wl,-Bstatic -lthrift -Wl,-Bdynamic"
else:
@@ -1417,7 +1414,7 @@ with open(buildfile_tmp, 'w') as f:
command = echo -e $text > $out
description = GEN $out
rule swagger
command = {args.seastar_path}/scripts/seastar-json2code.py -f $in -o $out
command = seastar/scripts/seastar-json2code.py -f $in -o $out
description = SWAGGER $out
rule serializer
command = {python} ./idl-compiler.py --ns ser -f $in -o $out
@@ -1489,12 +1486,9 @@ with open(buildfile_tmp, 'w') as f:
build/{mode}/gen/${{stem}}Parser.cpp
description = ANTLR3 $in
rule checkhh.{mode}
command = $cxx -MD -MT $out -MF $out.d {seastar_cflags} $cxxflags $cxxflags_{mode} $obj_cxxflags --include $in -c -o $out build/{mode}/gen/empty.cc
command = $cxx -MD -MT $out -MF $out.d {seastar_cflags} $cxxflags $cxxflags_{mode} $obj_cxxflags -x c++ --include=$in -c -o $out /dev/null
description = CHECKHH $in
depfile = $out.d
rule test.{mode}
command = ./test.py --mode={mode}
description = TEST {mode}
''').format(mode=mode, antlr3_exec=antlr3_exec, fmt_lib=fmt_lib, **modeval))
f.write(
'build {mode}: phony {artifacts}\n'.format(
@@ -1596,17 +1590,6 @@ with open(buildfile_tmp, 'w') as f:
)
)
f.write(
'build {mode}-test: test.{mode} {test_executables} $builddir/{mode}/test/tools/cql_repl\n'.format(
mode=mode,
test_executables=' '.join(['$builddir/{}/{}'.format(mode, binary) for binary in tests]),
)
)
f.write(
'build {mode}-check: phony {mode}-headers {mode}-test\n'.format(
mode=mode,
)
)
gen_headers = []
for th in thrifts:
@@ -1625,7 +1608,7 @@ with open(buildfile_tmp, 'w') as f:
f.write(' cxxflags = {seastar_cflags} $cxxflags $cxxflags_{mode} {extra_cxxflags}\n'.format(mode=mode, extra_cxxflags=extra_cxxflags[src], **modeval))
for hh in swaggers:
src = swaggers[hh]
f.write('build {}: swagger {} | {}/scripts/seastar-json2code.py\n'.format(hh, src, args.seastar_path))
f.write('build {}: swagger {} | seastar/scripts/seastar-json2code.py\n'.format(hh, src))
for hh in serializers:
src = serializers[hh]
f.write('build {}: serializer {} | idl-compiler.py\n'.format(hh, src))
@@ -1651,9 +1634,8 @@ with open(buildfile_tmp, 'w') as f:
if has_sanitize_address_use_after_scope:
flags += ' -fno-sanitize-address-use-after-scope'
f.write(' obj_cxxflags = %s\n' % flags)
f.write(f'build build/{mode}/gen/empty.cc: gen\n')
for hh in headers:
f.write('build $builddir/{mode}/{hh}.o: checkhh.{mode} {hh} | build/{mode}/gen/empty.cc || {gen_headers_dep}\n'.format(
f.write('build $builddir/{mode}/{hh}.o: checkhh.{mode} {hh} || {gen_headers_dep}\n'.format(
mode=mode, hh=hh, gen_headers_dep=gen_headers_dep))
f.write('build build/{mode}/seastar/libseastar.a: ninja | always\n'
@@ -1695,18 +1677,11 @@ with open(buildfile_tmp, 'w') as f:
mode = 'dev' if 'dev' in modes else modes[0]
f.write('build checkheaders: phony || {}\n'.format(' '.join(['$builddir/{}/{}.o'.format(mode, hh) for hh in headers])))
f.write(
'build test: phony {}\n'.format(' '.join(['{mode}-test'.format(mode=mode) for mode in modes]))
)
f.write(
'build check: phony {}\n'.format(' '.join(['{mode}-check'.format(mode=mode) for mode in modes]))
)
f.write(textwrap.dedent('''\
rule configure
command = {python} configure.py $configure_args
generator = 1
build build.ninja: configure | configure.py SCYLLA-VERSION-GEN {args.seastar_path}/CMakeLists.txt
build build.ninja: configure | configure.py SCYLLA-VERSION-GEN seastar/CMakeLists.txt
rule cscope
command = find -name '*.[chS]' -o -name "*.cc" -o -name "*.hh" | cscope -bq -i-
description = CSCOPE

View File

@@ -105,7 +105,7 @@ options {
using namespace cql3::statements;
using namespace cql3::selection;
using cql3::cql3_type;
using conditions_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,lw_shared_ptr<cql3::column_condition::raw>>>;
using conditions_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::column_condition::raw>>>;
using operations_type = std::vector<std::pair<::shared_ptr<cql3::column_identifier::raw>,::shared_ptr<cql3::operation::raw_update>>>;
// ANTLR forces us to define a default-initialized return value
@@ -319,63 +319,63 @@ struct uninitialized {
/** STATEMENTS **/
query returns [std::unique_ptr<raw::parsed_statement> stmnt]
: st=cqlStatement (';')* EOF { $stmnt = std::move(st); }
query returns [shared_ptr<raw::parsed_statement> stmnt]
: st=cqlStatement (';')* EOF { $stmnt = st; }
;
cqlStatement returns [std::unique_ptr<raw::parsed_statement> stmt]
cqlStatement returns [shared_ptr<raw::parsed_statement> stmt]
@after{ if (stmt) { stmt->set_bound_variables(_bind_variables); } }
: st1= selectStatement { $stmt = std::move(st1); }
| st2= insertStatement { $stmt = std::move(st2); }
| st3= updateStatement { $stmt = std::move(st3); }
| st4= batchStatement { $stmt = std::move(st4); }
| st5= deleteStatement { $stmt = std::move(st5); }
| st6= useStatement { $stmt = std::move(st6); }
| st7= truncateStatement { $stmt = std::move(st7); }
| st8= createKeyspaceStatement { $stmt = std::move(st8); }
| st9= createTableStatement { $stmt = std::move(st9); }
| st10=createIndexStatement { $stmt = std::move(st10); }
| st11=dropKeyspaceStatement { $stmt = std::move(st11); }
| st12=dropTableStatement { $stmt = std::move(st12); }
| st13=dropIndexStatement { $stmt = std::move(st13); }
| st14=alterTableStatement { $stmt = std::move(st14); }
| st15=alterKeyspaceStatement { $stmt = std::move(st15); }
| st16=grantStatement { $stmt = std::move(st16); }
| st17=revokeStatement { $stmt = std::move(st17); }
| st18=listPermissionsStatement { $stmt = std::move(st18); }
| st19=createUserStatement { $stmt = std::move(st19); }
| st20=alterUserStatement { $stmt = std::move(st20); }
| st21=dropUserStatement { $stmt = std::move(st21); }
| st22=listUsersStatement { $stmt = std::move(st22); }
: st1= selectStatement { $stmt = st1; }
| st2= insertStatement { $stmt = st2; }
| st3= updateStatement { $stmt = st3; }
| st4= batchStatement { $stmt = st4; }
| st5= deleteStatement { $stmt = st5; }
| st6= useStatement { $stmt = st6; }
| st7= truncateStatement { $stmt = st7; }
| st8= createKeyspaceStatement { $stmt = st8; }
| st9= createTableStatement { $stmt = st9; }
| st10=createIndexStatement { $stmt = st10; }
| st11=dropKeyspaceStatement { $stmt = st11; }
| st12=dropTableStatement { $stmt = st12; }
| st13=dropIndexStatement { $stmt = st13; }
| st14=alterTableStatement { $stmt = st14; }
| st15=alterKeyspaceStatement { $stmt = st15; }
| st16=grantStatement { $stmt = st16; }
| st17=revokeStatement { $stmt = st17; }
| st18=listPermissionsStatement { $stmt = st18; }
| st19=createUserStatement { $stmt = st19; }
| st20=alterUserStatement { $stmt = st20; }
| st21=dropUserStatement { $stmt = st21; }
| st22=listUsersStatement { $stmt = st22; }
#if 0
| st23=createTriggerStatement { $stmt = st23; }
| st24=dropTriggerStatement { $stmt = st24; }
#endif
| st25=createTypeStatement { $stmt = std::move(st25); }
| st26=alterTypeStatement { $stmt = std::move(st26); }
| st27=dropTypeStatement { $stmt = std::move(st27); }
| st28=createFunctionStatement { $stmt = std::move(st28); }
| st29=dropFunctionStatement { $stmt = std::move(st29); }
| st25=createTypeStatement { $stmt = st25; }
| st26=alterTypeStatement { $stmt = st26; }
| st27=dropTypeStatement { $stmt = st27; }
| st28=createFunctionStatement { $stmt = st28; }
| st29=dropFunctionStatement { $stmt = st29; }
#if 0
| st30=createAggregateStatement { $stmt = st30; }
| st31=dropAggregateStatement { $stmt = st31; }
#endif
| st32=createViewStatement { $stmt = std::move(st32); }
| st33=alterViewStatement { $stmt = std::move(st33); }
| st34=dropViewStatement { $stmt = std::move(st34); }
| st35=listRolesStatement { $stmt = std::move(st35); }
| st36=grantRoleStatement { $stmt = std::move(st36); }
| st37=revokeRoleStatement { $stmt = std::move(st37); }
| st38=dropRoleStatement { $stmt = std::move(st38); }
| st39=createRoleStatement { $stmt = std::move(st39); }
| st40=alterRoleStatement { $stmt = std::move(st40); }
| st32=createViewStatement { $stmt = st32; }
| st33=alterViewStatement { $stmt = st33; }
| st34=dropViewStatement { $stmt = st34; }
| st35=listRolesStatement { $stmt = st35; }
| st36=grantRoleStatement { $stmt = st36; }
| st37=revokeRoleStatement { $stmt = st37; }
| st38=dropRoleStatement { $stmt = st38; }
| st39=createRoleStatement { $stmt = st39; }
| st40=alterRoleStatement { $stmt = st40; }
;
/*
* USE <KEYSPACE>;
*/
useStatement returns [std::unique_ptr<raw::use_statement> stmt]
: K_USE ks=keyspaceName { $stmt = std::make_unique<raw::use_statement>(ks); }
useStatement returns [::shared_ptr<raw::use_statement> stmt]
: K_USE ks=keyspaceName { $stmt = ::make_shared<raw::use_statement>(ks); }
;
/**
@@ -384,7 +384,7 @@ useStatement returns [std::unique_ptr<raw::use_statement> stmt]
* WHERE KEY = "key1" AND COL > 1 AND COL < 100
* LIMIT <NUMBER>;
*/
selectStatement returns [std::unique_ptr<raw::select_statement> expr]
selectStatement returns [shared_ptr<raw::select_statement> expr]
@init {
bool is_distinct = false;
::shared_ptr<cql3::term::raw> limit;
@@ -409,7 +409,7 @@ selectStatement returns [std::unique_ptr<raw::select_statement> expr]
( K_BYPASS K_CACHE { bypass_cache = true; })?
{
auto params = make_lw_shared<raw::select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering, is_json, bypass_cache);
$expr = std::make_unique<raw::select_statement>(std::move(cf), std::move(params),
$expr = ::make_shared<raw::select_statement>(std::move(cf), std::move(params),
std::move(sclause), std::move(wclause), std::move(limit), std::move(per_partition_limit),
std::move(gbcolumns));
}
@@ -476,7 +476,7 @@ jsonValue returns [::shared_ptr<cql3::term::raw> value]
* USING TIMESTAMP <long>;
*
*/
insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
insertStatement returns [::shared_ptr<raw::modification_statement> expr]
@init {
auto attrs = std::make_unique<cql3::attributes::raw>();
std::vector<::shared_ptr<cql3::column_identifier::raw>> column_names;
@@ -492,7 +492,7 @@ insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
( usingClause[attrs] )?
{
$expr = std::make_unique<raw::insert_statement>(std::move(cf),
$expr = ::make_shared<raw::insert_statement>(std::move(cf),
std::move(attrs),
std::move(column_names),
std::move(values),
@@ -504,7 +504,7 @@ insertStatement returns [std::unique_ptr<raw::modification_statement> expr]
( K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
( usingClause[attrs] )?
{
$expr = std::make_unique<raw::insert_json_statement>(std::move(cf),
$expr = ::make_shared<raw::insert_json_statement>(std::move(cf),
std::move(attrs),
std::move(json_value),
if_not_exists,
@@ -528,7 +528,7 @@ usingClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
* SET name1 = value1, name2 = value2
* WHERE key = value;
*/
updateStatement returns [std::unique_ptr<raw::update_statement> expr]
updateStatement returns [::shared_ptr<raw::update_statement> expr]
@init {
bool if_exists = false;
auto attrs = std::make_unique<cql3::attributes::raw>();
@@ -540,7 +540,7 @@ updateStatement returns [std::unique_ptr<raw::update_statement> expr]
K_WHERE wclause=whereClause
( K_IF (K_EXISTS{ if_exists = true; } | conditions=updateConditions) )?
{
return std::make_unique<raw::update_statement>(std::move(cf),
return ::make_shared<raw::update_statement>(std::move(cf),
std::move(attrs),
std::move(operations),
std::move(wclause),
@@ -560,7 +560,7 @@ updateConditions returns [conditions_type conditions]
* WHERE KEY = keyname
[IF (EXISTS | name = value, ...)];
*/
deleteStatement returns [std::unique_ptr<raw::delete_statement> expr]
deleteStatement returns [::shared_ptr<raw::delete_statement> expr]
@init {
auto attrs = std::make_unique<cql3::attributes::raw>();
std::vector<::shared_ptr<cql3::operation::raw_deletion>> column_deletions;
@@ -572,7 +572,7 @@ deleteStatement returns [std::unique_ptr<raw::delete_statement> expr]
K_WHERE wclause=whereClause
( K_IF ( K_EXISTS { if_exists = true; } | conditions=updateConditions ))?
{
return std::make_unique<raw::delete_statement>(cf,
return ::make_shared<raw::delete_statement>(cf,
std::move(attrs),
std::move(column_deletions),
std::move(wclause),
@@ -620,11 +620,11 @@ usingClauseDelete[std::unique_ptr<cql3::attributes::raw>& attrs]
* ...
* APPLY BATCH
*/
batchStatement returns [std::unique_ptr<cql3::statements::raw::batch_statement> expr]
batchStatement returns [shared_ptr<cql3::statements::raw::batch_statement> expr]
@init {
using btype = cql3::statements::raw::batch_statement::type;
btype type = btype::LOGGED;
std::vector<std::unique_ptr<cql3::statements::raw::modification_statement>> statements;
std::vector<shared_ptr<cql3::statements::raw::modification_statement>> statements;
auto attrs = std::make_unique<cql3::attributes::raw>();
}
: K_BEGIN
@@ -633,14 +633,14 @@ batchStatement returns [std::unique_ptr<cql3::statements::raw::batch_statement>
( s=batchStatementObjective ';'? { statements.push_back(std::move(s)); } )*
K_APPLY K_BATCH
{
$expr = std::make_unique<cql3::statements::raw::batch_statement>(type, std::move(attrs), std::move(statements));
$expr = ::make_shared<cql3::statements::raw::batch_statement>(type, std::move(attrs), std::move(statements));
}
;
batchStatementObjective returns [std::unique_ptr<cql3::statements::raw::modification_statement> statement]
: i=insertStatement { $statement = std::move(i); }
| u=updateStatement { $statement = std::move(u); }
| d=deleteStatement { $statement = std::move(d); }
batchStatementObjective returns [shared_ptr<cql3::statements::raw::modification_statement> statement]
: i=insertStatement { $statement = i; }
| u=updateStatement { $statement = u; }
| d=deleteStatement { $statement = d; }
;
#if 0
@@ -694,7 +694,7 @@ dropAggregateStatement returns [DropAggregateStatement expr]
;
#endif
createFunctionStatement returns [std::unique_ptr<cql3::statements::create_function_statement> expr]
createFunctionStatement returns [shared_ptr<cql3::statements::create_function_statement> expr]
@init {
bool or_replace = false;
bool if_not_exists = false;
@@ -719,10 +719,10 @@ createFunctionStatement returns [std::unique_ptr<cql3::statements::create_functi
K_RETURNS rt = comparatorType
K_LANGUAGE language = IDENT
K_AS body = STRING_LITERAL
{ $expr = std::make_unique<cql3::statements::create_function_statement>(std::move(fn), to_lower($language.text), $body.text, std::move(arg_names), std::move(arg_types), std::move(rt), called_on_null_input, or_replace, if_not_exists); }
{ $expr = ::make_shared<cql3::statements::create_function_statement>(std::move(fn), to_lower($language.text), $body.text, std::move(arg_names), std::move(arg_types), std::move(rt), called_on_null_input, or_replace, if_not_exists); }
;
dropFunctionStatement returns [std::unique_ptr<cql3::statements::drop_function_statement> expr]
dropFunctionStatement returns [shared_ptr<cql3::statements::drop_function_statement> expr]
@init {
bool if_exists = false;
std::vector<shared_ptr<cql3_type::raw>> arg_types;
@@ -740,19 +740,19 @@ dropFunctionStatement returns [std::unique_ptr<cql3::statements::drop_function_s
')'
{ args_present = true; }
)?
{ $expr = std::make_unique<cql3::statements::drop_function_statement>(std::move(fn), std::move(arg_types), args_present, if_exists); }
{ $expr = ::make_shared<cql3::statements::drop_function_statement>(std::move(fn), std::move(arg_types), args_present, if_exists); }
;
/**
* CREATE KEYSPACE [IF NOT EXISTS] <KEYSPACE> WITH attr1 = value1 AND attr2 = value2;
*/
createKeyspaceStatement returns [std::unique_ptr<cql3::statements::create_keyspace_statement> expr]
createKeyspaceStatement returns [shared_ptr<cql3::statements::create_keyspace_statement> expr]
@init {
auto attrs = make_shared<cql3::statements::ks_prop_defs>();
bool if_not_exists = false;
}
: K_CREATE K_KEYSPACE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )? ks=keyspaceName
K_WITH properties[*attrs] { $expr = std::make_unique<cql3::statements::create_keyspace_statement>(ks, attrs, if_not_exists); }
K_WITH properties[attrs] { $expr = ::make_shared<cql3::statements::create_keyspace_statement>(ks, attrs, if_not_exists); }
;
/**
@@ -762,33 +762,33 @@ createKeyspaceStatement returns [std::unique_ptr<cql3::statements::create_keyspa
* <name3> <type>
* ) WITH <property> = <value> AND ...;
*/
createTableStatement returns [std::unique_ptr<cql3::statements::create_table_statement::raw_statement> expr]
createTableStatement returns [shared_ptr<cql3::statements::create_table_statement::raw_statement> expr]
@init { bool if_not_exists = false; }
: K_CREATE K_COLUMNFAMILY (K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
cf=columnFamilyName { $expr = std::make_unique<cql3::statements::create_table_statement::raw_statement>(cf, if_not_exists); }
cfamDefinition[*expr]
cf=columnFamilyName { $expr = make_shared<cql3::statements::create_table_statement::raw_statement>(cf, if_not_exists); }
cfamDefinition[expr]
;
cfamDefinition[cql3::statements::create_table_statement::raw_statement& expr]
cfamDefinition[shared_ptr<cql3::statements::create_table_statement::raw_statement> expr]
: '(' cfamColumns[expr] ( ',' cfamColumns[expr]? )* ')'
( K_WITH cfamProperty[$expr.properties()] ( K_AND cfamProperty[$expr.properties()] )*)?
( K_WITH cfamProperty[$expr->properties()] ( K_AND cfamProperty[$expr->properties()] )*)?
;
cfamColumns[cql3::statements::create_table_statement::raw_statement& expr]
cfamColumns[shared_ptr<cql3::statements::create_table_statement::raw_statement> expr]
@init { bool is_static=false; }
: k=ident v=comparatorType (K_STATIC {is_static = true;})? { $expr.add_definition(k, v, is_static); }
(K_PRIMARY K_KEY { $expr.add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{k}); })?
| K_PRIMARY K_KEY '(' pkDef[expr] (',' c=ident { $expr.add_column_alias(c); } )* ')'
: k=ident v=comparatorType (K_STATIC {is_static = true;})? { $expr->add_definition(k, v, is_static); }
(K_PRIMARY K_KEY { $expr->add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{k}); })?
| K_PRIMARY K_KEY '(' pkDef[expr] (',' c=ident { $expr->add_column_alias(c); } )* ')'
;
pkDef[cql3::statements::create_table_statement::raw_statement& expr]
pkDef[shared_ptr<cql3::statements::create_table_statement::raw_statement> expr]
@init { std::vector<shared_ptr<cql3::column_identifier>> l; }
: k=ident { $expr.add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{k}); }
| '(' k1=ident { l.push_back(k1); } ( ',' kn=ident { l.push_back(kn); } )* ')' { $expr.add_key_aliases(l); }
: k=ident { $expr->add_key_aliases(std::vector<shared_ptr<cql3::column_identifier>>{k}); }
| '(' k1=ident { l.push_back(k1); } ( ',' kn=ident { l.push_back(kn); } )* ')' { $expr->add_key_aliases(l); }
;
cfamProperty[cql3::statements::cf_properties& expr]
: property[*$expr.properties()]
: property[$expr.properties()]
| K_COMPACT K_STORAGE { $expr.set_compact_storage(); }
| K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[expr] (',' cfamOrdering[expr])* ')'
;
@@ -806,15 +806,15 @@ cfamOrdering[cql3::statements::cf_properties& expr]
* ....
* )
*/
createTypeStatement returns [std::unique_ptr<create_type_statement> expr]
createTypeStatement returns [::shared_ptr<create_type_statement> expr]
@init { bool if_not_exists = false; }
: K_CREATE K_TYPE (K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
tn=userTypeName { $expr = std::make_unique<create_type_statement>(tn, if_not_exists); }
'(' typeColumns[*expr] ( ',' typeColumns[*expr]? )* ')'
tn=userTypeName { $expr = ::make_shared<create_type_statement>(tn, if_not_exists); }
'(' typeColumns[expr] ( ',' typeColumns[expr]? )* ')'
;
typeColumns[create_type_statement& expr]
: k=ident v=comparatorType { $expr.add_definition(k, v); }
typeColumns[::shared_ptr<create_type_statement> expr]
: k=ident v=comparatorType { $expr->add_definition(k, v); }
;
@@ -822,7 +822,7 @@ typeColumns[create_type_statement& expr]
* CREATE INDEX [IF NOT EXISTS] [indexName] ON <columnFamily> (<columnName>);
* CREATE CUSTOM INDEX [IF NOT EXISTS] [indexName] ON <columnFamily> (<columnName>) USING <indexClass>;
*/
createIndexStatement returns [std::unique_ptr<create_index_statement> expr]
createIndexStatement returns [::shared_ptr<create_index_statement> expr]
@init {
auto props = make_shared<index_prop_defs>();
bool if_not_exists = false;
@@ -830,10 +830,10 @@ createIndexStatement returns [std::unique_ptr<create_index_statement> expr]
std::vector<::shared_ptr<index_target::raw>> targets;
}
: K_CREATE (K_CUSTOM { props->is_custom = true; })? K_INDEX (K_IF K_NOT K_EXISTS { if_not_exists = true; } )?
(idxName[*name])? K_ON cf=columnFamilyName '(' (target1=indexIdent { targets.emplace_back(target1); } (',' target2=indexIdent { targets.emplace_back(target2); } )*)? ')'
(idxName[name])? K_ON cf=columnFamilyName '(' (target1=indexIdent { targets.emplace_back(target1); } (',' target2=indexIdent { targets.emplace_back(target2); } )*)? ')'
(K_USING cls=STRING_LITERAL { props->custom_class = sstring{$cls.text}; })?
(K_WITH properties[*props])?
{ $expr = std::make_unique<create_index_statement>(cf, name, targets, props, if_not_exists); }
(K_WITH properties[props])?
{ $expr = ::make_shared<create_index_statement>(cf, name, targets, props, if_not_exists); }
;
indexIdent returns [::shared_ptr<index_target::raw> id]
@@ -856,7 +856,7 @@ indexIdent returns [::shared_ptr<index_target::raw> id]
* PRIMARY KEY (<pkColumns>)
* WITH <property> = <value> AND ...;
*/
createViewStatement returns [std::unique_ptr<create_view_statement> expr]
createViewStatement returns [::shared_ptr<create_view_statement> expr]
@init {
bool if_not_exists = false;
std::vector<::shared_ptr<cql3::column_identifier::raw>> partition_keys;
@@ -870,7 +870,7 @@ createViewStatement returns [std::unique_ptr<create_view_statement> expr]
| '(' k1=cident { partition_keys.push_back(k1); } ( ',' cn=cident { composite_keys.push_back(cn); } )* ')'
)
{
$expr = std::make_unique<create_view_statement>(
$expr = ::make_shared<create_view_statement>(
std::move(cf),
std::move(basecf),
std::move(sclause),
@@ -909,12 +909,12 @@ dropTriggerStatement returns [DropTriggerStatement expr]
/**
* ALTER KEYSPACE <KS> WITH <property> = <value>;
*/
alterKeyspaceStatement returns [std::unique_ptr<cql3::statements::alter_keyspace_statement> expr]
alterKeyspaceStatement returns [shared_ptr<cql3::statements::alter_keyspace_statement> expr]
@init {
auto attrs = make_shared<cql3::statements::ks_prop_defs>();
}
: K_ALTER K_KEYSPACE ks=keyspaceName
K_WITH properties[*attrs] { $expr = std::make_unique<cql3::statements::alter_keyspace_statement>(ks, attrs); }
K_WITH properties[attrs] { $expr = ::make_shared<cql3::statements::alter_keyspace_statement>(ks, attrs); }
;
/**
@@ -924,7 +924,7 @@ alterKeyspaceStatement returns [std::unique_ptr<cql3::statements::alter_keyspace
* ALTER COLUMN FAMILY <CF> WITH <property> = <value>;
* ALTER COLUMN FAMILY <CF> RENAME <column> TO <column>;
*/
alterTableStatement returns [std::unique_ptr<alter_table_statement> expr]
alterTableStatement returns [shared_ptr<alter_table_statement> expr]
@init {
alter_table_statement::type type;
auto props = make_shared<cql3::statements::cf_prop_defs>();
@@ -943,13 +943,13 @@ alterTableStatement returns [std::unique_ptr<alter_table_statement> expr]
| '(' id1=cident { column_changes.emplace_back(alter_table_statement::column_change{id1}); }
(',' idn=cident { column_changes.emplace_back(alter_table_statement::column_change{idn}); } )* ')'
)
| K_WITH properties[*props] { type = alter_table_statement::type::opts; }
| K_WITH properties[props] { type = alter_table_statement::type::opts; }
| K_RENAME { type = alter_table_statement::type::rename; }
id1=cident K_TO toId1=cident { renames.emplace_back(id1, toId1); }
( K_AND idn=cident K_TO toIdn=cident { renames.emplace_back(idn, toIdn); } )*
)
{
$expr = std::make_unique<alter_table_statement>(std::move(cf), type, std::move(column_changes), std::move(props), std::move(renames));
$expr = ::make_shared<alter_table_statement>(std::move(cf), type, std::move(column_changes), std::move(props), std::move(renames));
}
;
@@ -968,126 +968,126 @@ cfisStatic returns [bool isStaticColumn]
* ALTER TYPE <name> ADD <field> <newtype>;
* ALTER TYPE <name> RENAME <field> TO <newtype> AND ...;
*/
alterTypeStatement returns [std::unique_ptr<alter_type_statement> expr]
alterTypeStatement returns [::shared_ptr<alter_type_statement> expr]
: K_ALTER K_TYPE name=userTypeName
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(name, false, f, v); }
| K_ADD f=ident v=comparatorType { $expr = std::make_unique<alter_type_statement::add_or_alter>(name, true, f, v); }
( K_ALTER f=ident K_TYPE v=comparatorType { $expr = ::make_shared<alter_type_statement::add_or_alter>(name, false, f, v); }
| K_ADD f=ident v=comparatorType { $expr = ::make_shared<alter_type_statement::add_or_alter>(name, true, f, v); }
| K_RENAME
{ $expr = std::make_unique<alter_type_statement::renames>(name); }
renames[{ static_cast<alter_type_statement::renames&>(*$expr) }]
{ $expr = ::make_shared<alter_type_statement::renames>(name); }
renames[{ static_pointer_cast<alter_type_statement::renames>($expr) }]
)
;
/**
* ALTER MATERIALIZED VIEW <CF> WITH <property> = <value>;
*/
alterViewStatement returns [std::unique_ptr<alter_view_statement> expr]
alterViewStatement returns [::shared_ptr<alter_view_statement> expr]
@init {
auto props = make_shared<cql3::statements::cf_prop_defs>();
}
: K_ALTER K_MATERIALIZED K_VIEW cf=columnFamilyName K_WITH properties[*props]
: K_ALTER K_MATERIALIZED K_VIEW cf=columnFamilyName K_WITH properties[props]
{
$expr = std::make_unique<alter_view_statement>(std::move(cf), std::move(props));
$expr = ::make_shared<alter_view_statement>(std::move(cf), std::move(props));
}
;
renames[alter_type_statement::renames& expr]
: fromId=ident K_TO toId=ident { $expr.add_rename(fromId, toId); }
renames[::shared_ptr<alter_type_statement::renames> expr]
: fromId=ident K_TO toId=ident { $expr->add_rename(fromId, toId); }
( K_AND renames[$expr] )?
;
/**
* DROP KEYSPACE [IF EXISTS] <KSP>;
*/
dropKeyspaceStatement returns [std::unique_ptr<drop_keyspace_statement> ksp]
dropKeyspaceStatement returns [::shared_ptr<drop_keyspace_statement> ksp]
@init { bool if_exists = false; }
: K_DROP K_KEYSPACE (K_IF K_EXISTS { if_exists = true; } )? ks=keyspaceName { $ksp = std::make_unique<drop_keyspace_statement>(ks, if_exists); }
: K_DROP K_KEYSPACE (K_IF K_EXISTS { if_exists = true; } )? ks=keyspaceName { $ksp = ::make_shared<drop_keyspace_statement>(ks, if_exists); }
;
/**
* DROP COLUMNFAMILY [IF EXISTS] <CF>;
*/
dropTableStatement returns [std::unique_ptr<drop_table_statement> stmt]
dropTableStatement returns [::shared_ptr<drop_table_statement> stmt]
@init { bool if_exists = false; }
: K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = std::make_unique<drop_table_statement>(cf, if_exists); }
: K_DROP K_COLUMNFAMILY (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName { $stmt = ::make_shared<drop_table_statement>(cf, if_exists); }
;
/**
* DROP TYPE <name>;
*/
dropTypeStatement returns [std::unique_ptr<drop_type_statement> stmt]
dropTypeStatement returns [::shared_ptr<drop_type_statement> stmt]
@init { bool if_exists = false; }
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = std::make_unique<drop_type_statement>(name, if_exists); }
: K_DROP K_TYPE (K_IF K_EXISTS { if_exists = true; } )? name=userTypeName { $stmt = ::make_shared<drop_type_statement>(name, if_exists); }
;
/**
* DROP MATERIALIZED VIEW [IF EXISTS] <view_name>
*/
dropViewStatement returns [std::unique_ptr<drop_view_statement> stmt]
dropViewStatement returns [::shared_ptr<drop_view_statement> stmt]
@init { bool if_exists = false; }
: K_DROP K_MATERIALIZED K_VIEW (K_IF K_EXISTS { if_exists = true; } )? cf=columnFamilyName
{ $stmt = std::make_unique<drop_view_statement>(cf, if_exists); }
{ $stmt = ::make_shared<drop_view_statement>(cf, if_exists); }
;
/**
* DROP INDEX [IF EXISTS] <INDEX_NAME>
*/
dropIndexStatement returns [std::unique_ptr<drop_index_statement> expr]
dropIndexStatement returns [::shared_ptr<drop_index_statement> expr]
@init { bool if_exists = false; }
: K_DROP K_INDEX (K_IF K_EXISTS { if_exists = true; } )? index=indexName
{ $expr = std::make_unique<drop_index_statement>(index, if_exists); }
{ $expr = ::make_shared<drop_index_statement>(index, if_exists); }
;
/**
* TRUNCATE <CF>;
*/
truncateStatement returns [std::unique_ptr<truncate_statement> stmt]
: K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = std::make_unique<truncate_statement>(cf); }
truncateStatement returns [::shared_ptr<truncate_statement> stmt]
: K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = ::make_shared<truncate_statement>(cf); }
;
/**
* GRANT <permission> ON <resource> TO <grantee>
*/
grantStatement returns [std::unique_ptr<grant_statement> stmt]
grantStatement returns [::shared_ptr<grant_statement> stmt]
: K_GRANT
permissionOrAll
K_ON
resource
K_TO
grantee=userOrRoleName
{ $stmt = std::make_unique<grant_statement>($permissionOrAll.perms, $resource.res, std::move(grantee)); }
{ $stmt = ::make_shared<grant_statement>($permissionOrAll.perms, $resource.res, std::move(grantee)); }
;
/**
* REVOKE <permission> ON <resource> FROM <revokee>
*/
revokeStatement returns [std::unique_ptr<revoke_statement> stmt]
revokeStatement returns [::shared_ptr<revoke_statement> stmt]
: K_REVOKE
permissionOrAll
K_ON
resource
K_FROM
revokee=userOrRoleName
{ $stmt = std::make_unique<revoke_statement>($permissionOrAll.perms, $resource.res, std::move(revokee)); }
{ $stmt = ::make_shared<revoke_statement>($permissionOrAll.perms, $resource.res, std::move(revokee)); }
;
/**
* GRANT <rolename> to <grantee>
*/
grantRoleStatement returns [std::unique_ptr<grant_role_statement> stmt]
grantRoleStatement returns [::shared_ptr<grant_role_statement> stmt]
: K_GRANT role=userOrRoleName K_TO grantee=userOrRoleName
{ $stmt = std::make_unique<grant_role_statement>(std::move(role), std::move(grantee)); }
{ $stmt = ::make_shared<grant_role_statement>(std::move(role), std::move(grantee)); }
;
/**
* REVOKE <rolename> FROM <revokee>
*/
revokeRoleStatement returns [std::unique_ptr<revoke_role_statement> stmt]
revokeRoleStatement returns [::shared_ptr<revoke_role_statement> stmt]
: K_REVOKE role=userOrRoleName K_FROM revokee=userOrRoleName
{ $stmt = std::make_unique<revoke_role_statement>(std::move(role), std::move(revokee)); }
{ $stmt = ::make_shared<revoke_role_statement>(std::move(role), std::move(revokee)); }
;
listPermissionsStatement returns [std::unique_ptr<list_permissions_statement> stmt]
listPermissionsStatement returns [::shared_ptr<list_permissions_statement> stmt]
@init {
std::optional<auth::resource> r;
std::optional<sstring> role;
@@ -1098,7 +1098,7 @@ listPermissionsStatement returns [std::unique_ptr<list_permissions_statement> st
( K_ON resource { r = $resource.res; } )?
( K_OF rn=userOrRoleName { role = sstring(static_cast<cql3::role_name>(rn).to_string()); } )?
( K_NORECURSIVE { recursive = false; } )?
{ $stmt = std::make_unique<list_permissions_statement>($permissionOrAll.perms, std::move(r), std::move(role), recursive); }
{ $stmt = ::make_shared<list_permissions_statement>($permissionOrAll.perms, std::move(r), std::move(role), recursive); }
;
permission returns [auth::permission perm]
@@ -1131,7 +1131,7 @@ roleResource returns [uninitialized<auth::resource> res]
/**
* CREATE USER [IF NOT EXISTS] <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
*/
createUserStatement returns [std::unique_ptr<create_role_statement> stmt]
createUserStatement returns [::shared_ptr<create_role_statement> stmt]
@init {
cql3::role_options opts;
opts.is_superuser = false;
@@ -1142,42 +1142,42 @@ createUserStatement returns [std::unique_ptr<create_role_statement> stmt]
: K_CREATE K_USER (K_IF K_NOT K_EXISTS { ifNotExists = true; })? u=username
( K_WITH K_PASSWORD v=STRING_LITERAL { opts.password = $v.text; })?
( K_SUPERUSER { opts.is_superuser = true; } | K_NOSUPERUSER { opts.is_superuser = false; } )?
{ $stmt = std::make_unique<create_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts), ifNotExists); }
{ $stmt = ::make_shared<create_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts), ifNotExists); }
;
/**
* ALTER USER <username> [WITH PASSWORD <password>] [SUPERUSER|NOSUPERUSER]
*/
alterUserStatement returns [std::unique_ptr<alter_role_statement> stmt]
alterUserStatement returns [::shared_ptr<alter_role_statement> stmt]
@init {
cql3::role_options opts;
}
: K_ALTER K_USER u=username
( K_WITH K_PASSWORD v=STRING_LITERAL { opts.password = $v.text; })?
( K_SUPERUSER { opts.is_superuser = true; } | K_NOSUPERUSER { opts.is_superuser = false; } )?
{ $stmt = std::make_unique<alter_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts)); }
{ $stmt = ::make_shared<alter_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), std::move(opts)); }
;
/**
* DROP USER [IF EXISTS] <username>
*/
dropUserStatement returns [std::unique_ptr<drop_role_statement> stmt]
dropUserStatement returns [::shared_ptr<drop_role_statement> stmt]
@init { bool ifExists = false; }
: K_DROP K_USER (K_IF K_EXISTS { ifExists = true; })? u=username
{ $stmt = std::make_unique<drop_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), ifExists); }
{ $stmt = ::make_shared<drop_role_statement>(cql3::role_name(u, cql3::preserve_role_case::yes), ifExists); }
;
/**
* LIST USERS
*/
listUsersStatement returns [std::unique_ptr<list_users_statement> stmt]
: K_LIST K_USERS { $stmt = std::make_unique<list_users_statement>(); }
listUsersStatement returns [::shared_ptr<list_users_statement> stmt]
: K_LIST K_USERS { $stmt = ::make_shared<list_users_statement>(); }
;
/**
* CREATE ROLE [IF NOT EXISTS] <role_name> [WITH <roleOption> [AND <roleOption>]*]
*/
createRoleStatement returns [std::unique_ptr<create_role_statement> stmt]
createRoleStatement returns [::shared_ptr<create_role_statement> stmt]
@init {
cql3::role_options opts;
opts.is_superuser = false;
@@ -1186,36 +1186,36 @@ createRoleStatement returns [std::unique_ptr<create_role_statement> stmt]
}
: K_CREATE K_ROLE (K_IF K_NOT K_EXISTS { if_not_exists = true; })? name=userOrRoleName
(K_WITH roleOptions[opts])?
{ $stmt = std::make_unique<create_role_statement>(name, std::move(opts), if_not_exists); }
{ $stmt = ::make_shared<create_role_statement>(name, std::move(opts), if_not_exists); }
;
/**
* ALTER ROLE <rolename> [WITH <roleOption> [AND <roleOption>]*]
*/
alterRoleStatement returns [std::unique_ptr<alter_role_statement> stmt]
alterRoleStatement returns [::shared_ptr<alter_role_statement> stmt]
@init {
cql3::role_options opts;
}
: K_ALTER K_ROLE name=userOrRoleName
(K_WITH roleOptions[opts])?
{ $stmt = std::make_unique<alter_role_statement>(name, std::move(opts)); }
{ $stmt = ::make_shared<alter_role_statement>(name, std::move(opts)); }
;
/**
* DROP ROLE [IF EXISTS] <rolename>
*/
dropRoleStatement returns [std::unique_ptr<drop_role_statement> stmt]
dropRoleStatement returns [::shared_ptr<drop_role_statement> stmt]
@init {
bool if_exists = false;
}
: K_DROP K_ROLE (K_IF K_EXISTS { if_exists = true; })? name=userOrRoleName
{ $stmt = std::make_unique<drop_role_statement>(name, if_exists); }
{ $stmt = ::make_shared<drop_role_statement>(name, if_exists); }
;
/**
* LIST ROLES [OF <rolename>] [NORECURSIVE]
*/
listRolesStatement returns [std::unique_ptr<list_roles_statement> stmt]
listRolesStatement returns [::shared_ptr<list_roles_statement> stmt]
@init {
bool recursive = true;
std::optional<cql3::role_name> grantee;
@@ -1223,7 +1223,7 @@ listRolesStatement returns [std::unique_ptr<list_roles_statement> stmt]
: K_LIST K_ROLES
(K_OF g=userOrRoleName { grantee = std::move(g); })?
(K_NORECURSIVE { recursive = false; })?
{ $stmt = std::make_unique<list_roles_statement>(grantee, recursive); }
{ $stmt = ::make_shared<list_roles_statement>(grantee, recursive); }
;
roleOptions[cql3::role_options& opts]
@@ -1258,17 +1258,17 @@ ident returns [shared_ptr<cql3::column_identifier> id]
// Keyspace & Column family names
keyspaceName returns [sstring id]
@init { auto name = make_shared<cql3::cf_name>(); }
: ksName[*name] { $id = name->get_keyspace(); }
: ksName[name] { $id = name->get_keyspace(); }
;
indexName returns [::shared_ptr<cql3::index_name> name]
@init { $name = ::make_shared<cql3::index_name>(); }
: (ksName[*name] '.')? idxName[*name]
: (ksName[name] '.')? idxName[name]
;
columnFamilyName returns [::shared_ptr<cql3::cf_name> name]
@init { $name = ::make_shared<cql3::cf_name>(); }
: (ksName[*name] '.')? cfName[*name]
: (ksName[name] '.')? cfName[name]
;
userTypeName returns [uninitialized<cql3::ut_name> name]
@@ -1283,24 +1283,24 @@ userOrRoleName returns [uninitialized<cql3::role_name> name]
| QMARK {add_recognition_error("Bind variables cannot be used for role names");}
;
ksName[cql3::keyspace_element_name& name]
: t=IDENT { $name.set_keyspace($t.text, false);}
| t=QUOTED_NAME { $name.set_keyspace($t.text, true);}
| k=unreserved_keyword { $name.set_keyspace(k, false);}
ksName[::shared_ptr<cql3::keyspace_element_name> name]
: t=IDENT { $name->set_keyspace($t.text, false);}
| t=QUOTED_NAME { $name->set_keyspace($t.text, true);}
| k=unreserved_keyword { $name->set_keyspace(k, false);}
| QMARK {add_recognition_error("Bind variables cannot be used for keyspace names");}
;
cfName[cql3::cf_name& name]
: t=IDENT { $name.set_column_family($t.text, false); }
| t=QUOTED_NAME { $name.set_column_family($t.text, true); }
| k=unreserved_keyword { $name.set_column_family(k, false); }
cfName[::shared_ptr<cql3::cf_name> name]
: t=IDENT { $name->set_column_family($t.text, false); }
| t=QUOTED_NAME { $name->set_column_family($t.text, true); }
| k=unreserved_keyword { $name->set_column_family(k, false); }
| QMARK {add_recognition_error("Bind variables cannot be used for table names");}
;
idxName[cql3::index_name& name]
: t=IDENT { $name.set_index($t.text, false); }
| t=QUOTED_NAME { $name.set_index($t.text, true);}
| k=unreserved_keyword { $name.set_index(k, false); }
idxName[::shared_ptr<cql3::index_name> name]
: t=IDENT { $name->set_index($t.text, false); }
| t=QUOTED_NAME { $name->set_index($t.text, true);}
| k=unreserved_keyword { $name->set_index(k, false); }
| QMARK {add_recognition_error("Bind variables cannot be used for index names");}
;
@@ -1489,13 +1489,13 @@ columnCondition[conditions_type& conditions]
)
;
properties[cql3::statements::property_definitions& props]
properties[::shared_ptr<cql3::statements::property_definitions> props]
: property[props] (K_AND property[props])*
;
property[cql3::statements::property_definitions& props]
: k=ident '=' simple=propertyValue { try { $props.add_property(k->to_string(), simple); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } }
| k=ident '=' map=mapLiteral { try { $props.add_property(k->to_string(), convert_property_map(map)); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } }
property[::shared_ptr<cql3::statements::property_definitions> props]
: k=ident '=' simple=propertyValue { try { $props->add_property(k->to_string(), simple); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } }
| k=ident '=' map=mapLiteral { try { $props->add_property(k->to_string(), convert_property_map(map)); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } }
;
propertyValue returns [sstring str]

View File

@@ -50,7 +50,7 @@
namespace cql3 {
abstract_marker::abstract_marker(int32_t bind_index, lw_shared_ptr<column_specification>&& receiver)
abstract_marker::abstract_marker(int32_t bind_index, ::shared_ptr<column_specification>&& receiver)
: _bind_index{bind_index}
, _receiver{std::move(receiver)}
{ }
@@ -67,7 +67,7 @@ abstract_marker::raw::raw(int32_t bind_index)
: _bind_index{bind_index}
{ }
::shared_ptr<term> abstract_marker::raw::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const
::shared_ptr<term> abstract_marker::raw::prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const
{
if (receiver->type->is_collection()) {
if (receiver->type->get_kind() == abstract_type::kind::list) {
@@ -87,7 +87,7 @@ abstract_marker::raw::raw(int32_t bind_index)
return ::make_shared<constants::marker>(_bind_index, receiver);
}
assignment_testable::test_result abstract_marker::raw::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
assignment_testable::test_result abstract_marker::raw::test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const {
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
}
@@ -99,13 +99,13 @@ abstract_marker::in_raw::in_raw(int32_t bind_index)
: raw{bind_index}
{ }
lw_shared_ptr<column_specification> abstract_marker::in_raw::make_in_receiver(const column_specification& receiver) {
auto in_name = ::make_shared<column_identifier>(sstring("in(") + receiver.name->to_string() + sstring(")"), true);
return make_lw_shared<column_specification>(receiver.ks_name, receiver.cf_name, in_name, list_type_impl::get_instance(receiver.type, false));
::shared_ptr<column_specification> abstract_marker::in_raw::make_in_receiver(::shared_ptr<column_specification> receiver) {
auto in_name = ::make_shared<column_identifier>(sstring("in(") + receiver->name->to_string() + sstring(")"), true);
return ::make_shared<column_specification>(receiver->ks_name, receiver->cf_name, in_name, list_type_impl::get_instance(receiver->type, false));
}
::shared_ptr<term> abstract_marker::in_raw::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
return ::make_shared<lists::marker>(_bind_index, make_in_receiver(*receiver));
::shared_ptr<term> abstract_marker::in_raw::prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const {
return ::make_shared<lists::marker>(_bind_index, make_in_receiver(receiver));
}
}

View File

@@ -53,9 +53,9 @@ namespace cql3 {
class abstract_marker : public non_terminal {
protected:
const int32_t _bind_index;
const lw_shared_ptr<column_specification> _receiver;
const ::shared_ptr<column_specification> _receiver;
public:
abstract_marker(int32_t bind_index, lw_shared_ptr<column_specification>&& receiver);
abstract_marker(int32_t bind_index, ::shared_ptr<column_specification>&& receiver);
virtual void collect_marker_specification(variable_specifications& bound_names) const override;
@@ -70,9 +70,9 @@ public:
public:
raw(int32_t bind_index);
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
virtual sstring to_string() const override;
};
@@ -87,9 +87,9 @@ public:
public:
in_raw(int32_t bind_index);
private:
static lw_shared_ptr<column_specification> make_in_receiver(const column_specification& receiver);
static ::shared_ptr<column_specification> make_in_receiver(::shared_ptr<column_specification> receiver);
public:
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
};
};

View File

@@ -70,7 +70,7 @@ public:
// Test all elements of toTest for assignment. If all are exact match, return exact match. If any is not assignable,
// return not assignable. Otherwise, return weakly assignable.
template <typename AssignmentTestablePtrRange>
static test_result test_all(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver,
static test_result test_all(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver,
AssignmentTestablePtrRange&& to_test) {
test_result res = test_result::EXACT_MATCH;
for (auto&& rt : to_test) {
@@ -99,7 +99,7 @@ public:
* Most caller should just call the isAssignable() method on the result, though functions have a use for
* testing "strong" equality to decide the most precise overload to pick when multiple could match.
*/
virtual test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const = 0;
virtual test_result test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const = 0;
// for error reporting
virtual sstring assignment_testable_source_context() const = 0;

View File

@@ -135,12 +135,12 @@ std::unique_ptr<attributes> attributes::raw::prepare(database& db, const sstring
return std::unique_ptr<attributes>{new attributes{std::move(ts), std::move(ttl)}};
}
lw_shared_ptr<column_specification> attributes::raw::timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const {
return make_lw_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[timestamp]", true), data_type_for<int64_t>());
::shared_ptr<column_specification> attributes::raw::timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const {
return ::make_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[timestamp]", true), data_type_for<int64_t>());
}
lw_shared_ptr<column_specification> attributes::raw::time_to_live_receiver(const sstring& ks_name, const sstring& cf_name) const {
return make_lw_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[ttl]", true), data_type_for<int32_t>());
::shared_ptr<column_specification> attributes::raw::time_to_live_receiver(const sstring& ks_name, const sstring& cf_name) const {
return ::make_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[ttl]", true), data_type_for<int32_t>());
}
}

View File

@@ -78,9 +78,9 @@ public:
std::unique_ptr<attributes> prepare(database& db, const sstring& ks_name, const sstring& cf_name) const;
private:
lw_shared_ptr<column_specification> timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const;
::shared_ptr<column_specification> timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const;
lw_shared_ptr<column_specification> time_to_live_receiver(const sstring& ks_name, const sstring& cf_name) const;
::shared_ptr<column_specification> time_to_live_receiver(const sstring& ks_name, const sstring& cf_name) const;
};
};

View File

@@ -291,13 +291,13 @@ bool column_condition::applies_to(const data_value* cell_value, const query_opti
}
}
lw_shared_ptr<column_condition>
::shared_ptr<column_condition>
column_condition::raw::prepare(database& db, const sstring& keyspace, const column_definition& receiver) const {
if (receiver.type->is_counter()) {
throw exceptions::invalid_request_exception("Conditions on counters are not supported");
}
shared_ptr<term> collection_element_term;
lw_shared_ptr<column_specification> value_spec = receiver.column_specification;
shared_ptr<column_specification> value_spec = receiver.column_specification;
if (_collection_element) {
if (!receiver.type->is_collection()) {
@@ -306,7 +306,7 @@ column_condition::raw::prepare(database& db, const sstring& keyspace, const colu
}
// Pass a correct type specification to the collection_element->prepare(), so that it can
// later be used to validate the parameter type is compatible with receiver type.
lw_shared_ptr<column_specification> element_spec;
shared_ptr<column_specification> element_spec;
auto ctype = static_cast<const collection_type_impl*>(receiver.type.get());
const column_specification& recv_column_spec = *receiver.column_specification;
if (ctype->get_kind() == abstract_type::kind::list) {

View File

@@ -104,16 +104,16 @@ public:
* "IF col = 'foo'"
* "IF col LIKE <pattern>"
*/
static lw_shared_ptr<column_condition> condition(const column_definition& def, ::shared_ptr<term> collection_element,
static ::shared_ptr<column_condition> condition(const column_definition& def, ::shared_ptr<term> collection_element,
::shared_ptr<term> value, std::unique_ptr<like_matcher> matcher, const operator_type& op) {
return make_lw_shared<column_condition>(def, std::move(collection_element), std::move(value),
return ::make_shared<column_condition>(def, std::move(collection_element), std::move(value),
std::vector<::shared_ptr<term>>{}, std::move(matcher), op);
}
// Helper constructor wrapper for "IF col IN ... and IF col['key'] IN ... */
static lw_shared_ptr<column_condition> in_condition(const column_definition& def, ::shared_ptr<term> collection_element,
static ::shared_ptr<column_condition> in_condition(const column_definition& def, ::shared_ptr<term> collection_element,
::shared_ptr<term> in_marker, std::vector<::shared_ptr<term>> in_values) {
return make_lw_shared<column_condition>(def, std::move(collection_element), std::move(in_marker),
return ::make_shared<column_condition>(def, std::move(collection_element), std::move(in_marker),
std::move(in_values), nullptr, operator_type::IN);
}
@@ -146,9 +146,9 @@ public:
* "IF col = 'foo'"
* "IF col LIKE 'foo%'"
*/
static lw_shared_ptr<raw> simple_condition(::shared_ptr<term::raw> value, ::shared_ptr<term::raw> collection_element,
static ::shared_ptr<raw> simple_condition(::shared_ptr<term::raw> value, ::shared_ptr<term::raw> collection_element,
const operator_type& op) {
return make_lw_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{},
return ::make_shared<raw>(std::move(value), std::vector<::shared_ptr<term::raw>>{},
::shared_ptr<abstract_marker::in_raw>{}, std::move(collection_element), op);
}
@@ -160,13 +160,13 @@ public:
* "IF col['key'] IN * ('foo', 'bar', ...)"
* "IF col['key'] IN ?"
*/
static lw_shared_ptr<raw> in_condition(::shared_ptr<term::raw> collection_element,
static ::shared_ptr<raw> in_condition(::shared_ptr<term::raw> collection_element,
::shared_ptr<abstract_marker::in_raw> in_marker, std::vector<::shared_ptr<term::raw>> in_values) {
return make_lw_shared<raw>(::shared_ptr<term::raw>{}, std::move(in_values), std::move(in_marker),
return ::make_shared<raw>(::shared_ptr<term::raw>{}, std::move(in_values), std::move(in_marker),
std::move(collection_element), operator_type::IN);
}
lw_shared_ptr<column_condition> prepare(database& db, const sstring& keyspace, const column_definition& receiver) const;
::shared_ptr<column_condition> prepare(database& db, const sstring& keyspace, const column_definition& receiver) const;
};
};

View File

@@ -51,7 +51,7 @@ column_specification::column_specification(std::string_view ks_name_, std::strin
{ }
bool column_specification::all_in_same_table(const std::vector<lw_shared_ptr<column_specification>>& names)
bool column_specification::all_in_same_table(const std::vector<::shared_ptr<column_specification>>& names)
{
assert(!names.empty());

View File

@@ -45,6 +45,7 @@
namespace cql3 {
class column_specification;
class column_identifier;
class column_specification final {
@@ -62,15 +63,15 @@ public:
* @param alias the column alias
* @return a new <code>ColumnSpecification</code> for the same column but with the specified alias.
*/
lw_shared_ptr<column_specification> with_alias(::shared_ptr<column_identifier> alias) {
return make_lw_shared<column_specification>(ks_name, cf_name, alias, type);
::shared_ptr<column_specification> with_alias(::shared_ptr<column_identifier> alias) {
return ::make_shared<column_specification>(ks_name, cf_name, alias, type);
}
bool is_reversed_type() const {
return ::dynamic_pointer_cast<const reversed_type_impl>(type) != nullptr;
}
static bool all_in_same_table(const std::vector<lw_shared_ptr<column_specification>>& names);
static bool all_in_same_table(const std::vector<::shared_ptr<column_specification>>& names);
};
}

View File

@@ -82,7 +82,7 @@ constants::literal::parsed_value(data_type validator) const
}
assignment_testable::test_result
constants::literal::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const
constants::literal::test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const
{
auto receiver_type = receiver->type->as_cql3_type();
if (receiver_type.is_collection() || receiver_type.is_user_type()) {
@@ -155,7 +155,7 @@ constants::literal::test_assignment(database& db, const sstring& keyspace, lw_sh
}
::shared_ptr<term>
constants::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const
constants::literal::prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const
{
if (!is_assignable(test_assignment(db, keyspace, receiver))) {
throw exceptions::invalid_request_exception(format("Invalid {} constant ({}) for \"{}\" of type {}",

View File

@@ -87,7 +87,7 @@ public:
};
public:
static thread_local const ::shared_ptr<terminal> NULL_VALUE;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override {
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override {
if (!is_assignable(test_assignment(db, keyspace, receiver))) {
throw exceptions::invalid_request_exception("Invalid null value for counter increment/decrement");
}
@@ -96,7 +96,7 @@ public:
virtual assignment_testable::test_result test_assignment(database& db,
const sstring& keyspace,
lw_shared_ptr<column_specification> receiver) const override {
::shared_ptr<column_specification> receiver) const override {
return receiver->type->is_counter()
? assignment_testable::test_result::NOT_ASSIGNABLE
: assignment_testable::test_result::WEAKLY_ASSIGNABLE;
@@ -153,7 +153,7 @@ public:
return ::make_shared<literal>(type::DURATION, text);
}
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
private:
bytes parsed_value(data_type validator) const;
public:
@@ -161,7 +161,7 @@ public:
return _text;
}
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const;
virtual sstring to_string() const override {
return _type == type::STRING ? sstring(format("'{}'", _text)) : _text;
@@ -170,7 +170,7 @@ public:
class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
marker(int32_t bind_index, ::shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)}
{
assert(!_receiver->type->is_collection() && !_receiver->type->is_user_type());

View File

@@ -63,7 +63,7 @@ public:
};
shared_ptr<function> make_castas_function(data_type to_type, data_type from_type, castas_fctn func) {
return ::make_shared<castas_function_for>(std::move(to_type), std::move(from_type), func);
return ::make_shared<castas_function_for>(std::move(to_type), std::move(from_type), std::move(func));
}
} /* Anonymous Namespace */
@@ -73,22 +73,22 @@ shared_ptr<function> make_castas_function(data_type to_type, data_type from_type
*/
namespace {
static data_value identity_castas_fctn(data_value val) {
return val;
}
using bytes_opt = std::optional<bytes>;
template<typename ToType, typename FromType>
static data_value castas_fctn_simple(data_value from) {
auto val_from = value_cast<FromType>(from);
return static_cast<ToType>(val_from);
std::function<data_value(data_value)> make_castas_fctn_simple() {
return [](data_value from) -> data_value {
auto val_from = value_cast<FromType>(from);
return static_cast<ToType>(val_from);
};
}
template<typename ToType>
static data_value castas_fctn_from_decimal_to_float(data_value from) {
auto val_from = value_cast<big_decimal>(from);
return static_cast<ToType>(val_from.as_rational());
std::function<data_value(data_value)> make_castas_fctn_from_decimal_to_float() {
return [](data_value from) -> data_value {
auto val_from = value_cast<big_decimal>(from);
return static_cast<ToType>(val_from.as_rational());
};
}
static utils::multiprecision_int from_decimal_to_cppint(const data_value& from) {
@@ -98,44 +98,60 @@ static utils::multiprecision_int from_decimal_to_cppint(const data_value& from)
}
template<typename ToType>
static data_value castas_fctn_from_varint_to_integer(data_value from) {
const auto& varint = value_cast<utils::multiprecision_int>(from);
return static_cast<ToType>(from_varint_to_integer(varint));
std::function<data_value(data_value)> make_castas_fctn_from_varint_to_integer() {
return [](data_value from) -> data_value {
const auto& varint = value_cast<utils::multiprecision_int>(from);
return static_cast<ToType>(from_varint_to_integer(varint));
};
}
template<typename ToType>
static data_value castas_fctn_from_decimal_to_integer(data_value from) {
auto varint = from_decimal_to_cppint(from);
return static_cast<ToType>(from_varint_to_integer(varint));
std::function<data_value(data_value)> make_castas_fctn_from_decimal_to_integer() {
return [](data_value from) -> data_value {
auto varint = from_decimal_to_cppint(from);
return static_cast<ToType>(from_varint_to_integer(varint));
};
}
static data_value castas_fctn_from_decimal_to_varint(data_value from) {
return from_decimal_to_cppint(from);
std::function<data_value(data_value)> make_castas_fctn_from_decimal_to_varint() {
return [](data_value from) -> data_value {
return from_decimal_to_cppint(from);
};
}
template<typename FromType>
static data_value castas_fctn_from_integer_to_decimal(data_value from) {
auto val_from = value_cast<FromType>(from);
return big_decimal(1, 10*static_cast<boost::multiprecision::cpp_int>(val_from));
std::function<data_value(data_value)> make_castas_fctn_from_integer_to_decimal() {
return [](data_value from) -> data_value {
auto val_from = value_cast<FromType>(from);
return big_decimal(1, 10*static_cast<boost::multiprecision::cpp_int>(val_from));
};
}
template<typename FromType>
static data_value castas_fctn_from_float_to_decimal(data_value from) {
auto val_from = value_cast<FromType>(from);
return big_decimal(boost::lexical_cast<std::string>(val_from));
std::function<data_value(data_value)> make_castas_fctn_from_float_to_decimal() {
return [](data_value from) -> data_value {
auto val_from = value_cast<FromType>(from);
return big_decimal(boost::lexical_cast<std::string>(val_from));
};
}
template<typename FromType>
static data_value castas_fctn_to_string(data_value from) {
return to_sstring(value_cast<FromType>(from));
std::function<data_value(data_value)> make_castas_fctn_to_string() {
return [](data_value from) -> data_value {
return to_sstring(value_cast<FromType>(from));
};
}
static data_value castas_fctn_from_varint_to_string(data_value from) {
return to_sstring(value_cast<utils::multiprecision_int>(from).str());
std::function<data_value(data_value)> make_castas_fctn_from_varint_to_string() {
return [](data_value from) -> data_value {
return to_sstring(value_cast<utils::multiprecision_int>(from).str());
};
}
static data_value castas_fctn_from_decimal_to_string(data_value from) {
return value_cast<big_decimal>(from).to_string();
std::function<data_value(data_value)> make_castas_fctn_from_decimal_to_string() {
return [](data_value from) -> data_value {
return value_cast<big_decimal>(from).to_string();
};
}
db_clock::time_point millis_to_time_point(const int64_t millis) {
@@ -158,237 +174,178 @@ db_clock::time_point date_to_time_point(const uint32_t date) {
return db_clock::time_point(std::chrono::duration_cast<db_clock::duration>(millis));
}
static data_value castas_fctn_from_timestamp_to_date(data_value from) {
const auto val_from = value_cast<db_clock::time_point>(from);
return time_point_to_date(val_from);
std::function<data_value(data_value)> make_castas_fctn_from_timestamp_to_date() {
return [](data_value from) -> data_value {
const auto val_from = value_cast<db_clock::time_point>(from);
return time_point_to_date(val_from);
};
}
static data_value castas_fctn_from_date_to_timestamp(data_value from) {
const auto val_from = value_cast<uint32_t>(from);
return date_to_time_point(val_from);
std::function<data_value(data_value)> make_castas_fctn_from_date_to_timestamp() {
return [](data_value from) -> data_value {
const auto val_from = value_cast<uint32_t>(from);
return date_to_time_point(val_from);
};
}
static data_value castas_fctn_from_timeuuid_to_timestamp(data_value from) {
const auto val_from = value_cast<utils::UUID>(from);
return db_clock::time_point{db_clock::duration{utils::UUID_gen::unix_timestamp(val_from)}};
std::function<data_value(data_value)> make_castas_fctn_from_timeuuid_to_timestamp() {
return [](data_value from) -> data_value {
const auto val_from = value_cast<utils::UUID>(from);
return db_clock::time_point{db_clock::duration{utils::UUID_gen::unix_timestamp(val_from)}};
};
}
static data_value castas_fctn_from_timeuuid_to_date(data_value from) {
const auto val_from = value_cast<utils::UUID>(from);
return time_point_to_date(millis_to_time_point(utils::UUID_gen::unix_timestamp(val_from)));
std::function<data_value(data_value)> make_castas_fctn_from_timeuuid_to_date() {
return [](data_value from) -> data_value {
const auto val_from = value_cast<utils::UUID>(from);
return time_point_to_date(millis_to_time_point(utils::UUID_gen::unix_timestamp(val_from)));
};
}
static data_value castas_fctn_from_dv_to_string(data_value from) {
return from.type()->to_string_impl(from);
static std::function<data_value(data_value)> make_castas_fctn_from_dv_to_string() {
return [](data_value from) -> data_value {
return from.type()->to_string_impl(from);
};
}
// FIXME: Add conversions for counters, after they are fully implemented...
static constexpr unsigned next_power_of_2(unsigned val) {
unsigned ret = 1;
while (ret <= val) {
ret *= 2;
// Map <ToType, FromType> -> castas_fctn
using castas_fctn_key = std::pair<data_type, data_type>;
struct castas_fctn_hash {
std::size_t operator()(const castas_fctn_key& x) const noexcept {
return boost::hash_value(x);
}
return ret;
}
};
using castas_fctns_map = std::unordered_map<castas_fctn_key, castas_fctn, castas_fctn_hash>;
// List of supported castas functions...
thread_local castas_fctns_map castas_fctns {
{ {byte_type, byte_type}, make_castas_fctn_simple<int8_t, int8_t>() },
{ {byte_type, short_type}, make_castas_fctn_simple<int8_t, int16_t>() },
{ {byte_type, int32_type}, make_castas_fctn_simple<int8_t, int32_t>() },
{ {byte_type, long_type}, make_castas_fctn_simple<int8_t, int64_t>() },
{ {byte_type, float_type}, make_castas_fctn_simple<int8_t, float>() },
{ {byte_type, double_type}, make_castas_fctn_simple<int8_t, double>() },
{ {byte_type, varint_type}, make_castas_fctn_from_varint_to_integer<int8_t>() },
{ {byte_type, decimal_type}, make_castas_fctn_from_decimal_to_integer<int8_t>() },
{ {short_type, byte_type}, make_castas_fctn_simple<int16_t, int8_t>() },
{ {short_type, short_type}, make_castas_fctn_simple<int16_t, int16_t>() },
{ {short_type, int32_type}, make_castas_fctn_simple<int16_t, int32_t>() },
{ {short_type, long_type}, make_castas_fctn_simple<int16_t, int64_t>() },
{ {short_type, float_type}, make_castas_fctn_simple<int16_t, float>() },
{ {short_type, double_type}, make_castas_fctn_simple<int16_t, double>() },
{ {short_type, varint_type}, make_castas_fctn_from_varint_to_integer<int16_t>() },
{ {short_type, decimal_type}, make_castas_fctn_from_decimal_to_integer<int16_t>() },
{ {int32_type, byte_type}, make_castas_fctn_simple<int32_t, int8_t>() },
{ {int32_type, short_type}, make_castas_fctn_simple<int32_t, int16_t>() },
{ {int32_type, int32_type}, make_castas_fctn_simple<int32_t, int32_t>() },
{ {int32_type, long_type}, make_castas_fctn_simple<int32_t, int64_t>() },
{ {int32_type, float_type}, make_castas_fctn_simple<int32_t, float>() },
{ {int32_type, double_type}, make_castas_fctn_simple<int32_t, double>() },
{ {int32_type, varint_type}, make_castas_fctn_from_varint_to_integer<int32_t>() },
{ {int32_type, decimal_type}, make_castas_fctn_from_decimal_to_integer<int32_t>() },
{ {long_type, byte_type}, make_castas_fctn_simple<int64_t, int8_t>() },
{ {long_type, short_type}, make_castas_fctn_simple<int64_t, int16_t>() },
{ {long_type, int32_type}, make_castas_fctn_simple<int64_t, int32_t>() },
{ {long_type, long_type}, make_castas_fctn_simple<int64_t, int64_t>() },
{ {long_type, float_type}, make_castas_fctn_simple<int64_t, float>() },
{ {long_type, double_type}, make_castas_fctn_simple<int64_t, double>() },
{ {long_type, varint_type}, make_castas_fctn_from_varint_to_integer<int64_t>() },
{ {long_type, decimal_type}, make_castas_fctn_from_decimal_to_integer<int64_t>() },
{ {float_type, byte_type}, make_castas_fctn_simple<float, int8_t>() },
{ {float_type, short_type}, make_castas_fctn_simple<float, int16_t>() },
{ {float_type, int32_type}, make_castas_fctn_simple<float, int32_t>() },
{ {float_type, long_type}, make_castas_fctn_simple<float, int64_t>() },
{ {float_type, float_type}, make_castas_fctn_simple<float, float>() },
{ {float_type, double_type}, make_castas_fctn_simple<float, double>() },
{ {float_type, varint_type}, make_castas_fctn_simple<float, utils::multiprecision_int>() },
{ {float_type, decimal_type}, make_castas_fctn_from_decimal_to_float<float>() },
{ {double_type, byte_type}, make_castas_fctn_simple<double, int8_t>() },
{ {double_type, short_type}, make_castas_fctn_simple<double, int16_t>() },
{ {double_type, int32_type}, make_castas_fctn_simple<double, int32_t>() },
{ {double_type, long_type}, make_castas_fctn_simple<double, int64_t>() },
{ {double_type, float_type}, make_castas_fctn_simple<double, float>() },
{ {double_type, double_type}, make_castas_fctn_simple<double, double>() },
{ {double_type, varint_type}, make_castas_fctn_simple<double, utils::multiprecision_int>() },
{ {double_type, decimal_type}, make_castas_fctn_from_decimal_to_float<double>() },
{ {varint_type, byte_type}, make_castas_fctn_simple<utils::multiprecision_int, int8_t>() },
{ {varint_type, short_type}, make_castas_fctn_simple<utils::multiprecision_int, int16_t>() },
{ {varint_type, int32_type}, make_castas_fctn_simple<utils::multiprecision_int, int32_t>() },
{ {varint_type, long_type}, make_castas_fctn_simple<utils::multiprecision_int, int64_t>() },
{ {varint_type, float_type}, make_castas_fctn_simple<utils::multiprecision_int, float>() },
{ {varint_type, double_type}, make_castas_fctn_simple<utils::multiprecision_int, double>() },
{ {varint_type, varint_type}, make_castas_fctn_simple<utils::multiprecision_int, utils::multiprecision_int>() },
{ {varint_type, decimal_type}, make_castas_fctn_from_decimal_to_varint() },
{ {decimal_type, byte_type}, make_castas_fctn_from_integer_to_decimal<int8_t>() },
{ {decimal_type, short_type}, make_castas_fctn_from_integer_to_decimal<int16_t>() },
{ {decimal_type, int32_type}, make_castas_fctn_from_integer_to_decimal<int32_t>() },
{ {decimal_type, long_type}, make_castas_fctn_from_integer_to_decimal<int64_t>() },
{ {decimal_type, float_type}, make_castas_fctn_from_float_to_decimal<float>() },
{ {decimal_type, double_type}, make_castas_fctn_from_float_to_decimal<double>() },
{ {decimal_type, varint_type}, make_castas_fctn_from_integer_to_decimal<utils::multiprecision_int>() },
{ {decimal_type, decimal_type}, make_castas_fctn_simple<big_decimal, big_decimal>() },
{ {ascii_type, byte_type}, make_castas_fctn_to_string<int8_t>() },
{ {ascii_type, short_type}, make_castas_fctn_to_string<int16_t>() },
{ {ascii_type, int32_type}, make_castas_fctn_to_string<int32_t>() },
{ {ascii_type, long_type}, make_castas_fctn_to_string<int64_t>() },
{ {ascii_type, float_type}, make_castas_fctn_to_string<float>() },
{ {ascii_type, double_type}, make_castas_fctn_to_string<double>() },
{ {ascii_type, varint_type}, make_castas_fctn_from_varint_to_string() },
{ {ascii_type, decimal_type}, make_castas_fctn_from_decimal_to_string() },
{ {utf8_type, byte_type}, make_castas_fctn_to_string<int8_t>() },
{ {utf8_type, short_type}, make_castas_fctn_to_string<int16_t>() },
{ {utf8_type, int32_type}, make_castas_fctn_to_string<int32_t>() },
{ {utf8_type, long_type}, make_castas_fctn_to_string<int64_t>() },
{ {utf8_type, float_type}, make_castas_fctn_to_string<float>() },
{ {utf8_type, double_type}, make_castas_fctn_to_string<double>() },
{ {utf8_type, varint_type}, make_castas_fctn_from_varint_to_string() },
{ {utf8_type, decimal_type}, make_castas_fctn_from_decimal_to_string() },
{ {simple_date_type, timestamp_type}, make_castas_fctn_from_timestamp_to_date() },
{ {simple_date_type, timeuuid_type}, make_castas_fctn_from_timeuuid_to_date() },
{ {timestamp_type, simple_date_type}, make_castas_fctn_from_date_to_timestamp() },
{ {timestamp_type, timeuuid_type}, make_castas_fctn_from_timeuuid_to_timestamp() },
{ {ascii_type, timestamp_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, simple_date_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, time_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, timeuuid_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, uuid_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, boolean_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, inet_addr_type}, make_castas_fctn_from_dv_to_string() },
{ {ascii_type, ascii_type}, make_castas_fctn_simple<sstring, sstring>() },
{ {utf8_type, timestamp_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, simple_date_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, time_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, timeuuid_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, uuid_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, boolean_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, inet_addr_type}, make_castas_fctn_from_dv_to_string() },
{ {utf8_type, ascii_type}, make_castas_fctn_simple<sstring, sstring>() },
{ {utf8_type, utf8_type}, make_castas_fctn_simple<sstring, sstring>() },
};
static constexpr unsigned next_kind_power_of_2 = next_power_of_2(static_cast<unsigned>(abstract_type::kind::last));
static constexpr unsigned cast_switch_case_val(abstract_type::kind A, abstract_type::kind B) {
return static_cast<unsigned>(A) * next_kind_power_of_2 + static_cast<unsigned>(B);
}
} /* Anonymous Namespace */
castas_fctn get_castas_fctn(data_type to_type, data_type from_type) {
if (from_type == to_type) {
// Casting any type to itself doesn't make sense, but it is
// harmless so allow it instead of reporting a confusing error
// message about TypeX not being castable to TypeX.
return identity_castas_fctn;
auto it_candidate = castas_fctns.find(castas_fctn_key{to_type, from_type});
if (it_candidate == castas_fctns.end()) {
throw exceptions::invalid_request_exception(format("{} cannot be cast to {}", from_type->name(), to_type->name()));
}
using kind = abstract_type::kind;
switch(cast_switch_case_val(to_type->get_kind(), from_type->get_kind())) {
case cast_switch_case_val(kind::byte, kind::short_kind):
return castas_fctn_simple<int8_t, int16_t>;
case cast_switch_case_val(kind::byte, kind::int32):
return castas_fctn_simple<int8_t, int32_t>;
case cast_switch_case_val(kind::byte, kind::long_kind):
return castas_fctn_simple<int8_t, int64_t>;
case cast_switch_case_val(kind::byte, kind::float_kind):
return castas_fctn_simple<int8_t, float>;
case cast_switch_case_val(kind::byte, kind::double_kind):
return castas_fctn_simple<int8_t, double>;
case cast_switch_case_val(kind::byte, kind::varint):
return castas_fctn_from_varint_to_integer<int8_t>;
case cast_switch_case_val(kind::byte, kind::decimal):
return castas_fctn_from_decimal_to_integer<int8_t>;
case cast_switch_case_val(kind::short_kind, kind::byte):
return castas_fctn_simple<int16_t, int8_t>;
case cast_switch_case_val(kind::short_kind, kind::int32):
return castas_fctn_simple<int16_t, int32_t>;
case cast_switch_case_val(kind::short_kind, kind::long_kind):
return castas_fctn_simple<int16_t, int64_t>;
case cast_switch_case_val(kind::short_kind, kind::float_kind):
return castas_fctn_simple<int16_t, float>;
case cast_switch_case_val(kind::short_kind, kind::double_kind):
return castas_fctn_simple<int16_t, double>;
case cast_switch_case_val(kind::short_kind, kind::varint):
return castas_fctn_from_varint_to_integer<int16_t>;
case cast_switch_case_val(kind::short_kind, kind::decimal):
return castas_fctn_from_decimal_to_integer<int16_t>;
case cast_switch_case_val(kind::int32, kind::byte):
return castas_fctn_simple<int32_t, int8_t>;
case cast_switch_case_val(kind::int32, kind::short_kind):
return castas_fctn_simple<int32_t, int16_t>;
case cast_switch_case_val(kind::int32, kind::long_kind):
return castas_fctn_simple<int32_t, int64_t>;
case cast_switch_case_val(kind::int32, kind::float_kind):
return castas_fctn_simple<int32_t, float>;
case cast_switch_case_val(kind::int32, kind::double_kind):
return castas_fctn_simple<int32_t, double>;
case cast_switch_case_val(kind::int32, kind::varint):
return castas_fctn_from_varint_to_integer<int32_t>;
case cast_switch_case_val(kind::int32, kind::decimal):
return castas_fctn_from_decimal_to_integer<int32_t>;
case cast_switch_case_val(kind::long_kind, kind::byte):
return castas_fctn_simple<int64_t, int8_t>;
case cast_switch_case_val(kind::long_kind, kind::short_kind):
return castas_fctn_simple<int64_t, int16_t>;
case cast_switch_case_val(kind::long_kind, kind::int32):
return castas_fctn_simple<int64_t, int32_t>;
case cast_switch_case_val(kind::long_kind, kind::float_kind):
return castas_fctn_simple<int64_t, float>;
case cast_switch_case_val(kind::long_kind, kind::double_kind):
return castas_fctn_simple<int64_t, double>;
case cast_switch_case_val(kind::long_kind, kind::varint):
return castas_fctn_from_varint_to_integer<int64_t>;
case cast_switch_case_val(kind::long_kind, kind::decimal):
return castas_fctn_from_decimal_to_integer<int64_t>;
case cast_switch_case_val(kind::float_kind, kind::byte):
return castas_fctn_simple<float, int8_t>;
case cast_switch_case_val(kind::float_kind, kind::short_kind):
return castas_fctn_simple<float, int16_t>;
case cast_switch_case_val(kind::float_kind, kind::int32):
return castas_fctn_simple<float, int32_t>;
case cast_switch_case_val(kind::float_kind, kind::long_kind):
return castas_fctn_simple<float, int64_t>;
case cast_switch_case_val(kind::float_kind, kind::double_kind):
return castas_fctn_simple<float, double>;
case cast_switch_case_val(kind::float_kind, kind::varint):
return castas_fctn_simple<float, utils::multiprecision_int>;
case cast_switch_case_val(kind::float_kind, kind::decimal):
return castas_fctn_from_decimal_to_float<float>;
case cast_switch_case_val(kind::double_kind, kind::byte):
return castas_fctn_simple<double, int8_t>;
case cast_switch_case_val(kind::double_kind, kind::short_kind):
return castas_fctn_simple<double, int16_t>;
case cast_switch_case_val(kind::double_kind, kind::int32):
return castas_fctn_simple<double, int32_t>;
case cast_switch_case_val(kind::double_kind, kind::long_kind):
return castas_fctn_simple<double, int64_t>;
case cast_switch_case_val(kind::double_kind, kind::float_kind):
return castas_fctn_simple<double, float>;
case cast_switch_case_val(kind::double_kind, kind::varint):
return castas_fctn_simple<double, utils::multiprecision_int>;
case cast_switch_case_val(kind::double_kind, kind::decimal):
return castas_fctn_from_decimal_to_float<double>;
case cast_switch_case_val(kind::varint, kind::byte):
return castas_fctn_simple<utils::multiprecision_int, int8_t>;
case cast_switch_case_val(kind::varint, kind::short_kind):
return castas_fctn_simple<utils::multiprecision_int, int16_t>;
case cast_switch_case_val(kind::varint, kind::int32):
return castas_fctn_simple<utils::multiprecision_int, int32_t>;
case cast_switch_case_val(kind::varint, kind::long_kind):
return castas_fctn_simple<utils::multiprecision_int, int64_t>;
case cast_switch_case_val(kind::varint, kind::float_kind):
return castas_fctn_simple<utils::multiprecision_int, float>;
case cast_switch_case_val(kind::varint, kind::double_kind):
return castas_fctn_simple<utils::multiprecision_int, double>;
case cast_switch_case_val(kind::varint, kind::decimal):
return castas_fctn_from_decimal_to_varint;
case cast_switch_case_val(kind::decimal, kind::byte):
return castas_fctn_from_integer_to_decimal<int8_t>;
case cast_switch_case_val(kind::decimal, kind::short_kind):
return castas_fctn_from_integer_to_decimal<int16_t>;
case cast_switch_case_val(kind::decimal, kind::int32):
return castas_fctn_from_integer_to_decimal<int32_t>;
case cast_switch_case_val(kind::decimal, kind::long_kind):
return castas_fctn_from_integer_to_decimal<int64_t>;
case cast_switch_case_val(kind::decimal, kind::float_kind):
return castas_fctn_from_float_to_decimal<float>;
case cast_switch_case_val(kind::decimal, kind::double_kind):
return castas_fctn_from_float_to_decimal<double>;
case cast_switch_case_val(kind::decimal, kind::varint):
return castas_fctn_from_integer_to_decimal<utils::multiprecision_int>;
case cast_switch_case_val(kind::ascii, kind::byte):
case cast_switch_case_val(kind::utf8, kind::byte):
return castas_fctn_to_string<int8_t>;
case cast_switch_case_val(kind::ascii, kind::short_kind):
case cast_switch_case_val(kind::utf8, kind::short_kind):
return castas_fctn_to_string<int16_t>;
case cast_switch_case_val(kind::ascii, kind::int32):
case cast_switch_case_val(kind::utf8, kind::int32):
return castas_fctn_to_string<int32_t>;
case cast_switch_case_val(kind::ascii, kind::long_kind):
case cast_switch_case_val(kind::utf8, kind::long_kind):
return castas_fctn_to_string<int64_t>;
case cast_switch_case_val(kind::ascii, kind::float_kind):
case cast_switch_case_val(kind::utf8, kind::float_kind):
return castas_fctn_to_string<float>;
case cast_switch_case_val(kind::ascii, kind::double_kind):
case cast_switch_case_val(kind::utf8, kind::double_kind):
return castas_fctn_to_string<double>;
case cast_switch_case_val(kind::ascii, kind::varint):
case cast_switch_case_val(kind::utf8, kind::varint):
return castas_fctn_from_varint_to_string;
case cast_switch_case_val(kind::ascii, kind::decimal):
case cast_switch_case_val(kind::utf8, kind::decimal):
return castas_fctn_from_decimal_to_string;
case cast_switch_case_val(kind::simple_date, kind::timestamp):
return castas_fctn_from_timestamp_to_date;
case cast_switch_case_val(kind::simple_date, kind::timeuuid):
return castas_fctn_from_timeuuid_to_date;
case cast_switch_case_val(kind::timestamp, kind::simple_date):
return castas_fctn_from_date_to_timestamp;
case cast_switch_case_val(kind::timestamp, kind::timeuuid):
return castas_fctn_from_timeuuid_to_timestamp;
case cast_switch_case_val(kind::ascii, kind::timestamp):
case cast_switch_case_val(kind::ascii, kind::simple_date):
case cast_switch_case_val(kind::ascii, kind::time):
case cast_switch_case_val(kind::ascii, kind::timeuuid):
case cast_switch_case_val(kind::ascii, kind::uuid):
case cast_switch_case_val(kind::ascii, kind::boolean):
case cast_switch_case_val(kind::ascii, kind::inet):
case cast_switch_case_val(kind::utf8, kind::timestamp):
case cast_switch_case_val(kind::utf8, kind::simple_date):
case cast_switch_case_val(kind::utf8, kind::time):
case cast_switch_case_val(kind::utf8, kind::timeuuid):
case cast_switch_case_val(kind::utf8, kind::uuid):
case cast_switch_case_val(kind::utf8, kind::boolean):
case cast_switch_case_val(kind::utf8, kind::inet):
return castas_fctn_from_dv_to_string;
case cast_switch_case_val(kind::utf8, kind::ascii):
return castas_fctn_simple<sstring, sstring>;
}
throw exceptions::invalid_request_exception(format("{} cannot be cast to {}", from_type->name(), to_type->name()));
return it_candidate->second;
}
shared_ptr<function> castas_functions::get(data_type to_type, const std::vector<shared_ptr<cql3::selection::selector>>& provided_args) {

View File

@@ -58,7 +58,7 @@ namespace functions {
* Support for CAST(. AS .) functions.
*/
using castas_fctn = data_value(*)(data_value);
using castas_fctn = std::function<data_value(data_value)>;
castas_fctn get_castas_fctn(data_type to_type, data_type from_type);

View File

@@ -74,12 +74,12 @@ public:
raw(function_name name, std::vector<shared_ptr<term::raw>> terms)
: _name(std::move(name)), _terms(std::move(terms)) {
}
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
private:
// All parameters must be terminal
static bytes_opt execute(scalar_function& fun, std::vector<shared_ptr<term>> parameters);
public:
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const override;
virtual sstring to_string() const override;
};
};

View File

@@ -141,12 +141,12 @@ void functions::remove_function(const function_name& name, const std::vector<dat
with_udf_iter(name, arg_types, [] (functions::declared_t::iterator i) { _declared.erase(i); });
}
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
functions::make_arg_spec(const sstring& receiver_ks, const sstring& receiver_cf,
const function& fun, size_t i) {
auto&& name = boost::lexical_cast<std::string>(fun.name());
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
return make_lw_shared<column_specification>(receiver_ks,
return ::make_shared<column_specification>(receiver_ks,
receiver_cf,
::make_shared<column_identifier>(format("arg{:d}({})", i, name), true),
fun.arg_types()[i]);
@@ -187,7 +187,7 @@ functions::get(database& db,
const std::vector<shared_ptr<assignment_testable>>& provided_args,
const sstring& receiver_ks,
const sstring& receiver_cf,
lw_shared_ptr<column_specification> receiver) {
shared_ptr<column_specification> receiver) {
static const function_name TOKEN_FUNCTION_NAME = function_name::native_function("token");
static const function_name TO_JSON_FUNCTION_NAME = function_name::native_function("tojson");
@@ -507,7 +507,7 @@ function_call::make_terminal(shared_ptr<function> fun, cql3::raw_value result, c
}
::shared_ptr<term>
function_call::raw::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
function_call::raw::prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const {
std::vector<shared_ptr<assignment_testable>> args;
args.reserve(_terms.size());
std::transform(_terms.begin(), _terms.end(), std::back_inserter(args),
@@ -572,7 +572,7 @@ function_call::raw::execute(scalar_function& fun, std::vector<shared_ptr<term>>
}
assignment_testable::test_result
function_call::raw::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
function_call::raw::test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const {
// Note: Functions.get() will return null if the function doesn't exist, or throw is no function matching
// the arguments can be found. We may get one of those if an undefined/wrong function is used as argument
// of another, existing, function. In that case, we return true here because we'll throw a proper exception

View File

@@ -67,7 +67,7 @@ class functions {
private:
static std::unordered_multimap<function_name, shared_ptr<function>> init();
public:
static lw_shared_ptr<column_specification> make_arg_spec(const sstring& receiver_ks, const sstring& receiver_cf,
static shared_ptr<column_specification> make_arg_spec(const sstring& receiver_ks, const sstring& receiver_cf,
const function& fun, size_t i);
static int get_overload_count(const function_name& name);
public:
@@ -77,7 +77,7 @@ public:
const std::vector<shared_ptr<assignment_testable>>& provided_args,
const sstring& receiver_ks,
const sstring& receiver_cf,
lw_shared_ptr<column_specification> receiver = nullptr);
::shared_ptr<column_specification> receiver = nullptr);
template <typename AssignmentTestablePtrRange>
static shared_ptr<function> get(database& db,
const sstring& keyspace,
@@ -85,7 +85,7 @@ public:
AssignmentTestablePtrRange&& provided_args,
const sstring& receiver_ks,
const sstring& receiver_cf,
lw_shared_ptr<column_specification> receiver = nullptr) {
::shared_ptr<column_specification> receiver = nullptr) {
const std::vector<shared_ptr<assignment_testable>> args(std::begin(provided_args), std::end(provided_args));
return get(db, keyspace, name, args, receiver_ks, receiver_cf, receiver);
}

View File

@@ -30,28 +30,28 @@
namespace cql3 {
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
lists::index_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("idx({})", *column.name), true), int32_type);
}
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
lists::value_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("value({})", *column.name), true),
dynamic_pointer_cast<const list_type_impl>(column.type)->get_elements_type());
}
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
lists::uuid_index_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("uuid_idx({})", *column.name), true), uuid_type);
}
shared_ptr<term>
lists::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
lists::literal::prepare(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const {
validate_assignable_to(db, keyspace, *receiver);
// In Cassandra, an empty (unfrozen) map/set/list is equivalent to the column being null. In
@@ -101,7 +101,7 @@ lists::literal::validate_assignable_to(database& db, const sstring keyspace, con
}
assignment_testable::test_result
lists::literal::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
lists::literal::test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const {
if (!dynamic_pointer_cast<const list_type_impl>(receiver->type)) {
return assignment_testable::test_result::NOT_ASSIGNABLE;
}

View File

@@ -54,9 +54,9 @@ namespace cql3 {
class lists {
lists() = delete;
public:
static lw_shared_ptr<column_specification> index_spec_of(const column_specification&);
static lw_shared_ptr<column_specification> value_spec_of(const column_specification&);
static lw_shared_ptr<column_specification> uuid_index_spec_of(const column_specification&);
static shared_ptr<column_specification> index_spec_of(const column_specification&);
static shared_ptr<column_specification> value_spec_of(const column_specification&);
static shared_ptr<column_specification> uuid_index_spec_of(const column_specification&);
class literal : public term::raw {
const std::vector<shared_ptr<term::raw>> _elements;
@@ -64,11 +64,11 @@ public:
explicit literal(std::vector<shared_ptr<term::raw>> elements)
: _elements(std::move(elements)) {
}
virtual shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual shared_ptr<term> prepare(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const override;
private:
void validate_assignable_to(database& db, const sstring keyspace, const column_specification& receiver) const;
public:
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const override;
virtual sstring to_string() const override;
};
@@ -113,7 +113,7 @@ public:
*/
class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
marker(int32_t bind_index, ::shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)}
{ }
virtual ::shared_ptr<terminal> bind(const query_options& options) override;

View File

@@ -51,22 +51,22 @@
namespace cql3 {
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
maps::key_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("key({})", *column.name), true),
dynamic_pointer_cast<const map_type_impl>(column.type)->get_keys_type());
}
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
maps::value_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("value({})", *column.name), true),
dynamic_pointer_cast<const map_type_impl>(column.type)->get_values_type());
}
::shared_ptr<term>
maps::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
maps::literal::prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const {
validate_assignable_to(db, keyspace, *receiver);
auto key_spec = maps::key_spec_of(*receiver);
@@ -114,7 +114,7 @@ maps::literal::validate_assignable_to(database& db, const sstring& keyspace, con
}
assignment_testable::test_result
maps::literal::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
maps::literal::test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const {
if (!dynamic_pointer_cast<const map_type_impl>(receiver->type)) {
return assignment_testable::test_result::NOT_ASSIGNABLE;
}

View File

@@ -56,8 +56,8 @@ class maps {
private:
maps() = delete;
public:
static lw_shared_ptr<column_specification> key_spec_of(const column_specification& column);
static lw_shared_ptr<column_specification> value_spec_of(const column_specification& column);
static shared_ptr<column_specification> key_spec_of(const column_specification& column);
static shared_ptr<column_specification> value_spec_of(const column_specification& column);
class literal : public term::raw {
public:
@@ -66,11 +66,11 @@ public:
literal(const std::vector<std::pair<::shared_ptr<term::raw>, ::shared_ptr<term::raw>>>& entries_)
: entries{entries_}
{ }
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual ::shared_ptr<term> prepare(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
private:
void validate_assignable_to(database& db, const sstring& keyspace, const column_specification& receiver) const;
public:
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override;
virtual sstring to_string() const override;
};
@@ -104,7 +104,7 @@ public:
class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
marker(int32_t bind_index, ::shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)}
{ }
virtual ::shared_ptr<terminal> bind(const query_options& options) override;

View File

@@ -140,7 +140,7 @@ protected:
virtual shared_ptr<restrictions::restriction> new_EQ_restriction(database& db, schema_ptr schema,
variable_specifications& bound_names) override {
auto rs = receivers(db, *schema);
std::vector<lw_shared_ptr<column_specification>> col_specs(rs.size());
std::vector<::shared_ptr<column_specification>> col_specs(rs.size());
std::transform(rs.begin(), rs.end(), col_specs.begin(), [] (auto cs) {
return cs->column_specification;
});
@@ -151,7 +151,7 @@ protected:
virtual shared_ptr<restrictions::restriction> new_IN_restriction(database& db, schema_ptr schema,
variable_specifications& bound_names) override {
auto rs = receivers(db, *schema);
std::vector<lw_shared_ptr<column_specification>> col_specs(rs.size());
std::vector<::shared_ptr<column_specification>> col_specs(rs.size());
std::transform(rs.begin(), rs.end(), col_specs.begin(), [] (auto cs) {
return cs->column_specification;
});
@@ -175,7 +175,7 @@ protected:
variable_specifications& bound_names,
statements::bound bound, bool inclusive) override {
auto rs = receivers(db, *schema);
std::vector<lw_shared_ptr<column_specification>> col_specs(rs.size());
std::vector<::shared_ptr<column_specification>> col_specs(rs.size());
std::transform(rs.begin(), rs.end(), col_specs.begin(), [] (auto cs) {
return cs->column_specification;
});
@@ -200,7 +200,7 @@ protected:
return ::make_shared(multi_column_relation(std::move(new_entities), _relation_type, _values_or_marker, _in_values, _in_marker));
}
virtual shared_ptr<term> to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
virtual shared_ptr<term> to_term(const std::vector<shared_ptr<column_specification>>& receivers,
const term::raw& raw, database& db, const sstring& keyspace,
variable_specifications& bound_names) const override {
const auto& as_multi_column_raw = dynamic_cast<const term::multi_column_raw&>(raw);

View File

@@ -216,7 +216,7 @@ operation::subtraction::prepare(database& db, const sstring& keyspace, const col
} else if (ctype->get_kind() == abstract_type::kind::map) {
auto&& mtype = dynamic_pointer_cast<const map_type_impl>(ctype);
// The value for a map subtraction is actually a set
auto&& vr = make_lw_shared<column_specification>(
auto&& vr = ::make_shared<column_specification>(
receiver.column_specification->ks_name,
receiver.column_specification->cf_name,
receiver.column_specification->name,
@@ -294,7 +294,7 @@ operation::set_counter_value_from_tuple_list::prepare(database& db, const sstrin
// We need to fake a column of list<tuple<...>> to prepare the value term
auto & os = receiver.column_specification;
auto spec = make_lw_shared<cql3::column_specification>(os->ks_name, os->cf_name, os->name, counter_tuple_list_type);
auto spec = ::make_shared<cql3::column_specification>(os->ks_name, os->cf_name, os->name, counter_tuple_list_type);
auto v = _value->prepare(db, keyspace, spec);
// Will not be used elsewhere, so make it local.

View File

@@ -189,7 +189,7 @@ bytes_view query_options::linearize(fragmented_temporary_buffer::view view) cons
}
}
void query_options::prepare(const std::vector<lw_shared_ptr<column_specification>>& specs)
void query_options::prepare(const std::vector<::shared_ptr<column_specification>>& specs)
{
if (!_names) {
return;

View File

@@ -245,7 +245,7 @@ public:
return _cql_config;
}
void prepare(const std::vector<lw_shared_ptr<column_specification>>& specs);
void prepare(const std::vector<::shared_ptr<column_specification>>& specs);
private:
void fill_value_views();
};

View File

@@ -510,7 +510,7 @@ query_processor::execute_prepared(
if (needs_authorization) {
fut = statement->check_access(_proxy, query_state.get_client_state()).then([this, &query_state, prepared = std::move(prepared), cache_key = std::move(cache_key)] () mutable {
return _authorized_prepared_cache.insert(*query_state.get_client_state().user(), std::move(cache_key), std::move(prepared)).handle_exception([this] (auto eptr) {
log.error("failed to cache the entry: {}", eptr);
log.error("failed to cache the entry", eptr);
});
});
}
@@ -607,10 +607,10 @@ prepared_cache_key_type query_processor::compute_thrift_id(
std::unique_ptr<prepared_statement>
query_processor::get_statement(const sstring_view& query, const service::client_state& client_state) {
std::unique_ptr<raw::parsed_statement> statement = parse_statement(query);
::shared_ptr<raw::parsed_statement> statement = parse_statement(query);
// Set keyspace for statement that require login
auto cf_stmt = dynamic_cast<raw::cf_statement*>(statement.get());
auto cf_stmt = dynamic_pointer_cast<raw::cf_statement>(statement);
if (cf_stmt) {
cf_stmt->prepare_keyspace(client_state);
}
@@ -620,7 +620,7 @@ query_processor::get_statement(const sstring_view& query, const service::client_
return p;
}
std::unique_ptr<raw::parsed_statement>
::shared_ptr<raw::parsed_statement>
query_processor::parse_statement(const sstring_view& query) {
try {
auto statement = util::do_with_parser(query, std::mem_fn(&cql3_parser::CqlParser::query));
@@ -853,7 +853,7 @@ query_processor::execute_batch(
return batch->check_access(_proxy, query_state.get_client_state()).then([this, &query_state, &options, batch, pending_authorization_entries = std::move(pending_authorization_entries)] () mutable {
return parallel_for_each(pending_authorization_entries, [this, &query_state] (auto& e) {
return _authorized_prepared_cache.insert(*query_state.get_client_state().user(), e.first, std::move(e.second)).handle_exception([this] (auto eptr) {
log.error("failed to cache the entry: {}", eptr);
log.error("failed to cache the entry", eptr);
});
}).then([this, &query_state, &options, batch] {
batch->validate();

View File

@@ -147,7 +147,7 @@ public:
const std::string_view& query_string,
const sstring& keyspace);
static std::unique_ptr<statements::raw::parsed_statement> parse_statement(const std::string_view& query);
static ::shared_ptr<statements::raw::parsed_statement> parse_statement(const std::string_view& query);
query_processor(service::storage_proxy& proxy, database& db, service::migration_notifier& mn, memory_config mcfg, cql_config& cql_cfg);

View File

@@ -249,7 +249,7 @@ protected:
* @return the <code>Term</code> corresponding to the specified <code>Raw</code>
* @throws InvalidRequestException if the <code>Raw</code> term is not valid
*/
virtual ::shared_ptr<term> to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
virtual ::shared_ptr<term> to_term(const std::vector<::shared_ptr<column_specification>>& receivers,
const term::raw& raw,
database& db,
const sstring& keyspace,
@@ -265,7 +265,7 @@ protected:
* @return the <code>Term</code>s corresponding to the specified <code>Raw</code> terms
* @throws InvalidRequestException if the <code>Raw</code> terms are not valid
*/
std::vector<::shared_ptr<term>> to_terms(const std::vector<lw_shared_ptr<column_specification>>& receivers,
std::vector<::shared_ptr<term>> to_terms(const std::vector<::shared_ptr<column_specification>>& receivers,
const std::vector<::shared_ptr<term::raw>>& raws,
database& db,
const sstring& keyspace,

View File

@@ -639,10 +639,7 @@ bool single_column_restriction::EQ::is_satisfied_by(const schema& schema,
bool single_column_restriction::EQ::is_satisfied_by(bytes_view data, const query_options& options) const {
auto operand = value(options);
if (!operand) {
throw exceptions::invalid_request_exception(format("Invalid null value for {}", _column_def.name_as_text()));
}
return _column_def.type->compare(*operand, data) == 0;
return operand && _column_def.type->compare(*operand, data) == 0;
}
bool single_column_restriction::IN::is_satisfied_by(const schema& schema,
@@ -670,7 +667,7 @@ bool single_column_restriction::IN::is_satisfied_by(bytes_view data, const query
});
}
static query::range<bytes_view> to_range(const term_slice& slice, const query_options& options, const sstring& name) {
static query::range<bytes_view> to_range(const term_slice& slice, const query_options& options) {
using range_type = query::range<bytes_view>;
auto extract_bound = [&] (statements::bound bound) -> std::optional<range_type::bound> {
if (!slice.has_bound(bound)) {
@@ -678,7 +675,7 @@ static query::range<bytes_view> to_range(const term_slice& slice, const query_op
}
auto value = slice.bound(bound)->bind_and_get(options);
if (!value) {
throw exceptions::invalid_request_exception(format("Invalid null bound for {}", name));
return { };
}
auto value_view = options.linearize(*value);
return { range_type::bound(value_view, slice.is_inclusive(bound)) };
@@ -707,13 +704,13 @@ bool single_column_restriction::slice::is_satisfied_by(const schema& schema,
return false;
}
return cell_value->with_linearized([&] (bytes_view cell_value_bv) {
return contains_without_wraparound(to_range(_slice, options, _column_def.name_as_text()),
return contains_without_wraparound(to_range(_slice, options),
cell_value_bv, _column_def.type->as_tri_comparator());
});
}
bool single_column_restriction::slice::is_satisfied_by(bytes_view data, const query_options& options) const {
return contains_without_wraparound(to_range(_slice, options, _column_def.name_as_text()),
return contains_without_wraparound(to_range(_slice, options),
data, _column_def.type->underlying_type()->as_tri_comparator());
}
@@ -873,9 +870,7 @@ bool single_column_restriction::contains::is_satisfied_by(bytes_view collection_
auto map_key = _entry_keys[i]->bind_and_get(options);
auto map_value = _entry_values[i]->bind_and_get(options);
if (!map_key || !map_value) {
throw exceptions::invalid_request_exception(
format("Unsupported null map {} for column {}",
map_key ? "key" : "value", _column_def.name_as_text()));
continue;
}
auto found = with_linearized(*map_key, [&] (bytes_view map_key_bv) {
return std::find_if(data_map.begin(), data_map.end(), [&] (auto&& element) {
@@ -923,7 +918,7 @@ bool token_restriction::slice::is_satisfied_by(const schema& schema,
const query_options& options,
gc_clock::time_point now) const {
bool satisfied = false;
auto range = to_range(_slice, options, "token");
auto range = to_range(_slice, options);
for (auto* cdef : _column_definitions) {
auto cell_value = do_get_value(schema, *cdef, key, ckey, cells, now);
if (!cell_value) {

View File

@@ -43,12 +43,12 @@
namespace cql3 {
metadata::metadata(std::vector<lw_shared_ptr<column_specification>> names_)
metadata::metadata(std::vector<::shared_ptr<column_specification>> names_)
: _flags(flag_enum_set())
, _column_info(make_lw_shared<column_info>(std::move(names_)))
{ }
metadata::metadata(flag_enum_set flags, std::vector<lw_shared_ptr<column_specification>> names_, uint32_t column_count,
metadata::metadata(flag_enum_set flags, std::vector<::shared_ptr<column_specification>> names_, uint32_t column_count,
lw_shared_ptr<const service::pager::paging_state> paging_state)
: _flags(flags)
, _column_info(make_lw_shared<column_info>(std::move(names_), column_count))
@@ -60,7 +60,7 @@ uint32_t metadata::value_count() const {
return _flags.contains<flag::NO_METADATA>() ? _column_info->_column_count : _column_info->_names.size();
}
void metadata::add_non_serialized_column(lw_shared_ptr<column_specification> name) {
void metadata::add_non_serialized_column(::shared_ptr<column_specification> name) {
// See comment above. Because columnCount doesn't account the newly added name, it
// won't be serialized.
_column_info->_names.emplace_back(std::move(name));
@@ -101,7 +101,7 @@ lw_shared_ptr<const service::pager::paging_state> metadata::paging_state() const
return _paging_state;
}
prepared_metadata::prepared_metadata(const std::vector<lw_shared_ptr<column_specification>>& names,
prepared_metadata::prepared_metadata(const std::vector<::shared_ptr<column_specification>>& names,
const std::vector<uint16_t>& partition_key_bind_indices)
: _names{names}
, _partition_key_bind_indices{partition_key_bind_indices}
@@ -115,7 +115,7 @@ prepared_metadata::flag_enum_set prepared_metadata::flags() const {
return _flags;
}
const std::vector<lw_shared_ptr<column_specification>>& prepared_metadata::names() const {
const std::vector<::shared_ptr<column_specification>>& prepared_metadata::names() const {
return _names;
}
@@ -123,7 +123,7 @@ const std::vector<uint16_t>& prepared_metadata::partition_key_bind_indices() con
return _partition_key_bind_indices;
}
result_set::result_set(std::vector<lw_shared_ptr<column_specification>> metadata_)
result_set::result_set(std::vector<::shared_ptr<column_specification>> metadata_)
: _metadata(::make_shared<metadata>(std::move(metadata_)))
{ }
@@ -179,7 +179,7 @@ const std::deque<std::vector<bytes_opt>>& result_set::rows() const {
shared_ptr<const cql3::metadata>
make_empty_metadata() {
static thread_local shared_ptr<const metadata> empty_metadata_cache = [] {
auto result = ::make_shared<metadata>(std::vector<lw_shared_ptr<cql3::column_specification>>{});
auto result = ::make_shared<metadata>(std::vector<::shared_ptr<cql3::column_specification>>{});
result->set_skip_metadata();
return result;
}();

View File

@@ -74,15 +74,15 @@ public:
// used to include columns in the resultSet that we need to do post-query re-orderings
// (SelectStatement.orderResults) but that shouldn't be sent to the user as they haven't been requested
// (CASSANDRA-4911). So the serialization code will exclude any columns in name whose index is >= columnCount.
std::vector<lw_shared_ptr<column_specification>> _names;
std::vector<::shared_ptr<column_specification>> _names;
uint32_t _column_count;
column_info(std::vector<lw_shared_ptr<column_specification>> names, uint32_t column_count)
column_info(std::vector<::shared_ptr<column_specification>> names, uint32_t column_count)
: _names(std::move(names))
, _column_count(column_count)
{ }
explicit column_info(std::vector<lw_shared_ptr<column_specification>> names)
explicit column_info(std::vector<::shared_ptr<column_specification>> names)
: _names(std::move(names))
, _column_count(_names.size())
{ }
@@ -95,15 +95,15 @@ private:
lw_shared_ptr<const service::pager::paging_state> _paging_state;
public:
metadata(std::vector<lw_shared_ptr<column_specification>> names_);
metadata(std::vector<::shared_ptr<column_specification>> names_);
metadata(flag_enum_set flags, std::vector<lw_shared_ptr<column_specification>> names_, uint32_t column_count,
metadata(flag_enum_set flags, std::vector<::shared_ptr<column_specification>> names_, uint32_t column_count,
lw_shared_ptr<const service::pager::paging_state> paging_state);
// The maximum number of values that the ResultSet can hold. This can be bigger than columnCount due to CASSANDRA-4911
uint32_t value_count() const;
void add_non_serialized_column(lw_shared_ptr<column_specification> name);
void add_non_serialized_column(::shared_ptr<column_specification> name);
private:
bool all_in_same_cf() const;
@@ -120,7 +120,7 @@ public:
lw_shared_ptr<const service::pager::paging_state> paging_state() const;
const std::vector<lw_shared_ptr<column_specification>>& get_names() const {
const std::vector<::shared_ptr<column_specification>>& get_names() const {
return _column_info->_names;
}
};
@@ -139,14 +139,14 @@ public:
using flag_enum_set = enum_set<flag_enum>;
private:
flag_enum_set _flags;
std::vector<lw_shared_ptr<column_specification>> _names;
std::vector<::shared_ptr<column_specification>> _names;
std::vector<uint16_t> _partition_key_bind_indices;
public:
prepared_metadata(const std::vector<lw_shared_ptr<column_specification>>& names,
prepared_metadata(const std::vector<::shared_ptr<column_specification>>& names,
const std::vector<uint16_t>& partition_key_bind_indices);
flag_enum_set flags() const;
const std::vector<lw_shared_ptr<column_specification>>& names() const;
const std::vector<::shared_ptr<column_specification>>& names() const;
const std::vector<uint16_t>& partition_key_bind_indices() const;
};
@@ -167,7 +167,7 @@ class result_set {
friend class result;
public:
result_set(std::vector<lw_shared_ptr<column_specification>> metadata_);
result_set(std::vector<::shared_ptr<column_specification>> metadata_);
result_set(::shared_ptr<metadata> metadata);

View File

@@ -56,7 +56,7 @@ namespace selection {
selection::selection(schema_ptr schema,
std::vector<const column_definition*> columns,
std::vector<lw_shared_ptr<column_specification>> metadata_,
std::vector<::shared_ptr<column_specification>> metadata_,
bool collect_timestamps,
bool collect_TTLs,
trivial is_trivial)
@@ -92,7 +92,7 @@ private:
const bool _is_wildcard;
public:
static ::shared_ptr<simple_selection> make(schema_ptr schema, std::vector<const column_definition*> columns, bool is_wildcard) {
std::vector<lw_shared_ptr<column_specification>> metadata;
std::vector<::shared_ptr<column_specification>> metadata;
metadata.reserve(columns.size());
for (auto&& col : columns) {
metadata.emplace_back(col->column_specification);
@@ -106,7 +106,7 @@ public:
* get much duplicate in practice, it's more efficient not to bother.
*/
simple_selection(schema_ptr schema, std::vector<const column_definition*> columns,
std::vector<lw_shared_ptr<column_specification>> metadata, bool is_wildcard)
std::vector<::shared_ptr<column_specification>> metadata, bool is_wildcard)
: selection(schema, std::move(columns), std::move(metadata), false, false, trivial::yes)
, _is_wildcard(is_wildcard)
{ }
@@ -155,7 +155,7 @@ private:
::shared_ptr<selector_factories> _factories;
public:
selection_with_processing(schema_ptr schema, std::vector<const column_definition*> columns,
std::vector<lw_shared_ptr<column_specification>> metadata, ::shared_ptr<selector_factories> factories)
std::vector<::shared_ptr<column_specification>> metadata, ::shared_ptr<selector_factories> factories)
: selection(schema, std::move(columns), std::move(metadata),
factories->contains_write_time_selector_factory(),
factories->contains_ttl_selector_factory())
@@ -264,14 +264,14 @@ uint32_t selection::add_column_for_post_processing(const column_definition& c) {
}
}
std::vector<lw_shared_ptr<column_specification>>
std::vector<::shared_ptr<column_specification>>
selection::collect_metadata(const schema& schema, const std::vector<::shared_ptr<raw_selector>>& raw_selectors,
const selector_factories& factories) {
std::vector<lw_shared_ptr<column_specification>> r;
std::vector<::shared_ptr<column_specification>> r;
r.reserve(raw_selectors.size());
auto i = raw_selectors.begin();
for (auto&& factory : factories) {
lw_shared_ptr<column_specification> col_spec = factory->get_column_specification(schema);
::shared_ptr<column_specification> col_spec = factory->get_column_specification(schema);
::shared_ptr<column_identifier> alias = (*i++)->alias;
r.push_back(alias ? col_spec->with_alias(alias) : col_spec);
}

View File

@@ -99,7 +99,7 @@ protected:
selection(schema_ptr schema,
std::vector<const column_definition*> columns,
std::vector<lw_shared_ptr<column_specification>> metadata_,
std::vector<::shared_ptr<column_specification>> metadata_,
bool collect_timestamps,
bool collect_TTLs, trivial is_trivial = trivial::no);
@@ -197,7 +197,7 @@ private:
[] (auto&& s) { return s->processes_selection(); });
}
static std::vector<lw_shared_ptr<column_specification>> collect_metadata(const schema& schema,
static std::vector<::shared_ptr<column_specification>> collect_metadata(const schema& schema,
const std::vector<::shared_ptr<raw_selector>>& raw_selectors, const selector_factories& factories);
public:
static ::shared_ptr<selection> from_selectors(database& db, schema_ptr schema, const std::vector<::shared_ptr<raw_selector>>& raw_selectors);
@@ -268,7 +268,7 @@ public:
if (_selectors->requires_thread()) {
return async(std::move(func));
} else {
return futurize_invoke(std::move(func));
return futurize_apply(std::move(func));
}
}

View File

@@ -26,9 +26,9 @@ namespace cql3 {
namespace selection {
lw_shared_ptr<column_specification>
::shared_ptr<column_specification>
selector::factory::get_column_specification(const schema& schema) const {
return make_lw_shared<column_specification>(schema.ks_name(),
return ::make_shared<column_specification>(schema.ks_name(),
schema.cf_name(),
::make_shared<column_identifier>(column_name(), true),
get_return_type());

View File

@@ -107,7 +107,7 @@ public:
*/
virtual void reset() = 0;
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override {
virtual assignment_testable::test_result test_assignment(database& db, const sstring& keyspace, ::shared_ptr<column_specification> receiver) const override {
auto t1 = receiver->type->underlying_type();
auto t2 = get_type()->underlying_type();
// We want columns of `counter_type' to be served by underlying type's overloads
@@ -142,7 +142,7 @@ public:
* @param schema the column family schema
* @return a column specification
*/
lw_shared_ptr<column_specification> get_column_specification(const schema& schema) const;
::shared_ptr<column_specification> get_column_specification(const schema& schema) const;
/**
* Creates a new <code>selector</code> instance.

View File

@@ -27,15 +27,15 @@
namespace cql3 {
lw_shared_ptr<column_specification>
shared_ptr<column_specification>
sets::value_spec_of(const column_specification& column) {
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
return ::make_shared<column_specification>(column.ks_name, column.cf_name,
::make_shared<column_identifier>(format("value({})", *column.name), true),
dynamic_pointer_cast<const set_type_impl>(column.type)->get_elements_type());
}
shared_ptr<term>
sets::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
sets::literal::prepare(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const {
validate_assignable_to(db, keyspace, *receiver);
if (_elements.empty()) {
@@ -105,7 +105,7 @@ sets::literal::validate_assignable_to(database& db, const sstring& keyspace, con
}
assignment_testable::test_result
sets::literal::test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const {
sets::literal::test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const {
if (!dynamic_pointer_cast<const set_type_impl>(receiver->type)) {
// We've parsed empty maps as a set literal to break the ambiguity so handle that case now
if (dynamic_pointer_cast<const map_type_impl>(receiver->type) && _elements.empty()) {
@@ -224,7 +224,7 @@ sets::delayed_value::bind(const query_options& options) {
}
sets::marker::marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
sets::marker::marker(int32_t bind_index, ::shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)} {
assert(dynamic_cast<const set_type_impl*>(_receiver->type.get()));
}

View File

@@ -56,7 +56,7 @@ namespace cql3 {
class sets {
sets() = delete;
public:
static lw_shared_ptr<column_specification> value_spec_of(const column_specification& column);
static shared_ptr<column_specification> value_spec_of(const column_specification& column);
class literal : public term::raw {
std::vector<shared_ptr<term::raw>> _elements;
@@ -64,10 +64,10 @@ public:
explicit literal(std::vector<shared_ptr<term::raw>> elements)
: _elements(std::move(elements)) {
}
virtual shared_ptr<term> prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const override;
virtual shared_ptr<term> prepare(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const override;
void validate_assignable_to(database& db, const sstring& keyspace, const column_specification& receiver) const;
assignment_testable::test_result
test_assignment(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const;
test_assignment(database& db, const sstring& keyspace, shared_ptr<column_specification> receiver) const;
virtual sstring to_string() const override;
};
@@ -100,7 +100,7 @@ public:
class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver);
marker(int32_t bind_index, ::shared_ptr<column_specification> receiver);
virtual ::shared_ptr<terminal> bind(const query_options& options) override;
};

View File

@@ -53,7 +53,7 @@ using namespace cql3::restrictions;
namespace cql3 {
::shared_ptr<term>
single_column_relation::to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
single_column_relation::to_term(const std::vector<::shared_ptr<column_specification>>& receivers,
const term::raw& raw,
database& db,
const sstring& keyspace,
@@ -107,7 +107,7 @@ single_column_relation::new_LIKE_restriction(
return ::make_shared<single_column_restriction::LIKE>(column_def, std::move(term));
}
std::vector<lw_shared_ptr<column_specification>>
std::vector<::shared_ptr<column_specification>>
single_column_relation::to_receivers(const schema& schema, const column_definition& column_def) const
{
using namespace statements::request_validations;

View File

@@ -117,7 +117,7 @@ public:
}
protected:
virtual ::shared_ptr<term> to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
virtual ::shared_ptr<term> to_term(const std::vector<::shared_ptr<column_specification>>& receivers,
const term::raw& raw, database& db, const sstring& keyspace,
variable_specifications& bound_names) const override;
@@ -202,9 +202,9 @@ private:
* @return the receivers for the specified relation.
* @throws exceptions::invalid_request_exception if the relation is invalid
*/
std::vector<lw_shared_ptr<column_specification>> to_receivers(const schema& schema, const column_definition& column_def) const;
std::vector<::shared_ptr<column_specification>> to_receivers(const schema& schema, const column_definition& column_def) const;
static lw_shared_ptr<column_specification> make_collection_receiver(lw_shared_ptr<column_specification> receiver, bool for_key) {
static shared_ptr<column_specification> make_collection_receiver(shared_ptr<column_specification> receiver, bool for_key) {
return static_cast<const collection_type_impl*>(receiver->type.get())->make_collection_receiver(*receiver, for_key);
}

View File

@@ -62,8 +62,6 @@ public:
, _options(std::move(options)) {
}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
void validate(service::storage_proxy&, const service::client_state&) const override;
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;

View File

@@ -46,6 +46,11 @@ uint32_t cql3::statements::authentication_statement::get_bound_terms() const {
return 0;
}
std::unique_ptr<cql3::statements::prepared_statement> cql3::statements::authentication_statement::prepare(
database& db, cql_stats& stats) {
return std::make_unique<prepared_statement>(this->shared_from_this());
}
bool cql3::statements::authentication_statement::uses_function(
const sstring& ks_name, const sstring& function_name) const {
return parsed_statement::uses_function(ks_name, function_name);

View File

@@ -50,12 +50,14 @@ namespace cql3 {
namespace statements {
class authentication_statement : public raw::parsed_statement, public cql_statement_no_metadata {
class authentication_statement : public raw::parsed_statement, public cql_statement_no_metadata, public ::enable_shared_from_this<authentication_statement> {
public:
authentication_statement() : cql_statement_no_metadata(&timeout_config::other_timeout) {}
uint32_t get_bound_terms() const override;
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
bool uses_function(const sstring& ks_name, const sstring& function_name) const override;
bool depends_on_keyspace(const sstring& ks_name) const override;

View File

@@ -46,6 +46,11 @@ uint32_t cql3::statements::authorization_statement::get_bound_terms() const {
return 0;
}
std::unique_ptr<cql3::statements::prepared_statement> cql3::statements::authorization_statement::prepare(
database& db, cql_stats& stats) {
return std::make_unique<prepared_statement>(this->shared_from_this());
}
bool cql3::statements::authorization_statement::uses_function(
const sstring& ks_name, const sstring& function_name) const {
return parsed_statement::uses_function(ks_name, function_name);

View File

@@ -54,12 +54,14 @@ namespace cql3 {
namespace statements {
class authorization_statement : public raw::parsed_statement, public cql_statement_no_metadata {
class authorization_statement : public raw::parsed_statement, public cql_statement_no_metadata, public ::enable_shared_from_this<authorization_statement> {
public:
authorization_statement() : cql_statement_no_metadata(&timeout_config::other_timeout) {}
uint32_t get_bound_terms() const override;
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
bool uses_function(const sstring& ks_name, const sstring& function_name) const override;
bool depends_on_keyspace(const sstring& ks_name) const override;

View File

@@ -341,7 +341,7 @@ future<shared_ptr<cql_transport::messages::result_message>> batch_statement::exe
const query_options& options,
service::query_state& qs) const {
auto cl_for_learn = options.get_consistency();
auto cl_for_commit = options.get_consistency();
auto cl_for_paxos = options.check_serial_consistency();
seastar::shared_ptr<cas_request> request;
schema_ptr schema;
@@ -379,7 +379,7 @@ future<shared_ptr<cql_transport::messages::result_message>> batch_statement::exe
}
auto shard = service::storage_proxy::cas_shard(*_statements[0].statement->s, request->key()[0].start()->value().as_decorated_key().token());
if (shard != this_shard_id()) {
if (shard != engine().cpu_id()) {
proxy.get_stats().replica_cross_shard_ops++;
return make_ready_future<shared_ptr<cql_transport::messages::result_message>>(
make_shared<cql_transport::messages::result_message::bounce_to_shard>(shard));
@@ -387,7 +387,7 @@ future<shared_ptr<cql_transport::messages::result_message>> batch_statement::exe
return proxy.cas(schema, request, request->read_command(), request->key(),
{read_timeout, qs.get_permit(), qs.get_client_state(), qs.get_trace_state()},
cl_for_paxos, cl_for_learn, batch_timeout, cas_timeout).then([this, request] (bool is_applied) {
cl_for_paxos, cl_for_commit, batch_timeout, cas_timeout).then([this, request] (bool is_applied) {
return modification_statement::build_cas_result_set(_metadata, _columns_of_cas_result_set, is_applied, request->rows());
});
}
@@ -401,9 +401,9 @@ void batch_statement::build_cas_result_set_metadata() {
_columns_of_cas_result_set.resize(schema.all_columns_count());
// Add the mandatory [applied] column to result set metadata
std::vector<lw_shared_ptr<column_specification>> columns;
std::vector<shared_ptr<column_specification>> columns;
auto applied = make_lw_shared<cql3::column_specification>(schema.ks_name(), schema.cf_name(),
auto applied = ::make_shared<cql3::column_specification>(schema.ks_name(), schema.cf_name(),
::make_shared<cql3::column_identifier>("[applied]", false), boolean_type);
columns.push_back(applied);

View File

@@ -175,9 +175,9 @@ bool cas_request::applies_to() const {
return applies;
}
std::optional<mutation> cas_request::apply(foreign_ptr<lw_shared_ptr<query::result>> qr,
std::optional<mutation> cas_request::apply(query::result& qr,
const query::partition_slice& slice, api::timestamp_type ts) {
_rows = update_parameters::build_prefetch_data(_schema, *qr, slice);
_rows = update_parameters::build_prefetch_data(_schema, qr, slice);
if (applies_to()) {
return apply_updates(ts);
} else {

View File

@@ -95,7 +95,7 @@ public:
void add_row_update(const modification_statement& stmt_arg, std::vector<query::clustering_range> ranges_arg,
modification_statement::json_cache_opt json_cache_arg, const query_options& options_arg);
virtual std::optional<mutation> apply(foreign_ptr<lw_shared_ptr<query::result>> qr,
virtual std::optional<mutation> apply(query::result& qr,
const query::partition_slice& slice, api::timestamp_type ts) override;
private:

View File

@@ -54,6 +54,10 @@ namespace statements {
class create_role_statement final : public authentication_statement {
sstring _role;
bool _is_superuser;
bool _can_login;
role_options _options;
bool _if_not_exists;
@@ -66,8 +70,6 @@ public:
, _if_not_exists(if_not_exists) {
}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
future<> grant_permissions_to_creator(const service::client_state&) const;
void validate(service::storage_proxy&, const service::client_state&) const override;

View File

@@ -135,7 +135,7 @@ schema_ptr create_table_statement::get_cf_meta_data(const database& db) const {
void create_table_statement::apply_properties_to(schema_builder& builder, const database& db) const {
auto&& columns = get_columns();
for (auto&& column : columns) {
builder.with_column_ordered(column);
builder.with_column(column);
}
#if 0
cfmd.defaultValidator(defaultValidator)

View File

@@ -60,8 +60,6 @@ public:
drop_role_statement(const cql3::role_name& name, bool if_exists) : _role(name.to_string()), _if_exists(if_exists) {
}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
virtual void validate(service::storage_proxy&, const service::client_state&) const override;
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;

View File

@@ -61,8 +61,6 @@ public:
: _role(name.to_string()), _grantee(grantee.to_string()) {
}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;
virtual future<::shared_ptr<cql_transport::messages::result_message>>

View File

@@ -42,11 +42,6 @@
#include "grant_statement.hh"
#include "auth/authorizer.hh"
std::unique_ptr<cql3::statements::prepared_statement> cql3::statements::grant_statement::prepare(
database& db, cql_stats& stats) {
return std::make_unique<prepared_statement>(::make_shared<grant_statement>(*this));
}
future<::shared_ptr<cql_transport::messages::result_message>>
cql3::statements::grant_statement::execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) const {
auto& auth_service = *state.get_client_state().get_auth_service();

View File

@@ -51,8 +51,6 @@ class grant_statement : public permission_altering_statement {
public:
using permission_altering_statement::permission_altering_statement;
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
future<::shared_ptr<cql_transport::messages::result_message>> execute(service::storage_proxy&
, service::query_state&
, const query_options&) const override;

View File

@@ -58,11 +58,6 @@ cql3::statements::list_permissions_statement::list_permissions_statement(
, _recursive(recursive) {
}
std::unique_ptr<cql3::statements::prepared_statement> cql3::statements::list_permissions_statement::prepare(
database& db, cql_stats& stats) {
return std::make_unique<prepared_statement>(::make_shared<list_permissions_statement>(*this));
}
void cql3::statements::list_permissions_statement::validate(
service::storage_proxy& proxy,
const service::client_state& state) const {
@@ -110,14 +105,14 @@ cql3::statements::list_permissions_statement::execute(
service::query_state& state,
const query_options& options) const {
static auto make_column = [](sstring name) {
return make_lw_shared<column_specification>(
return ::make_shared<column_specification>(
auth::meta::AUTH_KS,
"permissions",
::make_shared<column_identifier>(std::move(name), true),
utf8_type);
};
static thread_local const std::vector<lw_shared_ptr<column_specification>> metadata({
static thread_local const std::vector<::shared_ptr<column_specification>> metadata({
make_column("role"), make_column("username"), make_column("resource"), make_column("permission")
});

View File

@@ -61,8 +61,6 @@ private:
public:
list_permissions_statement(auth::permission_set, std::optional<auth::resource>, std::optional<sstring>, bool);
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
void validate(service::storage_proxy&, const service::client_state&) const override;
future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;

View File

@@ -62,8 +62,6 @@ public:
list_roles_statement(const std::optional<role_name>& grantee, bool recursive)
: _grantee(grantee ? sstring(grantee->to_string()) : std::optional<sstring>()), _recursive(recursive) {}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;
virtual future<::shared_ptr<cql_transport::messages::result_message>>

View File

@@ -45,11 +45,6 @@
#include "auth/common.hh"
#include "transport/messages/result_message.hh"
std::unique_ptr<cql3::statements::prepared_statement> cql3::statements::list_users_statement::prepare(
database& db, cql_stats& stats) {
return std::make_unique<prepared_statement>(::make_shared<list_users_statement>(*this));
}
void cql3::statements::list_users_statement::validate(service::storage_proxy& proxy, const service::client_state& state) const {
}
@@ -63,7 +58,7 @@ cql3::statements::list_users_statement::execute(service::storage_proxy& proxy, s
static const sstring virtual_table_name("users");
static const auto make_column_spec = [](const sstring& name, const ::shared_ptr<const abstract_type>& ty) {
return make_lw_shared<column_specification>(
return ::make_shared<column_specification>(
auth::meta::AUTH_KS,
virtual_table_name,
::make_shared<column_identifier>(name, true),
@@ -71,7 +66,7 @@ cql3::statements::list_users_statement::execute(service::storage_proxy& proxy, s
};
static thread_local const auto metadata = ::make_shared<cql3::metadata>(
std::vector<lw_shared_ptr<column_specification>>{
std::vector<::shared_ptr<column_specification>>{
make_column_spec("name", utf8_type),
make_column_spec("super", boolean_type)});

View File

@@ -49,9 +49,6 @@ namespace statements {
class list_users_statement : public authentication_statement {
public:
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
void validate(service::storage_proxy&, const service::client_state&) const override;
future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;
future<::shared_ptr<cql_transport::messages::result_message>> execute(service::storage_proxy&

View File

@@ -213,7 +213,7 @@ bool modification_statement::applies_to(const update_parameters::prefetch_data::
return row == nullptr;
}
auto condition_applies = [&row, &options](const lw_shared_ptr<column_condition>& cond) {
auto condition_applies = [&row, &options](const shared_ptr<column_condition>& cond) {
const data_value* value = nullptr;
if (row != nullptr) {
auto it = row->cells.find(cond->column.ordinal_id);
@@ -322,7 +322,7 @@ modification_statement::execute_without_condition(service::storage_proxy& proxy,
future<::shared_ptr<cql_transport::messages::result_message>>
modification_statement::execute_with_condition(service::storage_proxy& proxy, service::query_state& qs, const query_options& options) const {
auto cl_for_learn = options.get_consistency();
auto cl_for_commit = options.get_consistency();
auto cl_for_paxos = options.check_serial_consistency();
db::timeout_clock::time_point now = db::timeout_clock::now();
const timeout_config& cfg = options.get_timeout_config();
@@ -346,7 +346,7 @@ modification_statement::execute_with_condition(service::storage_proxy& proxy, se
request->add_row_update(*this, std::move(ranges), std::move(json_cache), options);
auto shard = service::storage_proxy::cas_shard(*s, request->key()[0].start()->value().as_decorated_key().token());
if (shard != this_shard_id()) {
if (shard != engine().cpu_id()) {
proxy.get_stats().replica_cross_shard_ops++;
return make_ready_future<shared_ptr<cql_transport::messages::result_message>>(
make_shared<cql_transport::messages::result_message::bounce_to_shard>(shard));
@@ -354,7 +354,7 @@ modification_statement::execute_with_condition(service::storage_proxy& proxy, se
return proxy.cas(s, request, request->read_command(), request->key(),
{read_timeout, qs.get_permit(), qs.get_client_state(), qs.get_trace_state()},
cl_for_paxos, cl_for_learn, statement_timeout, cas_timeout).then([this, request] (bool is_applied) {
cl_for_paxos, cl_for_commit, statement_timeout, cas_timeout).then([this, request] (bool is_applied) {
return build_cas_result_set(_metadata, _columns_of_cas_result_set, is_applied, request->rows());
});
}
@@ -408,9 +408,9 @@ modification_statement::build_cas_result_set(seastar::shared_ptr<cql3::metadata>
void modification_statement::build_cas_result_set_metadata() {
std::vector<lw_shared_ptr<column_specification>> columns;
std::vector<shared_ptr<column_specification>> columns;
// Add the mandatory [applied] column to result set metadata
auto applied = make_lw_shared<cql3::column_specification>(s->ks_name(), s->cf_name(),
auto applied = seastar::make_shared<cql3::column_specification>(s->ks_name(), s->cf_name(),
make_shared<cql3::column_identifier>("[applied]", false), boolean_type);
columns.push_back(applied);
@@ -647,7 +647,7 @@ void modification_statement::inc_cql_stats(bool is_internal) const {
++_stats.query_cnt(src_sel, _ks_sel, cond_sel, type);
}
void modification_statement::add_condition(lw_shared_ptr<column_condition> cond) {
void modification_statement::add_condition(::shared_ptr<column_condition> cond) {
if (cond->column.is_static()) {
_has_static_column_conditions = true;
_static_conditions.emplace_back(std::move(cond));

View File

@@ -107,8 +107,8 @@ protected:
cql_stats& _stats;
private:
// Separating normal and static conditions makes things somewhat easier
std::vector<lw_shared_ptr<column_condition>> _regular_conditions;
std::vector<lw_shared_ptr<column_condition>> _static_conditions;
std::vector<::shared_ptr<column_condition>> _regular_conditions;
std::vector<::shared_ptr<column_condition>> _static_conditions;
const ks_selector _ks_sel;
// True if this statement has _if_exists or _if_not_exists or other
@@ -185,7 +185,7 @@ public:
return *_restrictions;
}
public:
void add_condition(lw_shared_ptr<column_condition> cond);
void add_condition(::shared_ptr<column_condition> cond);
void set_if_not_exist_condition();

View File

@@ -69,10 +69,10 @@ public:
public:
const ::shared_ptr<cql_statement> statement;
const std::vector<lw_shared_ptr<column_specification>> bound_names;
const std::vector<::shared_ptr<column_specification>> bound_names;
std::vector<uint16_t> partition_key_bind_indices;
prepared_statement(::shared_ptr<cql_statement> statement_, std::vector<lw_shared_ptr<column_specification>> bound_names_, std::vector<uint16_t> partition_key_bind_indices);
prepared_statement(::shared_ptr<cql_statement> statement_, std::vector<::shared_ptr<column_specification>> bound_names_, std::vector<uint16_t> partition_key_bind_indices);
prepared_statement(::shared_ptr<cql_statement> statement_, const variable_specifications& names, const std::vector<uint16_t>& partition_key_bind_indices);

View File

@@ -66,12 +66,12 @@ public:
private:
type _type;
std::unique_ptr<attributes::raw> _attrs;
std::vector<std::unique_ptr<raw::modification_statement>> _parsed_statements;
std::vector<shared_ptr<raw::modification_statement>> _parsed_statements;
public:
batch_statement(
type type_,
std::unique_ptr<attributes::raw> attrs,
std::vector<std::unique_ptr<raw::modification_statement>> parsed_statements)
std::vector<shared_ptr<raw::modification_statement>> parsed_statements)
: cf_statement(nullptr)
, _type(type_)
, _attrs(std::move(attrs))

View File

@@ -70,10 +70,10 @@ namespace raw {
class modification_statement : public cf_statement {
public:
using conditions_vector = std::vector<std::pair<::shared_ptr<column_identifier::raw>, lw_shared_ptr<column_condition::raw>>>;
using conditions_vector = std::vector<std::pair<::shared_ptr<column_identifier::raw>, ::shared_ptr<column_condition::raw>>>;
protected:
const std::unique_ptr<attributes::raw> _attrs;
const std::vector<std::pair<::shared_ptr<column_identifier::raw>, lw_shared_ptr<column_condition::raw>>> _conditions;
const std::vector<std::pair<::shared_ptr<column_identifier::raw>, ::shared_ptr<column_condition::raw>>> _conditions;
private:
const bool _if_not_exists;
const bool _if_exists;

View File

@@ -71,7 +71,7 @@ bool parsed_statement::uses_function(const sstring& ks_name, const sstring& func
}
prepared_statement::prepared_statement(::shared_ptr<cql_statement> statement_, std::vector<lw_shared_ptr<column_specification>> bound_names_, std::vector<uint16_t> partition_key_bind_indices)
prepared_statement::prepared_statement(::shared_ptr<cql_statement> statement_, std::vector<::shared_ptr<column_specification>> bound_names_, std::vector<uint16_t> partition_key_bind_indices)
: statement(std::move(statement_))
, bound_names(std::move(bound_names_))
, partition_key_bind_indices(std::move(partition_key_bind_indices))
@@ -86,7 +86,7 @@ prepared_statement::prepared_statement(::shared_ptr<cql_statement> statement_, v
{ }
prepared_statement::prepared_statement(::shared_ptr<cql_statement>&& statement_)
: prepared_statement(statement_, std::vector<lw_shared_ptr<column_specification>>(), std::vector<uint16_t>())
: prepared_statement(statement_, std::vector<::shared_ptr<column_specification>>(), std::vector<uint16_t>())
{ }
}

View File

@@ -157,7 +157,7 @@ private:
bool contains_alias(const column_identifier& name) const;
lw_shared_ptr<column_specification> limit_receiver(bool per_partition = false);
::shared_ptr<column_specification> limit_receiver(bool per_partition = false);
#if 0
public:

View File

@@ -61,8 +61,6 @@ public:
: _role(name.to_string()), _revokee(revokee.to_string()) {
}
std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state&) const override;
virtual future<::shared_ptr<cql_transport::messages::result_message>>

Some files were not shown because too many files have changed in this diff Show More