Compare commits

...

858 Commits

Author SHA1 Message Date
Avi Kivity
123eb04136 lsa: disable constant_time_size in binomial_heap implementation
Corrupts heap on boost < 1.60, and not needed.

Fixes #698.
2015-12-29 15:12:30 +02:00
Takuya ASADA
37dfe9cfc6 dist: host gcc-5.1.1-4.fc22.src.rpm on our S3 account, since Fedora mirror deleted it
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-17 12:53:19 +02:00
Pekka Enberg
43d3c5f354 release: prepare for 0.13.2 2015-12-16 11:46:14 +02:00
Avi Kivity
59cd785778 Merge scylla-seastar branch-0.13
* seastar d40453b...8a76d06 (3):
  > memory: be less strict about NUMA bindings
  > reactor: let the resource code specify the default memory reserve
  > resource: reserve even more memory when hwloc is compiled in
2015-12-09 18:26:22 +02:00
Avi Kivity
bb24d4324f Redirect seastar submodule to scylla-seastar repository
This allows having a private scylla fork for seastar, for the stable
branches.
2015-12-09 18:23:47 +02:00
Pekka Enberg
eb7ae39f40 release: prepare for 0.13.1
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-12-09 14:19:43 +02:00
Asias He
4281b48472 gossip: Fix endless marking a node down
In commit 56df32ba56 (gossip: Mark node as
dead even if already left). A node liveness check is missed.

Fix it up.

Before: (mark a node down multiple times)

[Tue Dec  8 12:16:33 2015] INFO  [shard 0] gossip - InetAddress 127.0.0.3 is now DOWN
[Tue Dec  8 12:16:33 2015] DEBUG [shard 0] storage_service - endpoint=127.0.0.3 on_dead
[Tue Dec  8 12:16:34 2015] INFO  [shard 0] gossip - InetAddress 127.0.0.3 is now DOWN
[Tue Dec  8 12:16:34 2015] DEBUG [shard 0] storage_service - endpoint=127.0.0.3 on_dead
[Tue Dec  8 12:16:35 2015] INFO  [shard 0] gossip - InetAddress 127.0.0.3 is now DOWN
[Tue Dec  8 12:16:35 2015] DEBUG [shard 0] storage_service - endpoint=127.0.0.3 on_dead
[Tue Dec  8 12:16:36 2015] INFO  [shard 0] gossip - InetAddress 127.0.0.3 is now DOWN
[Tue Dec  8 12:16:36 2015] DEBUG [shard 0] storage_service - endpoint=127.0.0.3 on_dead

After: (mark a node down only one time)

[Tue Dec  8 12:28:36 2015] INFO  [shard 0] gossip - InetAddress 127.0.0.3 is now DOWN
[Tue Dec  8 12:28:36 2015] DEBUG [shard 0] storage_service - endpoint=127.0.0.3 on_dead

(cherry picked from commit 5a65d8bcdd)
2015-12-09 14:09:10 +02:00
Pekka Enberg
fef7375beb release: prepare for 0.13
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-12-08 11:28:15 +02:00
Takuya ASADA
8c98e239d0 dist: use /etc/scylla as SCYLLA_CONF directory on AMI
We don't need copy /var/lib/scylla/conf on RAID anymore, it moved to /etc/scylla.

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-08 11:09:12 +02:00
Avi Kivity
098136f4ab Merge "Convert serialization of query::result to use db::serializer<>" from Tomasz
Reviewed-by: Nadav Har'El <nyh@scylladb.com>
2015-12-07 16:53:34 +02:00
Amnon Heiman
2086c651ba column_family: get_snapshot_details should return empty map for no snapshots
If there is no snapshot directory for the specific column family,
get_snapshot_details should return an empty map.

This patch check that a directory exists before trying to iterate over
it.

Fixes #619

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-07 12:51:04 +01:00
Tomasz Grabiec
b43b5af894 Merge tag 'tgrabiec/make-future-values-nothrow-move-constructible-v3' from seastar-dev.git
Seastar's future<> now requires types to be nothrow move
constructible. This series makes Scylla code comply.
2015-12-07 10:43:18 +01:00
Tomasz Grabiec
95f515a6bd Move seastar submodule head
Scylla changes:
  sstable.cc: Remove file_exists() function which conflicts with seastar's

Amnon Heiman (2):
      reactor: Add file_exists method
      Add a wrapper for file_exists

Avi Kivity (2):
      Merge "Introduce shared_future" from Tomasz
      Merge ""scripts: a few fixes in posix_net_conf.sh" from Vlad

Gleb Natapov (3):
      rpc: not stop client in error state
      avoid allocation in parallel_for_each is there is nothing to do
      memory: fix size_to_idx calculation

Nadav Har'El (1):
      test: fix use-after-free in timertest

Pawe�� Dziepak (1):
      memory: use size instead of old_size to shrink memory block

Tomasz Grabiec (7):
      file: Mark move constructor as noexcept
      core: future: Add static asserts about type's noexcept guarantees
      core: future: Drop now redundant move_noexcept flag
      core: future_state: Make state getters non-destructive for non-rvalue-refs
      core: future: Make get_available_state() noexcept
      core: Introduce shared_future
      Make json_return_type movable

Vlad Zolotarov (8):
      scripts: posix_net_conf.sh: ban NIC IRQs from being moved by irqbalance
      scripts: posix_net_conf.sh: exclude CPU0 siblings from RPS
      scripts: posix_net_conf.sh: Configure XPS
      scripts: posix_net_conf.sh: Add a new mode for MQ NICs
      scripts: posix_net_conf.sh: increase some backlog sizes
      core: to_sstring(): cleanup
      core: to_sstring_strintf(): always use %g(or %lg) format for floating point values
      core: prevent explicit calls for to_sstring_sprintf()
2015-12-07 10:41:39 +01:00
Glauber Costa
79e70568d7 scylla-setup: do not add discard to the command line
In a recent discussion with the XFS developers, Dave Chinner recommended
us *not* to use discard, but rather issue fstrims explicitly. In machines
like Amazon's c3-class, the situation is made worse by the fact that discard
is not supported by the disk. Contrary to my intuition, adding the discard
mount option in such situation is *not* a nop and will just create load
for no reason.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-12-07 11:22:27 +02:00
Tomasz Grabiec
934d3f06d1 api: Make histogram reduction work on domain value instead of json objects
Objects extending json_base are not movable, so we won't be able to
pass them via future<>, which will assert that types are nothrow move
constructible.

This problem only affects httpd::utils_json::histogram, which is used
in map-reduce. This patch changes the aggregation to work on domain
value (utils::ihistrogram) instead of json objects.
2015-12-07 09:50:28 +01:00
Tomasz Grabiec
c0ac7b3a73 commitlog: Wrap subscription in a unique_ptr<> to make it nothrow movable
future<> will require nothrow move constructible types.
2015-12-07 09:50:28 +01:00
Tomasz Grabiec
657841922a Mark move constructors noexcept when possible 2015-12-07 09:50:27 +01:00
Tomasz Grabiec
fdc28a73f8 thrift: Make with_cob() handle not nothrow move constructible types 2015-12-07 09:50:27 +01:00
Tomasz Grabiec
538de7222a Introduce noexcept_traits 2015-12-07 09:50:27 +01:00
Tomasz Grabiec
bc23ebcbc3 schema_tables: Replace schema_result::value_type with equivalent movable type
future<> requires and will assert nothrow move constructible types.
2015-12-07 09:50:27 +01:00
Avi Kivity
91c2af2803 Merge "nodetool removenode fix + cleanup" from Asias 2015-12-07 10:41:51 +02:00
Takuya ASADA
2891291ad1 dist: add swagger-ui and api-doc on ubuntu package
Fixes .deb part of #520

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-07 10:39:59 +02:00
Takuya ASADA
3f0ca277e5 dist: add swagger-ui and api-doc on rpm package
Fixes .rpm part of #520

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-07 10:39:59 +02:00
Vlad Zolotarov
564cb2bcd1 gms::versioned_value: don't use to_sstring_sprintf() directly
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-12-06 12:24:54 +02:00
Raphael S. Carvalho
d435ca7da6 enable more logging for leveled compaction strategy
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-12-06 11:36:50 +02:00
Pekka Enberg
a95a7294ef types: Fix 'varint' type value compatibility check
Fixes #575.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-12-04 13:25:34 +01:00
Glauber Costa
5e8249f062 commitlog: fix but preventing flushing with default max_size value
The config file expresses this number in MB, while total_memory() gives us
a quantity in bytes. This causes the commitlog not to flush until we reach
really skyhigh numbers.

While we need this fix for the short term before we cook another release,
I will note that for the mid/long term, it would be really helpful to stop
representing memory amounts as integers, and use an explicit C++ type for
those. That would have prevented this bug.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-12-04 09:29:19 +02:00
Vlad Zolotarov
cd215fc552 types: map::to_string() - non-empty implementation
Print a map in the form of [(]{ key0 : value0 }[, { keyN : valueN }]*[)]
The map is printed inside () brackets if it's frozen.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-12-03 18:46:12 +01:00
Amnon Heiman
54b4f26cb0 API: Change the compaction summary to use an object
In origin, there are two APIs to get the information about the current
running compactions. Both APIs do the string formatting.

This patch changes the API to have a single API get_compaction that
would return a list of summary object.

The jmx would do the string formatting for the two APIs.

This change gives a better API experience is it's better documented and
would make it easier to support future format changes in origin.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-03 11:57:37 +02:00
Asias He
dcb9b441ab storage_service: Fix debug build
Start non-seed with debug build I saw:

==9844==WARNING: ASan is ignoring requested __asan_handle_no_return:
stack top: 0x7ffdabd73000; bottom 0x7fe309218000; size: 0x001aa2b5b000 (114398965760)
False positive error reports may follow
For details see http://code.google.com/p/address-sanitizer/issues/detail?id=189
DEBUG [shard 0] storage_service - Starting shadow gossip round to check for endpoint collision
=================================================================
==9844==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fe309219ad0 at pc 0x00000495a88e bp 0x7fe309219960 sp 0x7fe309219950
WRITE of size 8 at 0x7fe309219ad0 thread T0
    #0 0x495a88d in _Head_base<seastar::async(Func&&, Args&& ...)
       [with Func = service::storage_service::check_for_endpoint_collision()::<lambda()>; Args = {};
       futurize_t<typename std::result_of<typename std::decay<_Tp>::type(std::decay_t<Args>...)>::type> = future<>]::work*>
       /usr/include/c++/5.1.1/tuple:115
    #1 0x495a993 in _Tuple_impl<seastar::async(Func&&, Args&& ...)
       [with Func = service::storage_service::check_for_endpoint_collision()::<lambda()>; Args = {};
       futurize_t<typename std::result_of<typename std::decay<_Tp>::type(std::decay_t<Args>...)>::type> = future<>]::work*,
       std::default_delete<seastar::async(Func&&, Args&& ...) [with Func = service::storage_service::check_for_endpoint_collision()::<lambda()>;
       Args = {}; futurize_t<typename std::result_of<typename std::decay<_Tp>::type(std::decay_t<Args>...)>::type> = future<>]::work>, void>
       /usr/include/c++/5.1.1/tuple:213
    #2 0x495aa73 in tuple<seastar::async(Func&&, Args&& ...)
       [with Func = service::storage_service::check_for_endpoint_collision()::<lambda()>; Args = {};
       futurize_t<typename std::result_of<typename std::decay<_Tp>::type(std::decay_t<Args>...)>::type> = future<>]::work*,
       std::default_delete<seastar::async(Func&&, Args&& ...)
       [with Func = service::storage_service::check_for_endpoint_collision()::<lambda()>; Args = {};
       futurize_t<typename std::result_of<typename std::decay<_Tp>::type(std::decay_t<Args>...)>::type> = future<>]::work>, void>
       /usr/include/c++/5.1.1/tuple:613
    #3 0x495ab82 in unique_ptr /usr/include/c++/5.1.1/bits/unique_ptr.h:206
    ...
    #16 0x4d44c8e in _M_invoke /usr/include/c++/5.1.1/functional:1871
    #17 0x5d2fb7 in std::function<void ()>::operator()() const /usr/include/c++/5.1.1/functional:2271
    #18 0x8a1e70 in seastar::thread_context::main() core/thread.cc:139
    #19 0x8a1d89 in seastar::thread_context::s_main(unsigned int, unsigned int) core/thread.cc:130
    #20 0x7fe311b6cf0f  (/lib64/libc.so.6+0x48f0f)

I'm not sure why this patch helps. Perhaps the exception makes ASAN unhappy.

Anyway, this patch makes the debug build work again.

Fixes #613.
2015-12-03 10:42:11 +02:00
Tomasz Grabiec
d64db98943 query: Convert serialization of query::result to use db::serializer<>
That's what we're trying to standardize on.

This patch also fixes an issue with current query::result::serialize()
not being const-qualified, because it modifies the
buffer. messaging_service did a const cast to work this around, which
is not safe.
2015-12-03 09:19:11 +01:00
Tomasz Grabiec
d4d3a5b620 bytes_ostream: Make size_type and value_type public 2015-12-03 09:19:11 +01:00
Tomasz Grabiec
96d215168e Merge tag 'asias/gossip_start_stop/fix/v1' from seastar-dev.git
Fixes for issues in tests from Asias.
2015-12-03 09:10:55 +01:00
Tomasz Grabiec
f0cfa61968 Relax header dependencies 2015-12-03 09:10:02 +01:00
Tomasz Grabiec
9e0c498425 Merge branch 'dev/amnon/latency_clock_v2'
From Amnon:

After this series an example run of cfhistograms report a maximal 0.5s latency
as it should
2015-12-02 19:58:43 +01:00
Amnon Heiman
1812fe9e70 API: Add the get_version to messaging_service swagger definition file
Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-02 14:45:44 +02:00
Amnon Heiman
ae53604ed7 API: Add the get_version implementation to messaging service
This patch adds the implementation to the get_version.
After this patch the following url will be available:
messaging_service/version?addr=127.0.0.1

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-02 13:29:40 +02:00
Avi Kivity
53e3e79349 Merge "API: Stubing the compaction manager" from Amnon
"This series allows the compaction manager to be used by the nodetool as a stub implementation.

It has two changes:
* Add to the compaction manager API a method that returns a compaction info
object

* Stub all the compaction method so that it will create an unimplemented
warning but will not fail, the API implementation will be reverted when the
work on compaction will be completed."
2015-12-02 13:28:34 +02:00
Takuya ASADA
871bfb1c94 dist: generate correct distribution codename on debian/changelog
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-02 12:38:52 +02:00
Takuya ASADA
b61ea247d2 dist: check supported Ubuntu release
Warn if unsupported release.

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-02 12:38:52 +02:00
Takuya ASADA
0c66c25250 dist: fix typo on scylla_prepare
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-12-02 11:30:15 +02:00
Asias He
3004866f59 gossip: Rename start to start_gossiping
So that we have a more consistent name start_gossiping() and
stop_gossiping() and it will not confuse with get_gossiper.start().
2015-12-02 16:50:34 +08:00
Asias He
5c3951b28a gossip: Get rid of the handler helper 2015-12-02 16:50:34 +08:00
Asias He
7a6ad7aec2 gossip: Fix Assertion `local_is_initialized()' failed
This patch fixes the following cql_query_test failure.

   cql_query_test: scylla/seastar/core/sharded.hh:439:
   Service& seastar::sharded<Service>::local() [with Service =
   gms::gossiper]: Assertion `local_is_initialized()' failed.

The problem is in gossiper::stop() we call gossip::add_local_application_state()
which will in turn call gms::get_local_gossiper(). In seastar::sharded::stop

 _instances[engine().cpu_id()].service = nullptr;
 return inst->stop().then([this, inst] {
     return _instances[engine().cpu_id()].freed.get_future();
 });

We set the _instances to nullptr before we call the stop method, so
local_is_initialized asserts when we try to access get_local_gossiper
again.

To fix, we make the stopping of gossiper explicit. In the shutdown
procedure, we call stop_gossiping() explicitly.

This has two more advantages:

1) The api to stop gossip is now calling the stop_gossiping() instead of
sharing the seastar::sharded's stop method.

2) We can now get rid of the _handler seastar::sharded helper.
2015-12-02 16:50:34 +08:00
Asias He
e22972009b gossip: Make log message in mark_dead stick to cassandra 2015-12-02 14:21:26 +08:00
Asias He
ad30cf0faf failure_detector: Use a standalone logger name
Do not share logger with gossip. Sometimes, it is useful to only see one
of them.
2015-12-02 14:21:26 +08:00
Asias He
eb05dc680d storage_service: Warn lost of data when remove a node
If RF = 1 and one node is down, it is possible that data is lost. Warn
this in the logger.
2015-12-02 14:21:26 +08:00
Asias He
0fe14e2b4b storage_service: Do not ignore future in remove_node 2015-12-02 14:21:26 +08:00
Asias He
5a7f15ba49 storage_service: Run confirm_replication on cpu zero
storage_service::_replicating_nodes is valid on cpu zero only.
2015-12-02 14:21:26 +08:00
Amnon Heiman
7e79d35f85 Estimated histogram: Clean the add interface
The add interface of the estimated histogram is confusing as it is not
clear what units are used.

This patch removes the general add method and replace it with a add_nano
that adds nanoseconds or add that gets duration.

To be compatible with origin, nanoseconds vales are translated to
microseconds.
2015-12-01 15:28:06 +02:00
Amnon Heiman
61abc85eb3 histogram: Add started counter
This patch adds a started counter, that is used to mark the number of
operation that were started.

This counter serves two purposes, it is a better indication for when to
sample the data and it is used to indicate how many pending operations
are.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-01 15:28:06 +02:00
Amnon Heiman
88dcf2e935 latency: Switch to steady_clock
The system clock is less suitable for for time difference than
steady_clock.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-01 15:28:06 +02:00
Avi Kivity
f667e05e08 Merge "backport gosisp and storage_service fix" from Asias
"This contains most bug fixes from imported version commit
38847a6bd967e4f41bc7b1fc83629161a2c214dc to c* 2.1.11 for gossip and
storage_service."
2015-12-01 14:42:41 +02:00
Asias He
dc6f2157e7 Update ORIGIN for gossip and storage_service 2015-12-01 19:45:04 +08:00
Amnon Heiman
3674ee2fc1 API: get snapshot size
This patch adds the column family API that return the snapshot size.
The changes in the swagger definition file follo origin so the same API will be used for the metric and the
column_family.

The implementation is based on the get_snapshot_details in the
column_family.

This fix:
425

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-12-01 11:41:52 +02:00
Asias He
56df32ba56 gossip: Mark node as dead even if already left
Backport: CASSANDRA-10205

484e645 Mark node as dead even if already left
2015-12-01 17:29:25 +08:00
Asias He
59694a8e43 failure_detector: Print versions for gossip states in gossipinfo
Backport: CASSANDRA-10330

ae4cd69 Print versions for gossip states in gossipinfo

For instance, the version for each state, which can be useful for
diagnosing the reason for any missing states. Also instead of just
omitting the TOKENS state, let's indicate whether the state was actually
present or not.
2015-12-01 17:29:25 +08:00
Asias He
af91a8f31b storage_service: Fix transition from write survey to normal mode
Backport: CASSANDRA-9740

52dbc3f Can't transition from write survey to normal mode
2015-12-01 17:29:25 +08:00
Asias He
2f071d9648 storage_service: Refuse to decommission if not in state NORMAL
Backport: CASSANDRA-8741

5bc56c3 refuse to decomission if not in state NORMAL
2015-12-01 17:29:25 +08:00
Asias He
224db2ba37 failure_detector: Don't mark nodes down before the max local pause interval once paused
Backport: CASSANDRA-9446

7fba3d2 Don't mark nodes down before the max local pause interval once paused
2015-12-01 17:29:25 +08:00
Asias He
51fcc48700 failure_detector: Failure detector detects and ignores local pauses
Backport: CASSANDRA-9183

4012134 Failure detector detects and ignores local pauses
2015-12-01 17:29:25 +08:00
Asias He
1b9e350614 gossip: Do not print node is now part of the cluster during gossip shadow round
With

   Node 1 (Seed node, Port 7000 is opened, 10.184.9.144)
   Node 2 (Port 7000 is opened, 10.184.9.145)
   Node 3 (Port 7000 is blocked by firewall)

On Node 3, we saw the following error which was very confusing: Node 3
saw Node 1 and Node 3 but it complained it can not contact any seeds.

The message "Node 10.184.9.144 is now part of the cluster" and friends
are actually messages printed during the gossip shadow round where Node
3 connects to Node 1's port 7000 and Node 1 returns all info it knows to
Node 3, so that Node 3 knows Node 1 and Node 2 and we see the "Node
10.184.9.144/145 is now part of the cluster" message.

However, during the normal gossip round, Node 3 will not mark Node 1 and
Node 2 UP until the Seed node initiates a gossip round to Node 3, (note
port 7000 on node 3 is blocked in this case). So Node 3 will not mark
Node 1 and Node 2 UP and we see the "Unable to contact any seeds" error.

[shard 0] storage_service - Loading persisted ring state
[shard 0] gossip - Node 10.184.9.144 is now part of the cluster
[shard 0] gossip - inet_address 10.184.9.144 is now UP
[shard 0] gossip - Node 10.184.9.145 is now part of the cluster
[shard 0] gossip - inet_address 10.184.9.145 is now UP
[shard 0] storage_service - Starting up server gossip
scylla_run[12479]: Start gossiper service ...
[shard 0] storage_service - JOINING: waiting for ring information
[shard 0] storage_service - JOINING: schema complete, ready to bootstrap
[shard 0] storage_service - JOINING: waiting for pending range calculation
[shard 0] storage_service - JOINING: calculation complete, ready to bootstrap
[shard 0] storage_service - JOINING: getting bootstrap token
[shard 0] storage_service - JOINING: sleeping 5000 ms for pending range setup
scylla_run[12479]: Exiting on unhandled exception of type 'std::runtime_error': Unable to contact any seeds!
2015-12-01 17:29:25 +08:00
Asias He
f62a6f234b gossip: Add shutdown gossip state
Backported: CASSANDRA-8336 and CASSANDRA-9871

84b2846 remove redundant state
b2c62bb Add shutdown gossip state to prevent timeouts during rolling restarts
8f9ca07 Cannot replace token does not exist - DN node removed as Fat Client

Fixes:

When X is shutdown, X sends SHUTDOWN message to both Y and Z, but for
some reason, only Y receives the message and Z does not receive the
message. If Z has a higher gossip version for X than Y has for
X, Z will initiate a gossip with Y and Y will mark X alive again.

X ------> Y
 \      /
  \    /
    Z
2015-12-01 17:29:25 +08:00
Gleb Natapov
8c02ad0e9e messaging: log connection dropping event 2015-11-30 19:42:04 +02:00
Avi Kivity
b85f3ad130 Merge "Commit log replay - handle corrupted data silently, as non-fatal"
Fixes: #593

"Changes the parser/replayer to treat data corruption as non-fatal,
skipping as little as possible to get the most data out of a segment,
but keeping track of, and reporting, the amount corrupted.

Replayer handles this and reports any non-fatal errors on replay finish.
Also added tests for corruption cases.

This patch series contains a cleanup-patch for commitlog_tests that was
previously submitted, but got lost."
2015-11-30 19:13:31 +02:00
Gleb Natapov
5b9f3bff7d storage_proxy: simplify error handling by using this/handle_exception
It is cleaner to use this/handle_exception instead of then_wrapped if
normal and error flow do not share any state.
2015-11-30 17:41:32 +02:00
Gleb Natapov
5484f25091 storage_proxy: remove unneeded continuation
make_ready_future() around when_all() is not longer needed. It was
added to catch mutate_locally() exceptions, but now it is handled in
lower level.
2015-11-30 17:41:28 +02:00
Gleb Natapov
cf95c3f681 storage_proxy: introduce unique_response_handler object to prevent write request leaks
If something bad happens between write request handler creation and
request execution the request handler have to be destroyed. Currently
code tries to do that explicitly in all places where request may be
abandoned, but it misses some (at least one). This patch replaces this
by introducing unique_response_handler object that will remove the handler
automatically if request is not executed for some reason.
2015-11-30 17:41:27 +02:00
Gleb Natapov
d8afc6014e storage_proxy: catch exception thrown by mutate_locally in mutate verb handler
Also simplify error logging.
2015-11-30 17:41:25 +02:00
Avi Kivity
3c9ded27cc Update scylla-ami submodule
* ami/files/scylla-ami 3f37184...07b7118 (1):
  > Use /etc/scylla as SCYLLA_CONF directory
2015-11-30 16:39:49 +02:00
Takuya ASADA
616903de12 dist: use distribution version of antlr3, on Ubuntu 15.10
Rename antlr3-tool to antlr3 (same as distribution package), and use distribution version if it's available

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-30 16:37:36 +02:00
Pekka Enberg
0e8f80b5ee Merge "Relax bootstrapping/leaving/moving nodes check" from Asias 2015-11-30 11:53:07 +02:00
Asias He
2022117234 failure_detector: Enable phi_convict_threshold option
Adjusts the sensitivity of the failure detector on an exponential scale.

Use as:

$ scylla --phi-convict-threshold 9

Default to 8.
2015-11-30 11:09:36 +02:00
Asias He
db70643fe3 failure_detector: Print application_state properly 2015-11-30 11:08:40 +02:00
Asias He
aaca88a1e7 token_metadata: Add print_pending_ranges for debug print
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-30 11:07:42 +02:00
Avi Kivity
2c59e2f81f Merge "Fix race between population and update in row cache" from Tomasz
"Before this change, populations could race with update from flushed
memtable, which might result in cache being populated with older
data. Populations started before the flush are not considering the
memtable nor its sstable.

The fix employed here is to make update wait for populations which
were started before the flushed memtable's sstable was added to the
undrelying data source. All populatinos started after that are
guaranteed to see the new data. The update() call will wait only for
current populating reads to complete, it will not wait for readers to
get advanced by the consumer for instance."
2015-11-30 11:06:23 +02:00
Tomasz Grabiec
8d88ece896 schema_tables: Fix "comment" property not being loaded from storage 2015-11-30 10:57:36 +02:00
Pekka Enberg
a64fa3db03 Merge "range_streamer fix and cleanup" from Asias
Do not use hard-coded value for is_replacing and rangemovement.
2015-11-30 10:47:06 +02:00
Asias He
879a4ad4d3 storage_service: Update pending ranges immediately after update of normal tokens
To avoid a race where natural endpoint was updated to contain node A,
but A was not yet removed from pending endpoints.

This fixes the root cause of commit d9d8f87c1 (storage_proxy: filter out
natural endpoints from pending endpoint). This patch alone fixes #539,
but we still want commit d9d8f87c1 to be safe.
2015-11-30 10:20:59 +02:00
Asias He
0af7fb5509 range_streamer: Kill FIXME in use_strict_consistency for consistent_rangemovement 2015-11-30 09:15:42 +08:00
Asias He
f80e3d7859 range_streamer: Simplify multiple_map to map conversion in add_ranges 2015-11-30 09:15:42 +08:00
Asias He
21882f5122 range_streamer: Kill one leftover comment 2015-11-30 09:15:42 +08:00
Asias He
6b258f1247 range_streamer: Kill FIXME for is_replacing 2015-11-30 09:15:42 +08:00
Asias He
aa2b11f21b database: Move is_replacing and get_replace_address to database class
So they can be used outside storage_service.
2015-11-30 09:15:42 +08:00
Asias He
80d1d4d161 storage_service: Relax bootstrapping/leaving/moving nodes check in check_for_endpoint_collision
When other bootstrapping/leaving/moving nodes are found during
bootstrap, instead of throwing immediately, sleep and try again for one
minute, hoping other nodes will finish the operation soon.

Since we are retrying using shadow gossip round more than once, we need
to put the gossip state back to shadow round after each shadow round, to
make shadow round works correctly.

This is useful when starting an empty cluster for testing. E.g,

   $ scylla --listen-address 127.0.0.1
   $ sleep 3
   $ scylla --listen-address 127.0.0.2
   $ sleep 3
   $ scylla --listen-address 127.0.0.3

Without this patch, node 3 will hit the check.

   TIME  STATUS
   -----------------------
   Node  1:
   32:00 Starts
   32:00 In NORMAL status

   Node  2:
   32:03 Starts
   32:04 In BOOT status
   32:10 In NORMAL status

   Node  3:
   32:06 Starts
   32:06 Found node 2 in BOOT status, hit the check, sleep and try again
   32:11 Found node 2 in NORMAL status, can keep going now
   32:12 In BOOT status
   32:18 In NORMAL status
2015-11-30 09:07:57 +08:00
Asias He
8b19373536 storage_service: Relax bootstrapping/leaving/moving nodes check in join_token_ring
When other bootstrapping/leaving/moving nodes are found during
bootstrap, instead of throwing immediately, sleep and try again for one
minute, hoping other nodes will finish the operation soon.

This is useful when starting an empty cluster for testing. E.g,

   $ scylla --listen-address 127.0.0.1
   $ scylla --listen-address 127.0.0.2
   $ scylla --listen-address 127.0.0.3

Without this patch, node 3 will hit the check.

   TIME  STATUS
   -----------------------
   Node  1:
   25:19 Starts
   25:20 In NORMAL status

   Node  2:
   25:19 Starts
   25:23 In BOOT status
   25:28 In NORMAL status

   Node  3:
   25:19 Starts
   25:24 Found node 2 in BOOT status, hit the check, sleep and try again
   25:29 Found node 2 in NORMAL status, can keep going now
   25:29 In BOOT status
   25:34 In NORMAL status
2015-11-30 09:07:57 +08:00
Tomasz Grabiec
df46542832 tests: Add test for populate and update race 2015-11-29 16:25:22 +01:00
Tomasz Grabiec
6f69d4b700 tests: Avoid potential use after free on partition range 2015-11-29 16:25:21 +01:00
Tomasz Grabiec
de75f3fa69 row_cache: Add default value for partition range in make_reader() 2015-11-29 16:25:21 +01:00
Tomasz Grabiec
ab328ead3d mutation: Introduce ring_position() 2015-11-29 16:25:21 +01:00
Tomasz Grabiec
32ac2ccc4a memtable: Introduce apply(memtable&) 2015-11-29 16:25:21 +01:00
Tomasz Grabiec
7c3e6c306b row_cache: Wait for in-flight populations on update
Before this change, populations could race with update from flushed
memtable, which might result in cache being populated with older
data. Populations started before the flush are not considering the
memtable nor its sstable.

The fix employed here is to make update wait for populations which
were started before the flushed memtable's sstable was added to the
undrelying data source. All populatinos started after that are
guaranteed to see the new data.
2015-11-29 16:25:21 +01:00
Tomasz Grabiec
a3e3add28a utils: Introduce phased_barrier
Utility for waiting on a group of async actions started before certain
point in time.
2015-11-29 16:25:21 +01:00
Pekka Enberg
a26ffefd53 transport/server: Remove CQL text type from encoding
The text data type is no longer present in CQL binary protocol v3 and
later. We don't need it for encoding earlier versions either because
it's an alias for varchar which is present in all CQL binary protocol
versions.

Fixes #526.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-27 09:13:56 +01:00
Pekka Enberg
2599b78583 Merge "CQL notification + storage_service fix" from Asias
"pushed_notifications_test.py dtest is now passing"
2015-11-27 10:09:56 +02:00
Asias He
da0e80a286 storage_service: Fix failed bootstrap/replace attempts being persisted in system.peers
Backported from:

ac46747 Fix failed bootstrap/replace attempts being persisted in system.peers (CASSANDRA-9180)
2015-11-27 15:31:56 +08:00
Asias He
36b2de10ed failure_detector: Improve FD logging when the arrival time is ignored
Backport from:

eb9c5bb Improve FD logging when the arrival time is ignored.
2015-11-27 15:31:56 +08:00
Asias He
ed9cd23a2d transport: Fix duplicate up/down messages sent to native clients
This patch plus pekka's previous commit 3c72ea9f96

   "gms: Fix gossiper::handle_major_state_change() restart logic"

fix CASSANDRA-7816.

Backported from:

   def4835 Add missing follow on fix for 7816 only applied to
           cassandra-2.1 branch in 763130bdbde2f4cec2e8973bcd5203caf51cc89f
   763130b Followup commit for 7816
   2199a87 Fix duplicate up/down messages sent to native clients

Tested by:
   pushed_notifications_test.py:TestPushedNotifications.restart_node_test
2015-11-27 15:31:56 +08:00
Asias He
25bb889c2a transport: Fix wrong message for UP and DOWN event 2015-11-27 15:31:56 +08:00
Asias He
ca8c4f3e77 storage_service: Fix MOVED_NODE client event (CASSANDRA-8516)
Backport from:

b296c55f956c6ef07c8330dc28ef8c351e5bcfe2 (Fix MOVED_NODE client event)

Fixes:

DISABLE_VNODES=true nosetests
pushed_notifications_test.py:TestPushedNotifications.move_single_node_test
2015-11-27 15:31:56 +08:00
Gleb Natapov
ad358300a9 cql server: remove connection from notifiers earlier
Remove connection from notifiers lists just before closing it to prevent
attempts to send notification on already closed connection.
2015-11-26 18:50:08 +02:00
Pekka Enberg
569d288891 cql3: Add TRUNCATE TABLE alias for TRUNCATE
CQL 3.2.1 introduces a "TRUNCATE TABLE X" alias for "TRUNCATE X":

  4e3555c1d9

Fix our CQL grammar to also support that.

Please note that we don't bump up advertised CQL version yet because our
cqlsh clients won't be able to connect by default until we upgrade them
to C* 2.1.10 or later.

Fixes #576

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-26 18:45:50 +02:00
Gleb Natapov
96f40d535e cql server: add missing gate during connection access
cql connection access is protected by a gate, but event notifiers have
omitted taking it. Fix it.
2015-11-26 13:05:59 +02:00
Tomasz Grabiec
a7c11d1e30 db: Fix handling of missing column family
The FIXMEs are no longer valid, we load schema on bootstrap and don't
support hot-plugging of column families via file system (nor does
Cassandra).

Handling of missing tables matches Cassandra 2.1, applies log
it and continue, queries propagate the error.
2015-11-25 16:59:15 +02:00
Tomasz Grabiec
3a402db1be storage_proxy: Remove dead signature 2015-11-25 16:57:03 +02:00
Asias He
d03b452322 storage_service: Remove RPC client in on_dead
When gossip mark a node down, we should close all the RPC connections to
that node.
2015-11-25 16:30:14 +02:00
Gleb Natapov
d9d8f87c1b storage_proxy: filter out natural endpoints from pending endpoint
If request comes after natural endpoint was updated to contain node A,
but A was not yet removed from pending endpoints it will be in both and
write request logic cannot handle this properly. Filter nodes which are
already in natural endpoint from pending endpoint to fix this.

Fixes #539.
2015-11-25 16:28:55 +02:00
Pekka Enberg
cf7541020f Merge "Enable more config options" from Asias 2015-11-25 16:09:22 +02:00
Tomasz Grabiec
c3f03d5c96 Merge branch 'pdziepak/random-lsa-patches/v3' from seastar-dev.git
LSA fixes from Paweł.
2015-11-25 10:26:23 +01:00
Paweł Dziepak
89f7f746cb lsa: fix printing object_descriptor::_alignment
object_descriptor::_alignment is of type uint8_t which is actually an
unsigned char.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 20:13:29 +01:00
Paweł Dziepak
65875124b7 lsa: guarantee that segment_heap doesn't throw
boost::heap::binomial_heap allocates helper object in push() and,
therefore, may throw an exception. This shouldn't happen during
compaction.

The solution is to reserve space for this helper object in
segment_descriptor and use a custom allocator with
boost::heap::binomial_heap.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 19:51:22 +01:00
Paweł Dziepak
273b8daeeb lsa: add no-op default constructor for segment
Zero initialization of segment::data when segment is value initialized
is undesirable.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 16:37:37 +01:00
Paweł Dziepak
e6cf3e915f lsa: add counters for memory used by large objects
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 16:36:27 +01:00
Paweł Dziepak
9396956955 scylla-gdb.py: show lsa statistics and regions
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 16:36:20 +01:00
Paweł Dziepak
aaecf5424c scylla-gdb.py: show free, used and total memory
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 16:36:16 +01:00
Paweł Dziepak
6b113a9a7a lsa: fix eviction of large blobs
LSA memory reclaimer logic assumes that the amount of memory used by LSA
equals: segments_in_use * segment_size. However, LSA is also responsible
for eviction of large objects which do not affect the used segmentcount,
e.g. region with no used segments may still use a lot of memory for
large objects. The solution is to switch from measuring memory in used
segments to used bytes count that includes also large objects.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-24 16:29:09 +01:00
Takuya ASADA
4a8c79ca0e dist: re-initialize RAID on ephemeral disk when stop/restart AMI instance
Since this won't check disk types, may re-initialize RAID on EBS when first block was lost.
But in such condition, probably re-initialize RAID is the only choice we can take, so this is fine.
Fixes #364.

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-24 10:46:10 +02:00
Asias He
3a9200db03 config: Add more document for options
For consistent_rangemovement, join_ring, load_ring_state, etc.
2015-11-24 10:07:31 +08:00
Asias He
7ddf8963f5 config: Enable broadcast_rpc_address option
With this patch, start two nodes

node 1:
scylla --rpc-address 127.0.0.1 --broadcast-rpc-address 127.0.0.11

node 2:
scylla --rpc-address 127.0.0.2 --broadcast-rpc-address 127.0.0.12

On node 1:
cqlsh> SELECT rpc_address from system.peers;

 rpc_address
-------------
  127.0.0.12

which means client should use this address to connect node 2 for cql and
thrift protocol.
2015-11-24 10:07:31 +08:00
Asias He
33ef58c5c9 utils: Add get_broadcast_rpc_address and set_broadcast_rpc_address helper 2015-11-24 10:07:31 +08:00
Asias He
1e55aa38c1 storage_service: Implement is_replacing 2015-11-24 10:07:29 +08:00
Asias He
644c226d58 config: Enable replace_address and replace_address_first_boot option
It is same as

   -Dcassandra.replace_address
   -Dcassandra.replace_address_first_boot

in cassandra.
2015-11-24 10:07:24 +08:00
Asias He
bfe26ea208 config: Enable replace_token option
It is same as

   -Dcassandra.replace_token

in cassandra.

Use it as:

   $ scylla --replace-token $token1,$token2,$token3
2015-11-24 10:07:20 +08:00
Asias He
730abbc421 config: Enable replace_node option
It is same as

   -Dcassandra.replace_node

in cassandra.

Use it as:

   $ scylla --replace-node $node_uuid
2015-11-24 10:07:16 +08:00
Asias He
2513d6ddbe config: Enable load_ring_state option
It is same as

   -Dcassandra.load_ring_state

in cassandra.

Use it as:

   $ scylla --load-ring-state 0

or

   $ scylla --load-ring-state 1
2015-11-24 10:07:12 +08:00
Asias He
6e72e78e0d config: Enable join_ring option
It is same as

   -Dcassandra.join_ring

in cassandra.

Use it as:

   $ scylla --join-ring 0

or

   $ scylla --join-ring 1
2015-11-24 10:07:07 +08:00
Asias He
505b3e4936 config: Enable consistent_rangemovement option
It is same as

  -Dcassandra.consistent.rangemovement

in cassandra.

Use it as:

  $ scylla --consistent-rangemovement 0

or

  $ scylla --consistent-rangemovement 1
2015-11-24 10:06:54 +08:00
Gleb Natapov
33e5097090 messaging: do not kill live connection needlessly
Messaging service closes connection in rpc call continuation on
closed_error, but the code runs for each outstanding rpc call on the
connection, so first continuation may destroy genuinely closed connection,
then connection is reopened and next continuation that handless previous
error kills now perfectly healthy connection. Fix this by closing
connection only in error state.
2015-11-23 20:16:28 +02:00
Tomasz Grabiec
cb0b56f75f Merge tag 'empty/v3' from https://github.com/avikivity/scylla
From Avi:

Origin supports a notion of empty values for non-container types; these
are serialized as zero-length blobs.  They are mostly useless and only
retained for compatibility.

The implementation here introduces a wrapper maybe_empty<T>, similar to
optional<T> but oriented towards usually-nonempty usage with implicit
conversion.

There is more work needed for full empty support: fixing up deserializers to
create empty values instead of nulls, and splitting up data_value into
data_value and a data_value_nonnull for the cases that require it.

(I chose maybe_empty<> rather than using optional<data_value> for nullable
data_value both because it requires fewer changes, and because
optional<data_value> introduces a lot of control flow when moving or copying,
which would be mostly useless in most cases).
2015-11-23 16:12:06 +01:00
Calle Wilund
b1a0c4b451 commitlog_tests: Add segment corruption tests
Test entry and chunk corruption.
2015-11-23 15:43:33 +01:00
Calle Wilund
d65adef10c commitlog_tests: test cleanup
This cleanup patch got lost in git-space some time ago. It is however sorely
needed...

* Use cleaner wrapper for creating temp dir + commit log, avoiding
  having to clear and clean in every test, etc.
* Remove assertions based on file system checks, since these are not
  valid due to both the async nature of the CL, and more to the point,
  because of pre-allocation of files and file blocks. Use CL
  counters/methods instead
* Fix some race conditions to ensure tests are safe(r)
* Speed up some tests
2015-11-23 15:42:45 +01:00
Calle Wilund
262f44948d commitlog: Add get_flush_count method (for testing) 2015-11-23 15:42:45 +01:00
Calle Wilund
76b43fbf74 commitlog_replayer: Handle replay data errors as non-fatal
Discern fatal and non-fatal excceptions, and handle data corruption 
by adding to stats, resporting it, but continue processing.

Note that "invalid_arguement", i.e. attempting to replay origin/old
segments are still considered fatal, as it is probably better to 
signal this strongly to user/admin
2015-11-23 15:42:45 +01:00
Calle Wilund
2fe2320490 commitlog: Make reading segments with crc/data errors non-fatal
Parser object now attempts to skip past/terminate parsing on corrupted
entries/chunks (as detected by invalid sizes/crc:s). The amount of data
skipped is kept track of (as well as we can estimate - pre-allocation
makes it tricky), and at the end of parsing/reporting, IFF errors 
occurred, and exception detailing the failures is thrown (since 
subsciption has little mechanism to deal with this otherwise). 

Thus a caller can decide how to deal with data corruption, but will be
given as many entries as possible.
2015-11-23 15:42:45 +01:00
Avi Kivity
23895ac7f5 types: fix up confusion around empty serialized representation
An empty serialized representation means an empty value, not NULL.

Fix up the confusion by converting incorrect make_null() calls to a new
make_empty(), and removing make_null() in empty-capable types like
bytes_type.

Collections don't support empty serialized representations, so remove
the call there.
2015-11-22 12:20:24 +02:00
Tomasz Grabiec
ae9e0c3d41 storage_proxy: Avoid potential use after move on schema_ptr
Paramter evaluation order is unspecified, so it's possible that the
move of 'schema' into lambda captures would happen before construction of
mutation.
2015-11-22 12:15:04 +02:00
Avi Kivity
0799251a9f Merge "optimize the sstable loading step of boot" from Raphael
"To speed up boot, parallelism was introduced to our code that loads
sstables from a column family, a function was implemented to read
the minimum from a sstable to determine whether it belongs to the
current shard, and buffer size in read simple is dynamically chosen
based on the size of the file and dma alignment.
The latter is important because filter file can be considerably
large when the respective sstable (data file) is very large.
Before this patchset, scylla took about 5 minutes to boot with a
data directory of 660GB. After this patchset, scylla took about 20
seconds to boot with the same data directory."
2015-11-22 11:27:34 +02:00
Asias He
23723991ed gossip: Fix STATUS field in nodetool gossipinfo
Before:
   === with c* cluster ===
   $ nodetool -p 7100 gossipinfo

   STATUS:NORMAL,-1139428872328849340

   === with scylla ===
   $ nodetool -p 7100 gossipinfo

   0:NORMAL,8251763528961471825;-9147358554612963965;5334343410266177046

After:
   === with scylla ===
   $ nodetool -p 7100 gossipinfo

   0:NORMAL,8251763528961471825

To align with c*, print one token in the STATUS field.

Refs #508.
2015-11-20 10:57:49 +02:00
Raphael S. Carvalho
a5842642fa sstables: change buf size in read_simple to 128k
Avi says:
"A small buffer size will hurt if we read a large file, but
a large buffer size won't hurt if we read a small file, since
we close it immediately."

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:35:25 -02:00
Raphael S. Carvalho
0f3ccc1143 db: optimize the sstable loading process
Currently, we only determine if a sstable belongs to current shard
after loading some of its components into memory. For example,
filter may be considerably big and its content is irrelevant to
decide if a sstable should be included to a given shard.
Start using the functions previously introduced to optimize the
sstable loading process. add_sstable no longer checks if a sstable
is relevant to the current shard.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:34:25 -02:00
Raphael S. Carvalho
0053394ec0 sstables: introduce mark_sstable_for_deletion
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:34:24 -02:00
Raphael S. Carvalho
0ce2b7bc8d db: introduce belongs_to_current_shard
Returns true if key range belongs to current shard.
False otherwise.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:34:21 -02:00
Raphael S. Carvalho
f06b72eb18 sstables: introduce function to return sstable key range
Provides a function that will return sstable key range reading only
the summary component.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:34:19 -02:00
Raphael S. Carvalho
966e8c7144 db: introduce parallelism to sstable loading
Boot may be slow because the function that loads sstables do so
serially instead of in parallel. In the callback supplied to
lister::scan_dir, let's push the future returned by probe_file
(function that loads sstable) into a vector of future and wait
for all of them at the end.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-19 13:34:11 -02:00
Takuya ASADA
83c8b3e433 dist: support Ubuntu 15.10
We cannot share some dependency package names between 14.04 and 15.10, so need to add ifdefs.
Not tested on other version of Ubuntu.

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-19 10:57:25 +02:00
Tomasz Grabiec
53e842aaf7 scylla-gdb.py: Fix scylla column_families command 2015-11-19 10:44:00 +02:00
Avi Kivity
0b91b643ba types: empty value support for non-container types
Origin supports (https://issues.apache.org/jira/browse/CASSANDRA-5648) "empty"
values even for non-container types such as int.  Use maybe_empty<> to
encapsulate abstract_type::native_type, adding an empty flag if needed.
2015-11-18 18:38:38 +02:00
Avi Kivity
7257f72fbf types: introduce maybe_empty<T> type alias
- T for container types (that can naturally be empty)
 - emptyable<T> otherwise (adding that property artificially)
2015-11-18 15:25:24 +02:00
Avi Kivity
58d3a3e138 types: introduce emptyable<> template
Similar to optional<>, with the following differences:
 - decays back to the encapsulated type, with an emptiness check;
   this reflects the expectation that the value will rarely be empty
 - avoids conditionals during copy/move (and requires a default constructor),
   again with the same expectation.
2015-11-18 15:25:22 +02:00
Gleb Natapov
0870caaea1 cql transport: catch all exceptions
Not all exceptions are inherited from std::exception
(std::nested_exception) for instance, so catch and log all of them.
2015-11-18 15:17:43 +02:00
Asias He
242e5ea291 streaming: Ignore remote no_such_column_family for stream_transfer_task
When we start to sending mutations for cf_id to remote node, remote node
might do not have the cf_id anymore due to dropping of the cf for
instance.

We should not fail the streaming if this happens, since the cf does not
exist anymore there is no point streaming it.

Fixes #566
2015-11-18 15:12:23 +02:00
Asias He
3816e35d11 storage_service: Detect other bootstrapping/leaving/moving nodes during bootstrap 2015-11-18 15:11:56 +02:00
Avi Kivity
6390bc3121 README: instructions for contributing 2015-11-18 15:10:37 +02:00
Asias He
3b52033371 gossip: Favor newly added node in do_gossip_to_live_member
When a new node joins a cluster, it will starts a gossip round with seed
node. However, within this round, the seed node will not tell the new
node anything it knows about other nodes in the cluster, because the
digest in the gossip SYN message contains only the new node itself and
no other nodes. The seed node will pick randomly from the live nodes,
including the newly added node in do_gossip_to_live_member to start a
gossip round. If the new node is "lucky", seed node will talk to it very
soon and tells all the information it knows about the cluster, thus the
new node will mark the seed node alive and think it has seen the seed
node. If there considerably large number of live nodes, it might take a
long time before the seed node pick the new node and talk to it.

In bootstrap code, storage_service::bootstrap checks if we see any nodes
after sleep of RING_DELAY milliseconds and throw "Unable to contact any
seeds!" if not, thus the node will fail to bootstrap.

To help the seed node talk to new node faster, we favor new node in
do_gossip_to_live_member.
2015-11-18 15:00:37 +02:00
Amnon Heiman
374414ffd0 API: failure_detector modify the get_all_endpoint_states
In origin, get_all_endpoint_states perform all the information
formatting and returns a string.

This is not a good API approach, this patch replaces the implementation
so the API will return an array of values and the JMX will do the
formatting.

This is a better API and would make it simpler in the future to stay in
sync with origin output.

This patch is part of #508

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-18 14:59:09 +02:00
Avi Kivity
17f6dc3671 Merge seastar upstream
* seastar 95ddb8e...84cb6df (2):
  > rpc: do not convert EOF into exception
  > reactor: remove debug output in command line option validation
2015-11-18 11:20:27 +02:00
Takuya ASADA
16cd5892f7 dist: setup rps on scylla_prepare, not on scylla_run
All preparation of running scylla should be done in scylla_prepare

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-18 11:20:17 +02:00
Asias He
269ea7f81b storage_service: Enable is_ready_for_bootstrap in join_token_ring
The goal is to make sure our schema matches with other nodes in the
cluster.
2015-11-18 10:46:40 +02:00
Asias He
bb1470f0d4 migration_manager: Introduce is_ready_for_bootstrap
This compares local schema version with other nodes in the cluster.
Return true if all of them match with each other.
2015-11-18 10:46:06 +02:00
Avi Kivity
ba859acb3b big_decimal: add default constructor
Arithmetic types should have a default constructor, and anyway the
following patch wants it.
2015-11-18 10:36:03 +02:00
Takuya ASADA
f0a6c33b6d dist: use /var/lib/scylla instead of /data on ami
Fixes #551.
Change mountpoint to /var/lib/scylla, copy conf/ on it.
Note: need to replace conf/ with symlink to /etc/scylla when new rpm uploaded on yum repository.

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
Signed-off-by: Pekka Enberg <penberg@iki.fi>
2015-11-18 10:10:48 +02:00
Calle Wilund
6d25b8d496 query_pagers: Handle partition with no data but statics
If we get a partition with no row data, but statics, we should treat this as
a row (include in count), but also make sure we skip to next partition
if our page ends here.

The "end partition" with zero rows but static data can also happen if we
happen to resume paging by giving a column range exluding all data. In this
case we should _not_ include it, since we have already provided the
data in question in previous page.

Fixes #556
2015-11-17 17:49:14 +02:00
Calle Wilund
5368f1a998 query_pagers: Fix aggregate query bug
1.) Should not reset to input query state if run repeatedly
2.) And if run repeatedly without input state, likewise keep
    the internal one active

Fixes #560
2015-11-17 17:48:58 +02:00
Avi Kivity
7d8c72d24f Merge "move scylla.yaml to /etc/scylla" from Takuya
"To keep compatibility with scylla-tools-java, it links /etc/scylla to /var/lib/scylla/conf.

Problem on this patchset is, I added SCYLLA_HOME and SCYLLA_CONF on /etc/sysconfig/scylla-server.
However, the file is marked as config file, it won't be automatically upgrade.
If user doesn't upgrade the file manually, scylla-server still able to run with /var/lib/scylla/conf because we have symlink, but never switches to /etc/scylla."
2015-11-17 17:02:14 +02:00
Takuya ASADA
60efcd791a dist: don't specify scylla.yaml path directly, use SCYLLA_CONF instead 2015-11-17 02:37:37 +09:00
Takuya ASADA
6972d78e93 dist: specify SCYLLA_CONF as /etc/scylla
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-17 02:37:37 +09:00
Takuya ASADA
aeb076a6c0 dist: change scylla.yaml install path to /etc/scylla (Ubuntu)
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-17 02:37:37 +09:00
Takuya ASADA
b5bd34c0c2 dist: change scylla.yaml install path to /etc/scylla (Fedora/CentOS)
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-17 02:37:37 +09:00
Takuya ASADA
51813dc8ce dist: merge redhat/limits.d and debian/limits.d to common/limits.d
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-17 02:37:37 +09:00
Takuya ASADA
863eea2bb3 dist: do not overwrite config files on 'yum update'
Fixes a problem on AMI which recently reported by Glauber

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-17 02:37:37 +09:00
Asias He
6ac54a27dc streaming: Skip non-exist cf for stream_transfer_task
Skip sending the mutation if the cf is dropped after we call
make_local_reader in stream_session::add_transfer_ranges().

Fix #550.
2015-11-16 16:48:35 +01:00
Paweł Dziepak
c37afcfdee lsa: account for size of objects too big for LSA
While the objects above max_manage_object_size aren't stored in the
LSA segments they are still considered to be belonging to the LSA
region and are evictable using that region evictor.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-16 12:22:12 +01:00
Avi Kivity
e04a6ea80a Merge "Add the natural_endpoints API" from Amnon
"This series adds the natural_endpoints API. It adds the implementation to the storage_service and to the storage_service API.

After this series the noodtool command getendpoints should work.

example:
$ bin/nodetool getendpoints keyspace1 standard1 0x5032394c323239385030127.0.0.2
127.0.0.2"
2015-11-16 13:16:42 +02:00
Amnon Heiman
c2051c200e API: messaging service add timeout and dropped support
This patch adds the API for timeout messages and dropped messages.

For dropped messages, origin has two APIs one for messages and one for
command.

droped messages return the number of messages per ver, so our API was
rename to reflect that.

For dropped messages (command) we currently do not have this logic of
throwing messages before sending, so the API will always return 0.

The total timeout API was removed and will be done on the jmx proxy
level.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-16 13:15:59 +02:00
Gleb Natapov
79ab5e68f4 enable broadcast_address configuration option
Reviewed-by: Asias He <asias@scylladb.com>
2015-11-16 13:14:07 +02:00
Asias He
358648a8ee init: Check seeds address if listen_address != broadcast_address
If listen_address is different than broadcast_address, we should use
broadcast_address for the seeds list. Check and ask user to fix the
configuration, e.g.,

$ scylla --rpc-address 127.0.0.1 --listen-address 127.0.0.1 --broadcast-address 192.168.1.100 --seed-provider-parameters seeds=127.0.0.1
Use broadcast_address instead of listen_address for seeds list: seeds={127.0.0.1}, listen_address=127.0.0.1, broadcast_address=192.168.1.100
Exiting on unhandled exception of type 'std::runtime_error': Use broadcast_address for seeds list
2015-11-16 13:11:44 +02:00
Asias He
c973d2ea65 to_string: Support std::set and std::unordered_set for to_string 2015-11-16 13:11:43 +02:00
Avi Kivity
9575a7b2ea Merge "Gossiper const correctness" from Pekka
"Fix various const correctness issues in gossiper code found while
working on inter-node protocol."
2015-11-16 13:08:53 +02:00
Asias He
b5cc3ac81c transport: Fix cql server stop
Abort accept and kill existing connections and wait for them.

Fix tests in debug mode:

==29352==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c000012758
at pc 0x00000211e371 bp 0x7ffe27369e10 sp 0x7ffe27369e00
READ of size 8 at 0x60c000012758 thread T0
    #0 0x211e370 in transport::cql_server::do_accepts(int)::{
    lambda(connected_socket, socket_address)#1}::operator()(connected_socket,
    socket_address)::{lambda(future<>)#1}::operator()(future) const
    (/home/asias/.dtest/dtest-AOBJua/test/node2/bin/scylla+0x211e370)
    #1 0x21a8090 in do_void_futurize_apply<transport::cql_server::do_accepts(int)::<
    lambda(connected_socket, socket_address)> mutable::<lambda(future<>)>, future<> >
    /home/asias/src/cloudius-systems/scylla/seastar/core/future.hh:1078
    #2 0x217e861 in apply<transport::cql_server::do_accepts(int)::<
    lambda(connected_socket, socket_address)> mutable::<lambda(future<>)>, future<> >
    /home/asias/src/cloudius-systems/scylla/seastar/core/future.hh:1126
    #3 0x223deb9 in _ZZN6futureIJEE12then_wrappedIZZN9transport10cql_server10do_accepts
    EiENUl16connected_socket14socket_addressE_clES4_S5_EUlS0_E_S0_EET0_OT_ENUlSA_E_
    clI12future_stateIJEEEEDaSA_
    (/home/asias/.dtest/dtest-AOBJua/test/node2/bin/scylla+0x223deb9)
2015-11-16 13:06:20 +02:00
Gleb Natapov
eb220507ce storage_proxy: use correct endpoint address for mutation acks processing
Write handler keeps track of all endpoints that not yet acked mutation
verb. It uses broadcast address as an enpoint id, but if local address
is different from broadcast address for local enpoints acknowledgements
will come from different address, so socket address cannot be used as
an acknowledgement source. Origin solves this by sending "from" in each
message, it looks like an overhead, solve this by providing endpoint's
broadcast address in rpc client_info and use that instead.
2015-11-16 10:29:47 +01:00
Tomasz Grabiec
a6e73d40d7 Move seastar.git HEAD
Gleb Natapov (2):
      rpc: allow non const client_info to be passed to rpc handler
      rpc: allow auxiliary data to be stored in client_info
2015-11-16 10:29:47 +01:00
Pekka Enberg
3c72ea9f96 gms: Fix gossiper::handle_major_state_change() restart logic
The restart logic is wrong because C* had a bug in
bf599fb5b062cbcc652da78b7d699e7a01b949ad and they fixed later and we
translated the broken version. We must check if there is an existing
endpoint state and call on_restart() hooks on that, not the newly
available endpoint state.

Spotted while inspecting the code.

Acked-by: Asias He <asias@scylladb.com>
2015-11-16 11:25:48 +02:00
Tomasz Grabiec
7e0f99cc3b Merge tag 'native-preparatory/v1' from https://github.com/avikivity/scylla.git
Assorted patches that pave the way for native storage (while not
committing us in any way).
2015-11-16 10:01:38 +01:00
Tomasz Grabiec
b6e7312c07 Merge 'memtable-allocating_section/v2' from https://github.com/avikivity/scylla.git
From Avi:

Memtables do not use an allocating_section to guard against allocation
failure, and hence can fail an allocation.  Reproducible by changing
perf_mutation to use an allocating type (bytes_type with a nontrivial
size) and making the loop longer.

Fix by using an allocating_section.
2015-11-16 10:01:05 +01:00
Avi Kivity
a40a62d840 memtable: use allocating_section to guard allocations
Without this, an allocation can fail, and we may not be able to reclaim
memory.
2015-11-16 10:56:06 +02:00
Pekka Enberg
5f48f4aa7c gms/heart_beat_state: Make get_heart_beat_version() const
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-16 08:12:25 +02:00
Pekka Enberg
dc6eaa3a44 gms/gossip_digest: Make some members const
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-16 08:12:16 +02:00
Pekka Enberg
5815bde695 gms/gossip_digest_ack: Make some members const
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-16 08:12:16 +02:00
Avi Kivity
1c425d6b50 logalloc: allow allocating_section code blocks to return references 2015-11-15 19:10:24 +02:00
Tomasz Grabiec
6626d1a100 storage_proxy: Stop latency_counter before throwing 2015-11-15 10:34:55 +02:00
Glauber Costa
0989f80c97 provide cf_stats where one is needed
Recently, I have introduced cf_stats into the database, propagating all the way
back to the column family. The problem, however, is that some tests create a
column family config themselves instead of going through make_column_family.

That is ultimately ok if those tests are not expected to flush memtables. But
if they are, the cf_stats pointer will be null and we will crash. Although
there are many solutions to this, the one that is in tune with our current
practices is to have the test that requires it provide an empty cf_stats storage
area that can be written to. That's already how we handle the disk directory and
other things like compaction properties.

With this patch, test.py passes again.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-15 10:31:32 +02:00
Glauber Costa
fe2b928a3f change defaults for commitlog maximum size
arbitrary 8G -> all_memory.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-15 10:29:23 +02:00
Glauber Costa
00c12319f1 config: change type for commitlog maximum size config option
This patch substitutes uint64_t for uint32_t as the type for
commitlog_total_space_in_mb.  Moving to 64 is not strictly needed, since even a
signed 32-bit type would allow us to easily handle 2TB. But since we store that
in the commitlog as a 64-bit value, let's match it.

Moving from unsigned to signed, however, allow us to represent negative
numbers.  With that in place, we can change the semantics of the value
slightly, so to allow a negative number to mean "all memory".

The reason behind this, is that the default value "8GB", is an artifact of the
JVM.  We don't need that, and in many-shards configuration, each shard flushes
the commitlog way too often, since 8GB / many_shards = small_number.

8GB also happens to be a popular heap size for C* in the JVM. For us, we would
like to equate that (at least) with the amount of memory. The problem is how to
do that without introducing new options or changing the semantics of existing
options too radically.

The proposed solution will allow us to still parse C* yaml files, since those
will always have positive numbers, while introducing our own defaults.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-15 10:29:23 +02:00
Avi Kivity
baf3b2ff4f Merge "Eliminate errors/warnings on building ubuntu package" from Takuya
"Fixes part of #493 (few warnings still remains)"
2015-11-15 10:26:19 +02:00
Takuya ASADA
df9e7d542f dist: ignore bogus 'dist/ubuntu/debian/source/lintian-overrides' on ubuntu package building 2015-11-15 15:03:02 +09:00
Takuya ASADA
d40ce51a01 dist: fix 'init.d-script-missing-dependency-on-remote_fs' message on building ubuntu package 2015-11-15 15:03:02 +09:00
Takuya ASADA
87ed97c387 dist: fix 'init.d-script-not-included-in-package' message on building ubuntu package 2015-11-15 15:03:02 +09:00
Takuya ASADA
100c22cfa5 dist: place 'default' file by debian way 2015-11-15 15:03:02 +09:00
Takuya ASADA
7c4c182268 dist: move redhat/sysconfig to common/sysconfig
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
0c9f837d04 dist: fix 'source-is-missing' message on building ubuntu package 2015-11-15 15:03:02 +09:00
Takuya ASADA
580ca26092 dist: fix 'extended-description-line-too-long' message on building ubuntu package 2015-11-15 15:03:02 +09:00
Takuya ASADA
ee45201b5a dist: make ubuntu package as 'debian non-native package'
Debian package system has two types of package, 'native' and 'non-native'.
'native' is the package just for Debian, it contains debian/ directory source tar.gz, doesn't have debian.tar.gz.
'non-native' has orig.tar.gz which is upstream source code tar ball, then it has debian.tar.gz which contains debian/ directory.
Scylla is 'native' now but should be 'non-native' since this is not just for Debian, so move debian/ to dist/ubuntu/, make orig.tar.gz using git-archive-all, copy dist/ubuntu/debian/ to debian/ then generate debian.tar.gz.
2015-11-15 15:03:02 +09:00
Takuya ASADA
c9c9a86195 dist: fix 'maintainer-script-needs-depends-on-adduser postinst' message on building ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
922f747122 dist: ignore some files under debian/ which are created on building time
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
10a7bd2d4a dist: fix 'wrong-section-according-to-package-name' and 'debug-package-should-be-priority-extra' message on building ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
63e262e507 correct permission of cassandra-rackdc.properties
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
91bd7cf71a dist: fix 'maintainer-script-lacks-debhelper-token' message on building ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
89fe283506 dist: fix 'ancient-standards-version 3.9.2' message on building ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Takuya ASADA
c09226fda8 dist: fix 'missing-license-paragraph-in-dep5-copyright' message on building ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-15 15:03:02 +09:00
Avi Kivity
36994a5d08 managed_bytes: add a constructor from std::initializer_list<>
Not actually used in the patchset now, but nice.
2015-11-13 17:13:07 +02:00
Avi Kivity
f3afe3e876 allocation_strategy: constify migrate_fn
Since abstract_type will be providing our migrate_fn, they must be const,
and indeed a migration does not change the migration function.
2015-11-13 17:13:07 +02:00
Avi Kivity
a4a776e66c cql3: add operation::make_cell() helpers
atomic_cell will soon become type-aware, so add helpers to class operation
that can supply the type, as it is available in operation::column.type.

(the type will be used in following patches)
2015-11-13 17:13:07 +02:00
Avi Kivity
79f7431a03 db: change collection_mutation::{one,view} not to use nested classes
Nested classes cannot be forward-declared, so change the naming
not to use them.  Follows atomic_cell{,_view}.
2015-11-13 17:13:07 +02:00
Avi Kivity
3fcb7add2e types: fix concrete_type::native_type_move()
The source is modified during a move, and so must not be const.
2015-11-13 17:13:07 +02:00
Avi Kivity
68a902ad0c data_value: add constructor from bool
schema_tables manages some boolean columns stored in system tables; it
dynamically creates them from C++ values.  But as we lacked bool->data_value
conversion, the C++ value was converted to a int32_type.  Somehow this didn't
cause any problems, but with some pending patches I have, it does.

Add a bool->data_value converting constructor to fix this.
2015-11-13 17:13:07 +02:00
Avi Kivity
47499dcf18 data_value: make conversion from bytes explicit
Since bytes is a very generic value that is returned from many calls,
it is easy to pass it by mistake to a function expecting a data_value,
and to get a wrong result.  It is impossible for the data_value constructor
to know if the argument is a genuine bytes variable, a data_value of another
type, but serialized, or some other serialized data type.

To prevent misuse, make the data_value(bytes) constructor
(and complementary data_value(optional<bytes>) explicit.
2015-11-13 17:12:29 +02:00
Asias He
2ebd18a248 streaming: Add two more virtual destructors
For stream_event_handler and stream_task.
2015-11-13 09:55:19 +02:00
Asias He
25a03013bf storage_service: Fix cql and thrift server stop in decommission
When do_stop_native_transport exits, cserver is destroyed which can
happen before cserver->stop(). Fix by capturing cserver in
cserver->stop()'s continuation to extend its lifetime. The same for
thrift server.

scylla: scylla/seastar/core/sharded.hh:327: seastar::sharded<Service>::~sharded()
[with Service = transport::cql_server]: Assertion `_instances.empty()' failed.
2015-11-13 09:40:07 +02:00
Tomasz Grabiec
b883ed3abf paging_state: Move instead of copy when possible 2015-11-12 20:19:00 +02:00
Glauber Costa
fa1ae45218 database: export collectd metrics about the state of memtable flushing
When analyzing a recent performance issue, I found helpful to keep track of
the amount of memtables that are currently in flight, as well as how much memory
they are consuming in the system.

Although those are memtable statistics, I am grouping them under the "cf_stats"
structure: being the column family a central piece of the puzzle, it is reasonable
to assume that a lot of metrics about it would be potentially welcome in the future.

Note that we don't want to reuse the "stats" structure in the column family: for once,
the fields not always map precisely (pending flushes, for instance, only tracks explicit
flushes), and also the stats structure is a lot more complex than we need.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-12 20:17:22 +02:00
Amnon Heiman
cda79c9a31 API: add get_natural_endpoints to storage_service
This adds the get_natural_endpoints implementation to the
storage_service API.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-12 14:55:19 +02:00
Amnon Heiman
3efa52c345 storage_service: add get_natural_endpoints implementation
This adds the get_natural_endpoints implementation similiar to origin.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-12 14:53:06 +02:00
Tomasz Grabiec
f3f2bf0b44 schema: Move definitions to source file 2015-11-12 13:50:01 +02:00
Pekka Enberg
551f5585bf gms/gossip_digest_syn: Make get_gossip_digests() const
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-11-12 11:51:28 +02:00
Avi Kivity
6a9ed4a4eb Merge seastar upstream
* seastar 5c10d3e...20bf03b (5):
  > do not re-throw exception to get to an exception pointer
  > Adding timeout counter to the rpc
  > configure.py: support for pkg-config before release 0.28
  > future: don't forget to warn about ignored exception
  > tutorial: continue network API section
2015-11-12 11:19:52 +02:00
Asias He
6aa5bfe59f range_streamer: Add virtual destructor to i_source_filter
Found by debug build

==10190==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x602000084430 in thread T0:
  object passed to delete has wrong type:
  size of the allocated type:   16 bytes;
  size of the deallocated type: 8 bytes.
    #0 0x7fe244add512 in operator delete(void*, unsigned long) (/lib64/libasan.so.2+0x9a512)
    #1 0x3c674fe in std::default_delete<dht::range_streamer::i_source_filter>::operator()(dht::range_streamer::i_source_filter*)
       const /usr/include/c++/5.1.1/bits/unique_ptr.h:76
    #2 0x3c60584 in std::unique_ptr<dht::range_streamer::i_source_filter, std::default_delete<dht::range_streamer::i_source_filter> >::~unique_ptr()
       /usr/include/c++/5.1.1/bits/unique_ptr.h:236
    #3 0x3c7ac22 in void __gnu_cxx::new_allocator<std::unique_ptr<dht::range_streamer::i_source_filter,
       std::default_delete<dht::range_streamer::i_source_filter> > >::destroy<std::unique_ptr<dht::range_streamer::i_source_filter,
       std::default_delete<dht::range_streamer::i_source_filter> > >(std::unique_ptr<dht::range_streamer::i_source_filter,
       std::default_delete<dht::range_streamer::i_source_filter> >*) /usr/include/c++/5.1.1/ext/new_allocator.h:124
...
2015-11-12 11:19:22 +02:00
Avi Kivity
47c7dd96c5 Merge "Aggregate paging support" from Calle
"This adds repeated paged querying to do aggregate queries (similar to
origin). Uses "batched" paging."

Fixes #549
2015-11-11 20:47:14 +02:00
Calle Wilund
fdc549cd47 select_statement: Handle aggregate queries
Fixes #549.

Being clinically absent-minded, aggregate query support (i.e. count(...))
was left out of the "paging" change set.

This adds repeated paged querying to do aggregate queries (similar to
origin). Uses "batched" paging.
2015-11-11 18:41:47 +01:00
Calle Wilund
cc88763961 query_pager: Add method for repeated queries
fetch_page method that instead of returning a full result set, adds row
to a pre-existing one. For "batching".
2015-11-11 18:40:14 +01:00
Amnon Heiman
27737d702b API: Stubing the compaction manager - workaround
Until the compaction manager api would be ready, its failing command
causes problem with nodetool related tests.
Ths patch stub the compaction manager logic so it will not fail.

It will be replaced by an actuall implementation when the equivelent
code in compaction will be ready.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-11 16:58:13 +02:00
Amnon Heiman
66e428799f API: add compaction info object
This patch adds a compaction info object and an API that returns it.
It will be mapped to the JMX getCompactions that returns a map.

The use of an object is more RESTFull and will be better documented in
the swagger definition file.
2015-11-11 16:57:44 +02:00
Amnon Heiman
1b369be663 compaction_strategy should accept both class name and full class name
For compatibility reasons, compaction_strategy should accept both class
name strategy and the full class name that includes the package name.

In origin the result name depends on the configuration, we cannot mimic
that as we are using enum for the type.

So currently the return class name remains the class itself, we can
consider changing it in the future.

If the name is org.apache.cassandra.db.compaction.Name the it will be
compare as Name

The error message was modified to report the name it was given.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>

Fixes #545
2015-11-11 15:31:39 +02:00
Avi Kivity
b95ff5c09e Merge "Commitlog format change: add scylla "magic"" from Calle
"Slight file format change for commitlog segments, now incluing
a scylla "marker". Allows for fast-fail if trying to load an
Origin segment.

WARNING: This changes the file format, and there is no good way for me to
check if a CL is "old" scylla, or Origin (since "version" is the same). So
either "old" scylla files also fail, or we never fail (until later, and
worse). Thus, if upgrading from older to this patch ensure to
have cleaned out all commit logs first."
2015-11-11 11:42:47 +02:00
Avi Kivity
dcc7302312 Merge "Paging support" from Calle
Fixes #355

"Implements query paging similar to origin. If driver sets a "page size" in
a query, and we cannot know that we will not exceed this limit in a single
query, the query is performed using a "pager" object, which, using modified
partition ranges and query limits, keeps track of returned rows to "page"
through the results.

Implementation structure sort of mimics the origin design, even though it
is maybe a little bit overkill for us (currently). On the other hand, it
does not really hurt.

This implementation is tested using the "paging_test" subset in dtest.
It passes all test except:

* test_paging_using_secondary_indexes
* test_paging_using_secondary_indexes_with_static_cols
* test_failure_threshold_deletions

The two first because we don't have secondary indexes yet, the latter
because the test depends on "tombstone_failure_threshold" in origin.

Potential todo: Currently the pager object does not shortcut result
building fully when page limit is exceeded. Could save a little work
here, but probably not very significant."
2015-11-11 10:45:41 +02:00
Avi Kivity
5aecf210e2 Merge "gossip shutdown fix + streaming fix" from Asias
Fixes: #540 #542
2015-11-11 10:27:43 +02:00
Asias He
efda753c0c token_metadata: Implement pending_endpoints_for
It is used in storage_proxy::create_write_response_handler. The second
argument should be keyspace name instead of the keyspace class.

Refs: #539
2015-11-11 09:41:21 +02:00
Calle Wilund
43712a583d commitlog_replayer: Special case exception from "old/origin file"
And write some nice informative stuff.
2015-11-10 17:14:22 +01:00
Calle Wilund
85b8d65374 commitlog: Change file format to include magic marker
Allows us fail fast if someone tries to replay an Origin commit log.

WARNING: This changes the file format, and there is no good way for me to
check if a CL is "old" scylla, or Origin (since "version" is the same). So
either "old" scylla files also fail, or we never fail (until later, and
worse). Thus, if upgrading from older to this patch, likewise, ensure to
have cleaned out all commit logs first.
2015-11-10 17:11:06 +01:00
Glauber Costa
72573d0b46 storage proxy: be more vocal about timeouts
If a timeout happens, we should log it. Trace level is really
not adequate for this.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-10 16:41:22 +02:00
Calle Wilund
ecd7674867 select_statement: Paging
Check if paging might be needed, and if so, use a paging object.
Similar to origin, but without all the filters.
2015-11-10 13:16:06 +01:00
Calle Wilund
13189c3176 query_pagers: Paging implementation
* Static query method to determine if paging might be required
(very conservative - almost all querys will be paged me thinks).
* Static factory method for pager
* Actual pager implementation

Pager object uses three variables to keep track of paging state:
1.) Last partition key - partition key of last partion processed 
	-> next partition to start process
2.) Last clustering key, i.e. row offset within last key partition, 
	i.e. how far we got last time
3.) Max remaining - max rows to process further, i.e. initial limit - 
    processed so far
    
Partition ranges are modified/removed so that we begin with "Last key", 
if present. (Or end with, in the case of reversed processing)

A counting visitor then keeps count of rows to include in processing.
2015-11-10 13:16:05 +01:00
Calle Wilund
bef3604f5a query_pager: Pure virtual interface
Basic interface for paging control objects.

We probably do not need virtual behaviour for paging, but on the other
hand it does not really cost much, and it keeps a nice symmetry with
origin.
2015-11-10 13:12:34 +01:00
Calle Wilund
284b10cabe Make partition_slice::row_ranges mulitplex on partition
Allows for having more than one clustering row range set, depending on
PK queried (although right now limited to one - which happens to be exactly
the number of mutiplexing paging needs... What a coincidence...)

Encapsulates the row_ranges member in a query function, and if needed holds
ranges outside the default one in an extra object.

Query result::builder::add_partition now fetches the correct row range for
the partition, and this is the range used in subsequent iteration.
2015-11-10 13:12:33 +01:00
Calle Wilund
d8cafa8dec cql_server::connection::read_options: Deserialize paging state 2015-11-10 13:12:33 +01:00
Calle Wilund
545d3151e2 paging_state implementation
Note: serial format blob is different compared to origin, due to scyllas
different internal architecture. I.e. we query actual rows.
But drivers etc ignore the content of the blob, it is opaque.
2015-11-10 13:12:33 +01:00
Calle Wilund
7e2569c680 result_set: Make "paging_state" a pointer to const member
Paging state is immutable. Constness is nice.
2015-11-10 13:12:33 +01:00
Calle Wilund
4a1a17defc cql3::selection: Move result set building visitor to result_set_builder
Allows its use (and partial override - hint hint) in more place than
one.
2015-11-10 13:12:33 +01:00
Calle Wilund
820ba3540b result_view: Add static helper method to do the dispatch from select
Again, makes it easier to use the same optimization/technique at more than
one location.
2015-11-10 13:12:33 +01:00
Calle Wilund
23b6240dad cql3::selection: Fix some constness correctness 2015-11-10 13:12:33 +01:00
Calle Wilund
369e09459c cql3::result_set: Add non-const metadata getter. 2015-11-10 13:12:33 +01:00
Calle Wilund
0fa543800a data_output: Template "blob" writers (bytes*) to allow for varying "size" type 2015-11-10 13:12:33 +01:00
Calle Wilund
9ee8204993 data_input: Fix missing bounds check 2015-11-10 13:12:33 +01:00
Asias He
19a6dfcfd0 streaming: stream_session print stream_session_state properly 2015-11-10 15:39:34 +08:00
Asias He
7506d57dec streaming: Add operator<< for stream_session_state 2015-11-10 15:39:34 +08:00
Asias He
860c7aff37 streaming: Print plan_id in logger 2015-11-10 15:39:34 +08:00
Asias He
d2e5d13e69 streaming: Set state to STREAMING only if we really have data to sent 2015-11-10 15:39:34 +08:00
Asias He
fcf7486d4c streaming: Improve state transition log for maybe_completed and complete 2015-11-10 15:39:34 +08:00
Asias He
72a7a6bd9b streaming: session close
Currently, there are multiple places we can close a session, this makes
the close code path hard to follow. Remove the call to maybe_completed
in follower_start_sent to simplify closing a bit.

- stream_session::follower_start_sent -> maybe_completed()
- stream_session::receive_task_completed -> maybe_completed()
- stream_session::transfer_task_completed -> maybe_completed()
- on receive of the COMPLETE_MESSAGE -> complete()
2015-11-10 15:39:34 +08:00
Asias He
cadf8b1484 streaming: Handle stream_plan with no range added
If no ranges for neither sending nor receiving are added for the stream
plan, the stream plan is empty. Return a ready future immediately.
2015-11-10 15:39:34 +08:00
Asias He
13934140f6 streaming: Remove bogus file size info for prepare completed
Scylla does not streaming sstable files directly for streaming. The file
size info is incorrect, let's get rid of it.
2015-11-10 15:39:34 +08:00
Asias He
ac1977486d gossip: Fix shutdown
nodetool decommission node 127.0.0.2, on node 127.0.0.1, I saw:

DEBUG [shard 0] gossip - failure_detector: Forcing conviction of 127.0.0.1
TRACE [shard 0] gossip - convict ep=127.0.0.1, phi=8, is_alive=1, is_dead_state=0
TRACE [shard 0] gossip - marking as down 127.0.0.1
INFO [shard 0] gossip - inet_address 127.0.0.1 is now DOWN
DEBUG [shard 0] storage_service - on_dead endpoint=127.0.0.1

This is wrong since the argument for send_gossip_shutdown should be the
node being shutdown instead of the live node.
2015-11-10 15:39:34 +08:00
Avi Kivity
fee9688ae8 Merge "Fixes for collections of collections" from Paweł
"These are some fixes for removing items from collections of frozen
collections."
2015-11-10 09:38:13 +02:00
Paweł Dziepak
e494b2c1a0 tests/cql: add tests for collections of collections
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-09 16:37:50 +01:00
Paweł Dziepak
ee182f39a5 cql3/sets: simplify sets::discarder
Since the introduction of sets::element_discarder sets::discarder is
always given a set, never a single value.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-09 15:24:25 +01:00
Paweł Dziepak
0b0cef2457 cql3/maps: do not assume that the term type is constants::value
Fixes #516.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-09 15:18:07 +01:00
Paweł Dziepak
101ee1affd cql3/sets: add element_discarder
Currently sets::discarder is used by both set difference and removal of
a single element operations. To distinguish between them the discarder
checks whether the provided value is a set or something else, this won't
work however if a set of frozen sets is created.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-09 14:47:09 +01:00
Tomasz Grabiec
488528d1cd range: Fix range::subtract() for some cases
Was not handling wrap-around cases like this properly:

 (8, 3) - (2, 1)
2015-11-09 14:20:31 +02:00
Glauber Costa
8e0ad183b9 dist: AMI: add discard mount option
Crucial on SSDs, inocuous (hopefully) on HDDs. Let's add it to make peace
with our inner selves.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-09 13:31:01 +02:00
Asias He
d622fe867e gossip: Pass const ref if possible
It is clear that we will not change the parameter.
2015-11-09 13:01:37 +02:00
Asias He
615e1362da gossip: Add const version for get_heart_beat_state and friends
get_endpoint_state_map
get_application_state_map
2015-11-09 13:01:36 +02:00
Gleb Natapov
d77a2a0f03 do not try to write same memtable to sstable twice if moving it to a cache failed.
Error handling in column_family::try_flush_memtable_to_sstable() is
misplaced. It happens after update_cache(), so writing sstable may
have succeeded, but moving memtable into the cache may have failed.
update_cache() destroys memtable even if it fails, but error handler
is not aware of it (it does not even distinguish whether error happened
during sstable creation or moving into cache) and when it tells caller
to retry it retries with already destroyed memtable. Fix it by ignoring
moving to cache errors.
2015-11-09 11:27:37 +01:00
Avi Kivity
cb93af2ad7 Revert "do not try to write same memtable to sstable twice if moving it to a cache failed."
This reverts commit fff37d15cd.

Says Tomek (and the comment in the code):

"update_cache() must be called before unlinking the memtable because cache + memtable at any time is supposed to be authoritative source of data for contained partitions. If there is a cache hit in cache, sstables won't be checked. If we unlink the memtable before cache is updated, it's possible that a query will miss data which was in that unlinked memtable, if it hits in the cache (with an old value)."
2015-11-09 11:22:12 +02:00
Avi Kivity
975a3eb49f Merge "move node support + decommission fix" from Asias
"Usage example:

$ nodetool -p 7200 move -- "-9223372036854775000"

or

$ curl -X POST --header "Content-Type: application/json" --header "Accept: application/json"
  "http://127.0.0.2:10000/storage_service/move?new_token=8000000"

Note: Tomek's range subtract and cql_test_env fix for system_keyspace seriers are included."
2015-11-09 11:08:51 +02:00
Tzach Livyatan
0e9b3e4d37 add build and run from source instructions in README.md
fix #451

Signed-off-by: Tzach Livyatan <tzach@cloudius-systems.com>
2015-11-09 10:05:05 +02:00
Gleb Natapov
fff37d15cd do not try to write same memtable to sstable twice if moving it to a cache failed.
Error handling in column_family::try_flush_memtable_to_sstable() is
misplaced. It happens after update_cache(), so writing sstable may
have succeeded, but moving memtable into the cache may have failed.
update_cache() destroys memtable even if it fails, but error handler
is not aware of it (it does not even distinguish whether error happened
during sstable creation or moving into cache) and when it tells caller
to retry it retries with already destroyed memtable. Fix it by ignoring
moving to cache errors.
2015-11-09 09:56:45 +02:00
Asias He
85b42e362b storage_service: Fix hang of decommission
nodetool decommission hangs forever due to a recursive lock.

decommission()
  with api lock
  shutdown_client_servers()
     with api lock
       stop_rpc_server()
     with api lock
       stop_native_transport()

Fix it by calling helpers for stop_rpc_server and stop_native_transport
without the lock.
2015-11-09 08:43:04 +08:00
Asias He
cb8b0eedfc token_metadata: Fix set_difference in calculate_pending_ranges
std::set_difference requires the container to be sorted.
2015-11-09 08:43:04 +08:00
Asias He
87292d6a16 range_streamer: Simplify unordered_multimap_to_unordered_map
operator[] is own friend, it creates map[x] if x is not in the map.
2015-11-09 08:43:04 +08:00
Asias He
a54989cd65 range_streamer: Fix get_all_ranges_with_strict_sources_for
std::set_difference requires the container to be sorted which is not
true here, use remove_if.

Do not use assert, use throw instead so that we can recover from this
error.
2015-11-09 08:43:04 +08:00
Asias He
145c122cb7 storage_service: Enable commented out in on_restart
on_dead is now available.
2015-11-09 08:43:04 +08:00
Asias He
1ab1a1d8d9 storage_service: Fix bogus log in on_dead 2015-11-09 08:43:04 +08:00
Asias He
9f69b4c969 storage_service: Enable add_moving_endpoint in handle_state_moving 2015-11-09 08:43:04 +08:00
Asias He
c90e9c97f5 token_metadata: Add add_moving_endpoint 2015-11-09 08:43:04 +08:00
Asias He
0fc6e76d1e storage_service: Make fd a reference in remove_node 2015-11-09 08:43:04 +08:00
Asias He
2d55e5e8ff api: Implement storage_service::move
Start node 1 and node 2:

node 1:
$ scylla --initial-token 0

node 2:
$ scylla --initial-token 2000000

To move node 2 to a new token 8000000

$ curl -X POST --header "Content-Type: application/json" --header "Accept: application/json"
"http://127.0.0.2:10000/storage_service/move?new_token=8000000"
2015-11-09 08:43:04 +08:00
Asias He
d124df17b4 storage_service: Use get_local_tokens in set_tokens
We are using _bootstrap_tokens since get_local_tokens was not available.
2015-11-09 08:43:04 +08:00
Asias He
e637faefbe storage_service: Implement move
Moves the node on the token ring to a new token.

$ nodetool move <new token>
2015-11-09 08:43:04 +08:00
Asias He
b12d95d955 storage_service: Implement calculate_to_from_streams 2015-11-09 08:43:04 +08:00
Asias He
d166b0f3fa range_streamer: Add get_work_map 2015-11-09 08:43:04 +08:00
Asias He
ada2466e18 token_metadata: Add clone_after_all_settled
Needed by storage_service::range_relocator::calculate_to_from_streams.
2015-11-09 08:43:04 +08:00
Asias He
47cf4dfbc5 storage_service: Implement range_relocator class 2015-11-09 08:43:04 +08:00
Asias He
53d30ed985 storage_service: Implement calculate_stream_and_fetch_ranges
This is needed by calculate_to_from_streams.
2015-11-09 08:42:56 +08:00
Tomasz Grabiec
3c4c83c66f cql_test_env: Initialize system keyspace 2015-11-09 08:42:53 +08:00
Tomasz Grabiec
1c9d8571a8 cql_test_env: Flatten stop() 2015-11-09 08:42:51 +08:00
Tomasz Grabiec
1c1a4c9656 tests: Add test for range::subtract() 2015-11-09 08:42:47 +08:00
Tomasz Grabiec
0f2727b183 range: Implement subtract() 2015-11-09 08:42:45 +08:00
Tomasz Grabiec
48c7f51966 range: Extract bound comparators 2015-11-09 08:42:42 +08:00
Tomasz Grabiec
f37512d1f7 range: Make unwrap() return ranges in-order 2015-11-09 08:42:39 +08:00
Gleb Natapov
9abd724b30 storage_proxy: fix mutation verb error reporting
Currently error code is attached to a future returned by when_all() which
is never is exceptional one, but it may hold exceptional future as a
first element. Move error handling close to where error it tries to
catch is generated instead.
2015-11-08 16:35:41 +02:00
Raphael S. Carvalho
4eb94fbc35 sstables: improve exception handling in compact_sstables
Let's move the code that prints that a compaction succeeded only
after the code that catches exception on either read or write
fibers. Let's also get rid of done and use repeat instead in
the read fiber.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-08 11:24:55 +02:00
Takuya ASADA
368ee17d53 dist: prevent error building ubuntu package on EC2
fixes #491

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-06 22:06:55 +02:00
Gleb Natapov
120ae08082 storage_proxy: fix race during write completion
If write timeout and last acknowledgement needed for CL happen simultaneously
_ready can be sent to be exceptional by the timeout handler, but since
removal of the response handler happens in continuation it may be
reordered with last ack processing and there _ready will be set again
which will trigger assert. Fix it by removing the handler immediately,
no need to wait for continuation. It makes code simpler too.
2015-11-05 19:35:18 +02:00
Paweł Dziepak
64f1c2866c lsa: free segment in trim_emergency_reserve_to_max()
_emergency_reserve is an intrusive containers and it doesn't care about
segment lifetime.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-05 18:04:38 +02:00
Amnon Heiman
5f1cae67ff API: compaction_manager should catch the field reference by value
The get_cm_stats gets a pointer to a field in the stats object. It
should capture it by value or segmentation falut may occure when the
caller gets out of scope.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-05 14:17:12 +02:00
Avi Kivity
c9f02ce42f Merge seastar upstream
* seastar 05b41b8...5c10d3e (3):
  > reactor: more conservative signal handling
  > output_stream: add write(temporary_buffer) variant
  > input_stream: add read() method
2015-11-05 13:20:26 +02:00
Takuya ASADA
b50a6a1521 dist: add missing dist/ubuntu/changelog.in
Missing file for d2dd6b90a9

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-05 11:09:32 +02:00
Glauber Costa
958abc17a0 sstables: be more descriptive with filename parsing errors
Currently, we don't let the user know even what is the filename that failed.
That information should be included in the message.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-11-05 10:45:59 +02:00
Raphael S. Carvalho
279a8f13ee sstables: compaction: handle failure on read fiber
This assert (in write fiber) would fail if read fiber failed
because the variable done will not be set to true.
The use of assert is very bad, because it prevents scylla
from proceeding, which is possible.
To solve it, let's trigger an exception if done is not true.
We do have code that will wait for both read and write fibers,
and catch exceptions, if any.

Closes #523.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-11-04 16:48:01 +01:00
Tomasz Grabiec
598f4104fd query_processor: Use the correct client_state
Since 4641dfff24, query_state keeps a
copy of client_state, not a reference. Therefore _cl is no longer
updated by queries using _qp. Fix by using the client_state from _qp.

Fixes #525.
2015-11-04 12:43:26 +02:00
Takuya ASADA
ec06fd77a8 dist: split debug symbol to sepalate package on ubuntu
Fixes #524

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-04 12:35:35 +02:00
Asias He
0304567c09 storage_service: Implement get_new_source_ranges
It is needed by restore_replica_count.
2015-11-04 12:21:00 +02:00
Takuya ASADA
d2dd6b90a9 dist: support ./SCYLLA-VERSION-GEN on ubuntu package
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-04 11:50:38 +02:00
Avi Kivity
a41ffb3f4b Merge "support initial_token config option" from Asias
"This is needed by some tests to specify specific tokens."
2015-11-04 11:42:39 +02:00
Paweł Dziepak
a553c9236e transport: do not send response with unknown protocol version
All responses sent from the server have protocol version set to
connection::_version which is set to the version used by the client
in its first message. However, if the protocol version used by the
client is unuspported or invalide the server should use the latest
version it recognizes.

This solves problem with version negotiation with Java driver. The
driver first sends a request in the latest version it recognizes, if
that fails it retries with the version that server has used in the error
message. If that fails as well it gives up. However, since Scylla always
responds with the same version that the client has used the negotiation
always fails if the client supports more protocol version than the
server.

Refs #317.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-11-04 08:59:23 +02:00
Asias He
ed313160c2 storage_service: Add initial_token config option support 2015-11-04 10:42:17 +08:00
Asias He
20ecb0bede database: Introduce get_initial_tokens
Get initial tokens specified by the initial_token in scylla.conf.

E.g.,

   --initial-token "-1112521204969569328,1117992399013959838"
   --initial-token "1117992399013959838"

It can be multiple tokens split by comma.
2015-11-04 10:40:12 +08:00
Asias He
16596385ee token: Handle minimum token correctly in long_token
Fixes:

Exiting on unhandled exception of type 'runtime_exception': runtime
error: Invalid token. Should have size 8, has size 0
2015-11-04 09:01:06 +08:00
Avi Kivity
a060610347 Merge seastar upstream
* seastar 258daf9...05b41b8 (5):
  > resource: fix system memory reservation
  > Add .gitattributes to improve 'git diff' output
  > README: remove irrelevant OSv instructions
  > Add invocation of ninja in Ubuntu section of README
  > collectd: remove incorrect license
2015-11-04 00:18:06 +02:00
Avi Kivity
012f13eb53 Merge "Adding describering API" from Amnon
"This series adds the missing functionality that the nodetool describering would work.

It import the missing functionality from origin.
After this patch the API:
GET /storage_service/describe_ring/{keyspace}

will be available"
2015-11-03 16:54:13 +02:00
Amnon Heiman
ef3c6b2647 API: Add describe ring API implementation
This patch chanages the API to support describe ring instead of describe
ring jmx that will be implemented in the jmx server.

The API will return a list of objects instead of string.

An additional api was added as the equivelent to the jmx call with an
empty param.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-03 16:33:39 +02:00
Amnon Heiman
3809565dbd storage_service: Add method implementation from origin
This patch adds the following methods implementation:
getRpcaddress
getRangeToAddressMap
getRangeToAddressMapInLocalDC
describeRing
getAllRanges

Those methods are used as part of the describe_ring method
implementation.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-03 16:33:20 +02:00
Gleb Natapov
28bb6a3efe messaging_service: fix hanging reference access
Do not pass reference to an on-stack objects to a function that uses
its parameters asynchronously.
2015-11-03 12:10:38 +01:00
Tomasz Grabiec
7a2ac628a0 Fix compilation of types_test 2015-11-03 11:02:35 +01:00
Avi Kivity
74faaa4698 types: implement date_type::from_string()
Luckily all the hard work was already done for timestamp_type.

Fixes #522.
2015-11-03 10:33:20 +01:00
Amnon Heiman
b77ec2bd6a Importing token_range and endpoint_details from origin
The storage server uses the token_range in origin to return inforamtion
about the ring.

This import the structures. The functionality in origin is redundant in
this case and was not imported.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-03 10:17:05 +02:00
Asias He
dafdac6731 ami: Improve scylla raid setup
Use all the disks except the one for rootfs for RAID0 which stores
scylla data. If only one disk is available warn the user since currently
our AMI's rootfs is not XFS.

[fedora@ip-172-31-39-189 ~]$ cat WARN.TXT
WARN: Scylla is not using XFS to store data. Performance will suffer.

Tested on AWS with 1 disk, 2 disks, 7 disk case.

(cherry picked from commit 49d6cba471)
2015-11-03 08:16:09 +08:00
Avi Kivity
389e035d19 Update scylla-ami submodule
* dist/ami/files/scylla-ami c6ddbea...3f37184 (1):
  > Update reflector URL

(cherry picked from commit 440b403089)
2015-11-03 08:12:51 +08:00
Takuya ASADA
a0feaf801c dist: add scylla.repo to fetch scylla rpms on ami
Mistakenly didn't included on yum repository for AMI patchset, but it's needed

Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
(cherry picked from commit 8587c4d6b3)
2015-11-03 08:01:09 +08:00
Takuya ASADA
a5a69279ef dist: update packages on ec2 instance first bootup
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
(cherry picked from commit aaeccdee60)
2015-11-03 07:50:43 +08:00
Takuya ASADA
db634dfe01 dist: use scylla repo on ami, instead of locally built rpms
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
(cherry picked from commit 8b98fe5a1c)
2015-11-03 07:50:33 +08:00
Takuya ASADA
63d16f5816 dist: move inline script to setup-ami.sh
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
(cherry picked from commit 2863b8098f)
2015-11-03 07:50:12 +08:00
Amnon Heiman
e562736e82 API: A workaround for nodetool cleanup
The nodetool cleanup command is used in many of the tests, because the
API call is not implemented it causes the tests to fail.

This is a workaround until the cleanup will be implemented, the method
return successfuly.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 17:38:48 +02:00
Amnon Heiman
80e5289359 Adding API as an unimplemented cause
Normally an API call that is not implemented should fail, there are
cases that as a workaround an API call is stub, in those cases a warning
is added to indicate that the API is not implemented.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 17:38:48 +02:00
Avi Kivity
c9b8c368bd Merge "Adding missing statistics to enable nodetool netstats" from Amnon
"The series adds read repair and storage_service server statistics."
2015-11-02 17:10:43 +02:00
Amnon Heiman
fc7ea6207c API: messaging service, Add getter for the pending and completed server
This patch adds getter for the messeging service server pending and sent
messages.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 16:17:47 +02:00
Amnon Heiman
55d7ddafe5 API: Add repond complete to the messaging service swagger
This patch do the following:
It adds a getter for the completed respond messages (i.e. the total
messages that were sent by the server)

It replaces the return mapping for the statistics to use the key, value
notation that is used in the jmx side.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 16:17:36 +02:00
Amnon Heiman
afb921a643 API: add read repair stats to the storage_proxy
This adds the API to the storage_proxy read repair stats that replaces
the stub implementation.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 16:17:22 +02:00
Amnon Heiman
b6034572dc storage_proxy: Add read repair statistics
This adds the read repair statistics to he storage_proxy stats and adds
to its implementation incrementing the counters value.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 16:16:40 +02:00
Amnon Heiman
d5d0653210 messaging_service: Add a function that goes over all the server stats
The API needs to get the stats from the rpc server, that is hidden from the
messaging service API.

This patch adds a foreach function that goes over all the server stats
without exposing the server implementation.

Signed-off-by: Amnon Heiman <amnon@scylladb.com>
2015-11-02 16:15:52 +02:00
Avi Kivity
9c09f43311 Merge "add [background] read/write statistics" from Gleb
"The main objective of the series is to introduce statistics about ongoing
read/writes and especially those that are done in the background (acknowledged,
but uncompleted), but it contains some cleanups as well."
2015-11-02 15:46:07 +02:00
Avi Kivity
e2b661bb78 sstables: fix compile error 2015-11-02 15:32:44 +02:00
Gleb Natapov
9af55b3a7b storage_proxy: add ongoing read statistics
Add statistics for ongoing reads and ongoing background reads. Read is
a background one if it was acknowledged, but there still work to do to
complete it.
2015-11-02 15:02:13 +02:00
Gleb Natapov
463d330a24 storage_proxy: do not capture 'this' needlessly. 2015-11-02 15:01:16 +02:00
Gleb Natapov
5067d027ba storage_proxy: export statistics via collectd 2015-11-02 15:01:16 +02:00
Gleb Natapov
287cf894a0 storage_proxy: count background mutation writes
Count how many writes are running in the background. Write is a
background write if it was acknowledged, but there still work to do to
complete it.
2015-11-02 15:01:12 +02:00
Gleb Natapov
afa61cb87c storage_proxy: separate methods from members with access specifier 2015-11-02 15:00:47 +02:00
Gleb Natapov
62e5ad27d8 storage_proxy: devirtualize total_block_for()
total_block_for() is defined only in base class, so make it non virtual.
2015-11-02 15:00:47 +02:00
Gleb Natapov
59d8f9f392 storage_proxy: move proxy pointer to write response handler
We will need it later there.
2015-11-02 15:00:47 +02:00
Gleb Natapov
ca0177f5cc storage_proxy: simplify timeout handling
Use _cl_achieved instead of calculating if there is enough acks.
2015-11-02 15:00:47 +02:00
Gleb Natapov
4838de008f storage_proxy: get rid of semaphore in mutation write response handler
Acks are counted in _cl_acks, so there is no need to count them once
more in semaphore, just make promise available when there is enough of
them.
2015-11-02 15:00:47 +02:00
Gleb Natapov
9381ad0741 storage_proxy: initialize _stats 2015-11-02 15:00:47 +02:00
Avi Kivity
b1d13636bb Merge "locator: use the correct snitch instance in gossiping_property_file_snitch::reload_configuration()" from Vlad
"Commit 4cd9c4c0c5441cf55e280c6f2f2e5529426b9c98 introduced a minor
issue: a wrong snitch instance may be used when updating a Gossiper state
(if I/O CPU is different from CPU0).

In order to fix this issue a local snitch instance on CPU0 should be used,
just like a Gossiper local instance.

We have to move some interfaces to i_endpoint_snitch
from being private in a gossiping_property_file_snitch in order to be
able to access it using snitch_ptr handle."
2015-11-02 14:09:27 +02:00
Vlad Zolotarov
b654d942b4 locator::gossiping_property_file_snitch: don't ignore a returned future
Don't ignore yet another returned future in reload_configuration().

Since commit 5e8037b50a
storage_service::gossip_snitch_info() returns a future.

This patch takes this into an account.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-11-02 13:44:53 +02:00
Vlad Zolotarov
689d5fb000 locator::gossiping_property_file_snitch: fix in reload_configuration()
When we access a gossiper instance we use a _gossip_started
state of a snitch, which is set in a gossiper_starting() method.

gossiper_starting() method however is invoked by a gossiper on CPU0
only therefore the _gossip_started snitch state will be set for an
instance on CPU0 only.

Therefore instead of synchronizing the _gossip_started state between
all shards we just have to make sure we check it on the right CPU,
which is CPU0.

This patch fixes this issue.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-11-02 13:44:53 +02:00
Vlad Zolotarov
5da4e62a59 locator::i_endpoint_snitch: align the _prefer_local parameter with _my_dc and _my_rack
Adjust the interface and distribution of prefer_local parameter read
from a snitch property file with the rest of similar parameters (e.g. dc and rack):
they are read and their values are distributed (copied) across all shards'
instances.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-11-02 13:44:53 +02:00
Vlad Zolotarov
5042f3c952 locator::i_endpoint_snitch_base: make reload_gossiper_state() a virtual function
Make reload_gossiper_state() be a virtual method
of a base class in order to allow calling it using a snitch_ptr
handle.

A base class already has a ton of virtual methods so no harm is
done performance-wise. Using virtual methods instead of doing
dynamic_cast results in a much cleaner code however.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-11-02 13:44:53 +02:00
Vlad Zolotarov
926ce145db locator::i_endpoint_snitch_base: move _gossip_started to the base class
Move the member and add an access method.
This is needed in order to be able to access this state using
snitch_ptr handle.

This also allows to get rid of ec2_multi_region_snitch::_helper_added
member since it duplicates _gossip_started semantics.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-11-02 13:44:31 +02:00
Takuya ASADA
919d94a52b dist: update Ubuntu's g++ to 5.x
Now ubuntu-toolchain-r repo has g++-5 package for 14.04, so switch to it

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-11-02 13:31:19 +02:00
Avi Kivity
4e3d281402 Merge 2015-11-02 13:31:02 +02:00
Avi Kivity
d436617adc Merge seastar upstream
* seastar 9ae6407...258daf9 (6):
  > rpc server: Add pending and sent messages to server
  > scripts: posix_net_conf.sh: Use a generic logic for RPS configuring
  > scripts: posix_net_conf.sh: allow passing a NIC name as a parameter
  > doc: link to the tutorial
  > tutorial: begin documenting the network API
  > slab: remove bogus uintptr_t definition
2015-11-02 13:30:26 +02:00
Avi Kivity
c6968b2940 Make abstract_type::serialize(data_value) a member of data_value
Reduces duplication.  Fixes #517.
2015-11-02 12:25:35 +01:00
Asias He
66a576c0c0 tests: Add documents to tests/gossip.cc
- How to run the test
- What to expect
2015-11-02 11:29:43 +02:00
Avi Kivity
4b1fffe54c Merge "storage_service: serialize more management operations" from Asias
- Add run_with_no_api_lock
- Do not hold the api lock while do the streaming for rebuild
- Include "config: Enable storage_port option" in this series
2015-11-02 10:55:57 +02:00
Avi Kivity
107877f33a Merge "Futurize all callers of add_local_application_state" from Asias
"In 5e8037b50a (gossip: Futurize
add_local_application_state()) , we futurized add_local_application_state.
However, not all of the callers are futurized. Fix it up."
2015-11-02 10:22:01 +02:00
Asias He
f9ff98f4c4 tests: Fix ignored future for add_local_application_state 2015-11-02 09:34:17 +08:00
Asias He
6748bc686f load_broadcaster: Fix ignored future in start_broadcasting 2015-11-02 09:22:05 +08:00
Asias He
a8724a046e migration_manager: Fix ignored future in passive_announce
add_local_application_state returns future. Do not ignore it.
2015-11-02 09:21:55 +08:00
Asias He
e3c5a31e85 gossip: Futurize gossiper_starting
gossiper_starting calls gossiper::add_local_application_state which
returns a future, so futurize gossiper_starting as well.
2015-11-02 09:10:48 +08:00
Avi Kivity
6470cfc63e Merge "Updates for EC2Snitchs"
"- Fix snitch names from EC2XXX to Ec2XXX to align with configuration.
- Copy cassandra-rackdc.properties file to /var/lib/scylla/conf
- Set SCYLLA_HOME before booting process"
2015-11-01 18:52:23 +02:00
Shlomi Livne
67899b7b51 dist: set SCYLLA_HOME used to find the configuration and property files
Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-11-01 17:31:47 +02:00
Shlomi Livne
f0cd241478 dist: fedora/rhel/centos copy cassandra-rackdc.properties
Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-11-01 15:21:54 +02:00
Shlomi Livne
b35f56cf8d dist: ubuntu copy cassandra-rackdc.properties
Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-11-01 15:21:34 +02:00
Shlomi Livne
50cdcbd255 Update snitch registration EC2MultiRegionSnitch --> Ec2MultiRegionSnitch
Update snitch EC2MultiRegionSnitch to Ec2MultiRegionSnitch,
org.apache.cassandra.locator.EC2MultiRegionSnitch to
org.apache.cassandra.locator.Ec2MultiRegionSnitch

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-11-01 15:21:26 +02:00
Shlomi Livne
72b27a91fe Update snitch registration EC2Snitch --> Ec2Snitch
Update EC2Snitch to Ec2Snitch, org.apache.cassandra.locator.EC2Snitch to
org.apache.cassandra.locator.Ec2Snitch

Signed-off-by: Shlomi Livne <shlomi@scylladb.com>
2015-11-01 15:20:28 +02:00
Lucas Meneghel Rodrigues
6a2f5409c9 test.py: Use shlex to split the patch
Let's use shlex to do the path splitting instead of the
simple .split() call.

Signed-off-by: Lucas Meneghel Rodrigues <lmr@scylladb.com>
2015-11-01 14:33:32 +02:00
Avi Kivity
212fcdc159 Remove kvm/ subdirectory
It's a seastar thing, not a Scylla thing.
2015-11-01 12:48:32 +02:00
Lucas Meneghel Rodrigues
c1dde5dc4d service/storage_service.cc: Fix control reaches end of non-void function error
During testing build, the debugging statement at the end
of the function body (after return statements) causes compilation to
fail due to the flag -Werror=return-type:

service/storage_service.cc: In member function ‘future<> service::storage_service::clear_snapshot(sstring, std::vector<basic_sstring<char, unsigned int, 15u> >)’:
service/storage_service.cc:1358:1: error: control reaches end of non-void function [-Werror=return-type]

Which traces back to 21f84d77. Let's attach a then_wrapped()
clause to parallel_for_each() adding the debug message as
suggested by Avi.

CC: Glauber Costa <glommer@scylladb.com>
Signed-off-by: Lucas Meneghel Rodrigues <lmr@scylladb.com>
2015-11-01 11:59:44 +02:00
Asias He
5e8037b50a gossip: Futurize add_local_application_state()
We are ignoring the future returned by seastar::async. Futurize it so
caller can wait for the application state to be actually applied.

In addition, dropping the unused add_local_application_states function.
2015-11-01 11:20:52 +02:00
Avi Kivity
2c3591cbd9 data_value de-any-fication
We use boost::any to convert to and from database values (stored in
serlialized form) and native C++ values.  boost::any captures information
about the data type (how to copy/move/delete etc.) and stores it inside
the boost::any instance.  We later retrieve the real value using
boost::any_cast.

However, data_value (which has a boost::any member) already has type
information as a data_type instance.  By teaching data_type intances about
the corresponding native type, we can elimiante the use of boost::any.

While boost::any is evil and eliminating it improves efficiency somewhat,
the real goal is growing native type support in data_type.  We will use that
later to store native types in the cache, enabling O(log n) access to
collections, O(1) access to tuples, and more efficient large blob support.
2015-10-30 17:38:51 +01:00
Pekka Enberg
b478d9d8a6 Merge "Wire reconnectable_snitch_helper to gossiping_property_file_snitch" from Vlad
"gossiping_property_file_snitch checks its property
file (cassandra-rackdc.properties) for changes every minute and
if there were changes it re-registers the helper and initiates
re-read of the new DC and Rack values in the corresponding places.

Therefore we need the ability to unregister/register the corresponding subscriber
at the same time when a subscriber list is possibly iterated by
some other asynchronous context on the current CPU.

The current gossiper implementation assumes that subscribers list may not be
changed from the context different from the one that iterates on their list.

So, this had to be fixed.

There was also missing an update_endpoint(ep) interface in the locator::topology
class and the corresponding token_metadata::update_topology(ep) wrapper.

Also there were some bugs in the gossiping_property_file::reload_configuration()
method."
2015-10-30 15:48:42 +02:00
Pekka Enberg
a9a8d1e8a2 Merge "Fixes for dependency packages, fix upstart script" from Takuya
"Fixes #510, (part of) #493."
2015-10-30 15:41:40 +02:00
Lucas Meneghel Rodrigues
a3d26f699e test.py: Only print test stdout if non None, non empty
On hindsight, it doesn't make much sense to print an
empty string, so let's only print stdout if it's non
None, non empty.

Signed-off-by: Lucas Meneghel Rodrigues <lmr@scylladb.com>
2015-10-30 09:11:07 +02:00
Avi Kivity
91a8cfc029 cql3: don't declare counter-related functions
This works now, but fails when an in-progress patch I'm working on calls
one of the type's methods.
2015-10-30 09:06:48 +02:00
Vlad Zolotarov
6b4b983f9d locator::gossiping_property_file_snitch: implement gossiper_starting() and reload_gossiper_state()
This functions were empty and now they have the intended code:
   - Register the reconnectable_snitch_helper if "prefer_local"
     parameter was given the TRUE value.
   - Set the application INTERNAL_IP state to listen_address().

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-30 00:16:53 +02:00
Vlad Zolotarov
17294a3bc7 locator::gossiping_property_file_snitch: fix some issues in reload_configuration()
- Invoke reload_gossiper_state() and gossip_snitch_info() on CPU0 since
     gossiper is effectively running on CPU0 therefore all methods
     modifying its state should be invoked on CPU0 as well.
   - Don't invoke any method on external "distributed" objects unless their
     corresponding per-shard service object have already been initialized.
   - Update a local Node info in a storage_service::token_metadata::topology
     when reloading snitch configuration when DC and/or Rack info has changed.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-30 00:16:53 +02:00
Vlad Zolotarov
b3504f9b1f locator::token_metadata: added topology::update_endpoint(ep) and update_topology(ep)
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-30 00:16:53 +02:00
Vlad Zolotarov
a3d55ba882 locator::reconnectable_snitch_helper: remove unused constructor parameter
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-30 00:16:53 +02:00
Vlad Zolotarov
33b195760b gms::gossiper: allow the modification of _subscribers while it's being iterated
Introduce a subscribers_list class that exposes 3 methods:
  - push_back(s) - adds a new element s to the back of the list
  - remove(s) - removes an element s from the list
  - for_each(f) - invoke f on each element of the list
  - make a subscriber_list store shared_ptr to a subscriber
    to allow removing (currently it stores a naked pointer to the object).

subscribers_list allows push_back() and remove() to be called while
another thread (e.g. seastar::async()) is in the middle of for_each().

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Simplify subscribers_list::remove() method.
   - load_broadcaster: inherit from enable_shared_from_this instead
     of async_sharded_service.
2015-10-30 00:16:16 +02:00
Pekka Enberg
763b718418 Update 'docker run' instructions in README
Explicitly mention how to enable port forwarding so that external
applications are able to connect.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-29 20:07:04 +02:00
Takuya ASADA
3bf69db90c dist: handle SIGKILL correctly on upstart, also do not respawn process
Fixes #510
2015-10-30 00:55:47 +09:00
Takuya ASADA
6aac944588 dist: fix warning when building scylla-server ubuntu package 2015-10-30 00:53:20 +09:00
Takuya ASADA
37e00d3527 dist: fix warning when building thrift ubuntu package 2015-10-30 00:52:11 +09:00
Takuya ASADA
a165d6aa01 dist: fix warning when building antlr3-c++-dev ubuntu package 2015-10-30 00:52:00 +09:00
Takuya ASADA
9eb8aa7ea3 dist: fix warning when building antlr3-tool ubuntu package 2015-10-30 00:51:42 +09:00
Avi Kivity
f7f996d473 Merge seastar upstream
* seastar 9d8913a...9ae6407 (2):
  > core/memory.cc: Declare member min_free_pages from cpu_pages struct
  > http: All http replies should have version set
2015-10-29 16:49:10 +02:00
Asias He
6259dd73b6 token: Print token using the partitioner defined method
Make nodetool ring output align with c* output.
2015-10-29 15:53:47 +02:00
Pekka Enberg
f4849000c8 cql3: Fix exception message in lists::setter_by_index::execute()
Spotted by C* unit tests.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-29 15:36:56 +02:00
Pekka Enberg
6634f37464 cql3: Fix exception message in lists::discarder_by_index::execute()
Spotted by C* unit tests.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-29 15:36:51 +02:00
Pekka Enberg
2344bd806d cql3: Fix grammar 'WITH WITH' bug that causes a SIGSEGV
Fix an issue where 'WITH WITH' in CREATE and ALTER KEYSPACE would bring
down the whole server.

  https://issues.apache.org/jira/browse/CASSANDRA-9565

  c939422637

Spotted by C* unit tests.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-29 10:59:57 +01:00
Raphael S. Carvalho
6bea503f9a db: fallback to sizetiered if compaction strategy isn't supported
It may happen that the user will migrate a table to Scylla which
compaction strategy isn't supported yet, such as Data tiered.
Let's handle that by falling back to size-tiered compaction
strategy and printing a warning message.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-29 09:33:28 +02:00
Asias He
c030e6713b storage_service: Serialize rebuild
Do not hold the api lock while streaming the data since it might take a
long time, so we need to reconcile other operations while we are in the
middle of rebuild.
2015-10-29 09:51:52 +08:00
Asias He
cc6d4e0fc9 storage_service: Introduce run_with_no_api_lock
Run on cpu zero without take the api lock.
2015-10-29 09:50:03 +08:00
Asias He
2c8867c348 config: Enable storage_port option 2015-10-29 08:58:41 +08:00
Asias He
97d2bdf663 storage_service: Serialize gossiping operations 2015-10-29 08:58:41 +08:00
Asias He
f2e5e318d7 storage_service: Serialize effective_ownershipp with read api lock 2015-10-29 08:58:41 +08:00
Asias He
94a49121c2 storage_service: Serialize get_ownership with read api lock 2015-10-29 08:58:41 +08:00
Asias He
d41cd48a5f storage_service: Serialize is_joined with read api lock 2015-10-29 08:58:41 +08:00
Asias He
24a452133a storage_service: Serialize join_ring with write api lock 2015-10-29 08:58:41 +08:00
Asias He
08337b0df1 storage_service: Serialize more node management operations with read api lock
- get_operation_mode
- is_starting
- is_rpc_server_running
- is_native_transport_running
- get_load_map
- is_initialized
2015-10-29 08:58:41 +08:00
Asias He
c6bf157610 storage_service: Introduce run_with_read_api_lock
Similar to run_with_write_api_lock, but the operations only query the
cluster.
2015-10-29 08:58:41 +08:00
Asias He
93154e0184 storage_service: Serialize more node management operations with write api lock
- start_rpc_server
- stop_rpc_server
- start_native_transport
- stop_native_transport
- remove_node
2015-10-29 08:57:45 +08:00
Raphael S. Carvalho
c2a98807c7 compaction_manager: fix remove
remove() is the function used to remove every reference to a cf from
the compaction manager. This function works by removing cf from the
queue, and waiting for possible ongoing compaction on cf.
However, a cf may be re-queued by compaction manager task if there
is pending compaction by the end of compaction.

If cf is still referenced by the time remove() returns, we could end
up with an use-after-free. To fix that, a task shouldn't re-queue a
cf if it was asked to stop. The stat pending_tasks was also not
being updated when a cf was removed from the task queue.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-28 17:35:26 +02:00
Gleb Natapov
ac5f92db70 storage_proxy: clean up local_dc checking
The only place local_dc is checked during mutation sending is in
send_to_live_endpoints(), but current code pass it there throw several
function call layers. Simplify the code by getting local_dc when it is
used directly.
2015-10-28 16:10:18 +02:00
Paweł Dziepak
6e5916161c test/cql_test_env: merge client state after executing query
Since 4641dfff24 "service: Copy client
state to query state" after executing a query client state needs to be
merged back. If that's not done client_state::_last_timestamp_micros
won't be advanced properly and mutations originating from the same
source may have exactly the same timestamp.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-28 14:31:11 +02:00
Avi Kivity
4d23712c9c Merge "Fix gossip test" from Asias 2015-10-28 12:59:19 +02:00
Asias He
25c898fe9c gossip: Enable too more log prints for debug 2015-10-28 16:13:57 +08:00
Asias He
e0e8e9a1ed tests: Remove redundant debug info for gossip
The debug info is printed in logger already. Avoid to print it twice.
2015-10-28 16:13:57 +08:00
Asias He
01ee5d002a failure_detector: Remove debug print in operator<< 2015-10-28 16:13:57 +08:00
Asias He
f205ae30c3 tests: Fix gossip
- scylla/seastar/core/sharded.hh:439: Service& seastar::sharded<Service>::local()
  [with Service = locator::snitch_ptr]: Assertion `local_is_initialized()' failed.
- ./utils/fb_utilities.hh:74: static const inet_address utils::fb_utilities::get_broadcast_address():
  Assertion `broadcast_address()' failed.
2015-10-28 16:13:57 +08:00
Takuya ASADA
5aab69e72f dist: do not remove build/ dir when scylla-server ubuntu package building
Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-10-27 18:23:09 +02:00
Avi Kivity
7f88db8625 Merge "storage_service and gossip update" from Asias 2015-10-27 18:14:43 +02:00
Lucas Meneghel Rodrigues
a9a33d5a99 test.py: PEP8 Fixes
Fix some PEP8 problems found in the tester code:

 * Wrong spacing around operators
 * Lines between class and function definitions
 * Fixed some of the larger than 80 column statements
 * Removed an unused import

Signed-off-by: Lucas Meneghel Rodrigues <lmr@scylladb.com>
2015-10-27 17:54:54 +02:00
Tomasz Grabiec
491eae58a4 Merge branch 'gleb/read-repair' from seastar-dev.git
From Gleb:

Now that we can calculate mutation diffs do so on digest mismatch and send
them out.
2015-10-27 16:36:05 +01:00
Asias He
7e6e90dc52 storage_service: Serialize decommission
Prevent two operations happen simultaneously.
2015-10-27 21:48:38 +08:00
Asias He
4b75815306 storage_service: Introduce run_with_write_api_lock helper
It is useful to run code on cpu zero with the api lock.
2015-10-27 21:48:38 +08:00
Asias He
62228726a3 storage_service: Introduce a rwlock to serialize management operations 2015-10-27 21:48:38 +08:00
Asias He
1bbc1920d2 range_streamer: Start to use get_preferred_ip
It is available now.
2015-10-27 21:48:37 +08:00
Asias He
306bab9ead storage_service: Use get_preferred_ip
Now that it is available, use it.
2015-10-27 21:48:37 +08:00
Asias He
55b76a8963 api: No cpu zero trick for remove_node
storage_service::remove_node is guaranteed to run on cpu zero only.
2015-10-27 21:48:37 +08:00
Asias He
b3c7305d25 storage_service: Make remove_node runs on cpu 0 only
We need to serialize nodetool operations to avoid two operations
happening simultaneously. Running on cpu 0 is one step toward this
goal.
2015-10-27 21:48:37 +08:00
Asias He
6c6b1c4ba7 storage_service: Make decommission runs on cpu 0 only
We need to serialize nodetool operations to avoid two operations
happening simultaneously. Running on cpu 0 is one step toward this goal.
2015-10-27 21:48:37 +08:00
Asias He
49daba2599 storage_service: Do not ignore future in decommission
gossiper::stop returns a future which we can not ignore.
2015-10-27 21:48:37 +08:00
Asias He
00311817bd storage_service: Implement shutdown_client_servers 2015-10-27 21:48:37 +08:00
Asias He
83eb36796f storage_service: Kill FIXME for LoadBroadcaster.BROADCAST_INTERVAL
It is available now.
2015-10-27 21:48:37 +08:00
Asias He
1469cec5bf gossiper: Kill free function helper to get heart version and generation number
They can only be executed on cpu 0. Make the gossiper member
functions for them to do so.
2015-10-27 21:48:37 +08:00
Asias He
f573059698 gossiper: Kill free function helper for {unsafe_,}assassinate_endpoint
They can only be executed on cpu 0. Make the gossiper member functions
for them to do so.
2015-10-27 21:48:37 +08:00
Asias He
c5f377eb8b gossip: Simplify get_endpoint_downtime
_unreachable_endpoints is replicated to call cores. No need to query
on core 0.
2015-10-27 21:48:37 +08:00
Asias He
6f1db4fb72 gossip: Simplify get_unreachable_members
_unreachable_endpoints is replicated to call cores. No need to query on
core 0.

This also fixes a bug in storage_proxy::truncate_blocking
which might access _unreachable_endpoints on non-zero cores.
2015-10-27 21:48:37 +08:00
Asias He
a9f96d1f5a gossip: Replicate _unreachable_endpoints to all cores 2015-10-27 21:48:37 +08:00
Asias He
2439a2a982 gossip: Simplify get_live_members
_live_endpoints is replicated to call cores. No need to query on core 0.
2015-10-27 21:48:37 +08:00
Asias He
a28ba9cde8 api: Simplify get_tokens get_node_tokens and get_token_endpoint
token_metadata is replicated to all cores. No need to query on core 0.
2015-10-27 21:48:37 +08:00
Asias He
4e886f0399 storage_service: Implement is_rpc_server_running 2015-10-27 21:48:37 +08:00
Asias He
7f0634b429 storage_service: Implement stop_rpc_server 2015-10-27 21:48:37 +08:00
Asias He
ca66bea619 storage_service: Implement is_native_transport_running 2015-10-27 21:48:37 +08:00
Asias He
7bc49a1efe storage_service: Implement stop_native_transport 2015-10-27 21:48:37 +08:00
Asias He
8218ab7922 storage_service: Implement start_native_transport and start_rpc_server
They are used for APIs. Share the code in main.cc as well.
2015-10-27 21:48:37 +08:00
Lucas Meneghel Rodrigues
42c0acfc44 test.py: Return test output only if subprocess succeeded
The current code will try to print the output of a
subprocess.Popen().communicate() call even if that
call raised an exception and that output is None.

Let's fix this problem by only printing the output
if it's not None.

Signed-off-by: Lucas Meneghel Rodrigues <lmr@scylladb.com>
2015-10-27 15:17:05 +02:00
Asias He
3c47844e8c storage_service: Complete check_for_endpoint_collision
Part of it was stubbed.
2015-10-27 21:17:02 +08:00
Asias He
77a87cb2b6 storage_service: Implement prepare_replacement_info
Needed by replace node operation.
2015-10-27 21:17:02 +08:00
Vlad Zolotarov
5cdbc3701a tests: set broadcast address
Since commit 5613979a85
broadcast address has to be set before it's used for the first
time.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-27 15:16:13 +02:00
Avi Kivity
345f739f28 Merge seastar upstream
* seastar 501e4cb...9d8913a (3):
  > Add mutable to with_lock and do_with
  > app-template: disable collectd by default
  > reactor: use fdatasync() instead of fsync()
2015-10-27 15:13:36 +02:00
Avi Kivity
42a5c8b92e Merge "CQL request load balancing" from Pekka
"Currently, CQL requests are processed on the same CPU core where the
connection lives in. This series adds infrastructure for migrating CQL
processing to other cores and implements a round-robin load balancing
algorithm that can be enabled with the "--load-balance=round-robin"
command line option. Load balancing is not enabled by default because we
need to first run performance tests to determine if the simple
round-robin algorithm is sufficient, or wheter we need to implement more
sophisticated dynamic load balancing."
2015-10-27 15:04:44 +02:00
Gleb Natapov
58154333e8 storage_proxy: send out mutation diffs to each destination 2015-10-27 14:58:35 +02:00
Pekka Enberg
a772938e73 transport/server: Round-robin CQL request load balancing
Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-10-27 13:24:58 +02:00
Pekka Enberg
ed0607c10e transport/server: Merge client state changes in process_request()
In preparation for processing queries on shards other than where the
connection lives in, merge client state changes in process_request().

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-27 13:24:58 +02:00
Pekka Enberg
4641dfff24 service: Copy client state to query state
In preparation for processing CQL requests on different core than where
the connection lives in, copy client state to query state for
processing and merge back the results after we're done.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-27 13:24:58 +02:00
Pekka Enberg
27c678b2a5 transport/server: Use bytes_view instead of moving temporary buffer around
Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-10-27 13:13:25 +02:00
Pekka Enberg
4482406aee transport/server: Write response from process_request()
In preparation for spreading request processing to multiple cores, make
sure CQL response is written out on the connection shard.

Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-10-27 13:13:25 +02:00
Pekka Enberg
3b6eba1344 transport/server: Remove _query_states from connection
Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-10-27 13:13:25 +02:00
Pekka Enberg
3884f1c8b6 transport/server.cc: Fix formatting glitch
Signed-off-by: Pekka Enberg <penberg@cloudius-systems.com>
2015-10-27 13:13:25 +02:00
Gleb Natapov
122f03e689 storage_proxy: calculate mutation diffs during reconcile. 2015-10-27 13:02:15 +02:00
Gleb Natapov
8bbe4bdbd4 storage_proxy: rename reconciliate to reconcile
'reconciliate' does not seams to be a world.
2015-10-27 12:57:02 +02:00
Vlad Zolotarov
3a3867588a tests::cql_test_env: set broadcast address
cql_query_test hasn't configured Broadcast address before
it was used for the first time.

Broadcast address is an essential Node's configuration.

There is an assert in utils::fb_utils::get_broadcast_address()
that ensures that broadcast address has been properly configured
before it's used for the first time and it is triggered without
this patch.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-27 12:38:56 +02:00
Avi Kivity
0754e9a34d Merge "Even more commitlog fixes" from Calle
"Fixes for commitlog (debug) test failures related to shutdowns.
Note that most the fixes here are only really related to the tests
failing, not really real scylla runs. However, at some point we'll
have real shutdown in scylla as well (not just hard exit), at which
point this becomes more relevant there as well.

Main issue was post-flush continuation chains for stats update
remaining unexecuted, due to task reordering, once the commitlog
object itself had been destroyed. This could have been handled by just
making the stats object a shared pointer, but in general it seems more
prudent to enforce having all tasks completed after shutdown.

* Change commitlog shutdown to use gate+wait for all outstanding ops
  (flush, write, timer). Thus we can ensure everything is finished
  when returning from "shutdown".
* Fix bug with "commitlog::clear" (test method) not doing the intended deed
* Most importantly, fix the tests themselves, cleaning up old crud, and
  fixing invalid assumptions (CL behaviour changed quite a bit since tests
  were created), and remove races.

Disclaimer: I've _never_ managed to reproduce the debug tests failing
like in jenkins locally (though I managed to provoke other failures),
but at least jenkins runs with this series have been clean. Knock knock."
2015-10-27 12:16:20 +02:00
Paweł Dziepak
f46cba7bc8 sstable: simplify key reader
Now that #475 is solved an read_indexes() guarantees to return disjont
sets of keys sstable key reader can be simplified, namely, only two key
lookups are needed (the first and the last one) and there is no need for
range splitting.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-27 10:33:02 +02:00
Avi Kivity
fa0f00e9d2 Merge "Add EC2MultiRegionSnitch and Co." from Vlad
"This series add the mighty EC2MultiRegionSnitch and some missing
multi-DC related functionality:
   - Use the proper Broadcast Address: either the one from the
    .yaml configuration (if present) or the one configured by some
    scylla component (e.g. snitch).
   - Introduce the ability to switch to internal IPs when connecting
     to Nodes in the same data center.
   - Store the known internal IPs in system.peers table and
     load then immediately during boot.

This series also contains some related fixes done on the way."
2015-10-26 18:38:57 +02:00
Gleb Natapov
5bc532261f load_broadcaster: add missing header file protector 2015-10-26 18:38:01 +02:00
Avi Kivity
91bde5e2e8 Merge "sstable improvements" from Raphael 2015-10-26 17:25:58 +02:00
Asias He
6f08c4facb dns: Move gethostbyname to source file
Fix multiple definition of gethostbyname.
2015-10-26 15:59:58 +02:00
Calle Wilund
6dc6b40495 commitlog_test: test fix 2015-10-26 14:57:15 +01:00
Calle Wilund
ceb9f4d647 database: Just do commitlog::shutdown on shutdown. It will do flushes. 2015-10-26 14:56:24 +01:00
Calle Wilund
5299cece4c commitlog: Make "shutdown" do flushing + hard sync of pending ops
* Do close + fsync on all segments
* Make sure all pending cycle/sync ops are guarded with a gate, and
  explicitly wait for this gate on shutdown to make sure we don't
  leave hanging flushes in the task queue.
* Fix bug where "commitlog::clear" did not in fact shut down the CL,
  due to "_shutdown" being already set.

Note: This is (at least currently) not an issue for anything else than tests,
since we don't shutdown the normal server "properly", i.e. the CL itself
will not go away, and hanging tasks are ok, as long as the sync-all is done
(which it was previously). But, to make tests predictable, and future-proof
the CL, this is better.
2015-10-26 14:50:54 +01:00
Raphael S. Carvalho
25a4d6686a sstables: update comment
sstable level is set to zero by default, but it may be set to
a different value if a new sstable is the result of leveled
compaction. This is done outside write_components.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-26 10:39:22 -02:00
Raphael S. Carvalho
028283869f sstables: reuse BASE_SAMPLING_LEVEL constant from downsampling class
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-26 10:35:46 -02:00
Raphael S. Carvalho
b908d3a5e9 sstables: fix prepare_summary
We were incorrectly setting s.header.min_index_interval to
BASE_SAMPLING_LEVEL, which luckily is the default value to
min index interval. BASE_SAMPLING_LEVEL was also used as
the min index interval when checking if the estimated
number of summary entries is greater than the limit.
To fix problems, get min index interval from schema and
use this value to check the limit.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-26 10:27:03 -02:00
Avi Kivity
38df381206 Merge "remove node support" from Asias 2015-10-26 14:23:47 +02:00
Vlad Zolotarov
f70aab2fbb locator: added ec2_multi_region_snitch
This snitch in addition to what EC2Snitch does registers
a reconnectable_snitch_helper that will make messenger_service
connect to internal IPs when it connects to the nodes in the same
data center with the current Node.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v4:
   - Added dual license in newly added files.

New in v3:
   - Returned the Apache license.

New in v2:
   - Update the license to the latest version. ;)
2015-10-26 14:10:47 +02:00
Vlad Zolotarov
5613979a85 utils::fb_utilities: add the ability to set a broadcast address
Add utils::fb_utilities::set_broadcast_address().
Set it to either broadcast_address or listen_address configuration value
if appropriate values are set. If none of the two values above
are set - abort the application.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Simplify the utils::fb_utilities::get_broadcast() logic.
2015-10-26 14:10:39 +02:00
Vlad Zolotarov
a182a33d4d locator::snitch_base: added i_endpoint_snitch::set_local_private_addr()
Sets the value of the local private IP address.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:10:39 +02:00
Vlad Zolotarov
1bb91399cd locator: added reconnectable_snitch_helper
reconnectable_snitch_helper implements i_endpoint_state_change_subscriber
and triggers reconnect using the internal IP to the nodes in the
same data center when one of the following events happen:

   - on_join()
   - on_change() - when INTERNAL_IP state is changed
   - on_alive()

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v4:
   - Added dual license for newly added files.

New in v3:
   - Fix reconnect() logic.
   - Returned the Apache license.
   - Check if the new local address is not already stored in the cache.
   - Get rid of get_ep_addr().

New in v2:
   - Update the license to the latest version. ;)
2015-10-26 14:09:48 +02:00
Vlad Zolotarov
d683d9cfb0 locator::ec2_snitch: moved info parsing and distribution into the separate function
Added load_config() function that reads AWS info and property file
and distributes the read values on all shards.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
703807b67d locator::ec2_snitch: rename ZONE_QUERY_SERVER_ADDR -> AWS_QUERY_SERVER_ADDR
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
d8de1099eb message::messaging_service: introduce _preferred_ip_cache
This map will contain the (internal) IPs corresponding to specific Nodes.
The mapping is also stored in the system.peers table.

So, instead of always connecting to external IP messaging_service::get_rpc_client()
will query _preferred_ip_cache and only if there is no entry for a given
Node will connect to the external IP.

We will call for init_local_preferred_ip_cache() at the end of system table init.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Improved the _preferred_ip_cache description.
   - Code styling issues.

New in v3:
   - Make get_internal_ip() public.
   - get_rpc_client(): return a get_preferred_ip() usage dropped
     in v2 by mistake during rebase.
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
f896f9a908 message::messaging_service: added remove_rpc_client(shard_id)
This function erases shard_info objects from all _clients maps.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Use remove_rpc_client_one() instead of direct map::erase().
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
e9789dd68c message::messaging_service: fixes in rpc_protocol_client_wrapper shut down
- Ensure messaging_service::stop() blocks until all rpc_protocol::client::stop()
     are over.
   - Remove the async code from rpc_protocol_client_wrapper destructor - call
     for stop() everywhere it's needed instead. Ensure that
     rpc_protocol_client_wrapper is always "stopped" when its destructor is called.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v3:
   - Code style fixes.
   - Killed rpc_protocol_client_wrapper::_stopped.
   - Killed rpc_protocol_client_wrapper::~rpc_protocol_client_wrapper().
   - Use std::move() for saving shared pointer before
     erasing the entry from _clients in
     remove_rpc_client_one() in
     order to avoid extra ref count bumping.
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
842b13325d message::messaging_service: make _clients to be std::array
This makes code cleaner. Also it would allow less changes
if we decide to increase _clients size in the future.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
fd811dd707 db::system_keyspace: added get_preferred_ips()
get_preferred_ips() returns all preferred_ip's stored in system.peers
table.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Get rid of extra std::move().
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
f2e1be0fc1 db::system_keyspace::update_preferred_ip(): use net::ipv4_address as a preferred_ip value
Fixes issue #481

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:09:26 +02:00
Vlad Zolotarov
4f603d285e gms::gossiper: call for i_endpoint_snitch::gossiper_starting()
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-26 14:09:26 +02:00
Takuya ASADA
17f2038949 dist: fix upstart script to make it able to start/stop correctly
Scylla is not "daemon" (witch forks twice), but it can be "fork" (forks once) when we don't use "exec" to call startup scripts.
Fixes #495

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-10-26 13:00:52 +02:00
Takuya ASADA
25398d5a1d dist: statically link to libstdc++ on Ubuntu
Fixes #494

Signed-off-by: Takuya ASADA <syuu@scylladb.com>
2015-10-26 12:59:28 +02:00
Asias He
201d439440 storage_service: Enable remove_node support 2015-10-26 10:33:19 +02:00
Asias He
06b19867d8 api: Fix storage_service remove_node parameter
nodetool removenode takes the parameter of host_id instead of token.

Refs: #496
2015-10-26 10:32:47 +02:00
Asias He
9912a68364 storage_service: Enable remove_node support 2015-10-26 15:29:13 +08:00
Asias He
5f2d97c0b8 api: Fix storage_service remove_node parameter
nodetool removenode takes the parameter of host_id instead of token.

Refs: #496
2015-10-26 15:26:59 +08:00
Avi Kivity
7254c87776 Merge seastar upstream
* seastar 6af5a0d...501e4cb (2):
  > configure: don't fail when sanitizer is unavailable
  > memcached: close socket at the end of request handling
2015-10-25 19:59:45 +02:00
Shlomi Livne
d493b2a7f7 dist: ubuntu update build script file permissions
Signed-off-by: Shlomi Livne <shlomi@cloudius-systems.com>
2015-10-25 12:44:50 +02:00
Avi Kivity
e2e869f150 Merge "API: storage proxy metrics" from Amnon
"This series adds two types of functionality to the storage_proxy, it adds the
API that returns the timeout constants from the config and it aligned the
metrics of the read, write and range to origin StorageProxy metrics."
2015-10-25 11:40:46 +02:00
Avi Kivity
01e301fc9a Merge "fix read_indexes" from Raphael
Fixes issue #474.
2015-10-25 11:25:42 +02:00
Avi Kivity
ec4d1dd7fd Merge "CQL code cleanups" from Pekka
"Yet another round of code cleanups to cql3/*."
2015-10-25 10:35:19 +02:00
Tomasz Grabiec
a3e84c1553 tests: Add test for make_local_reader() and min/max tokens 2015-10-25 10:27:59 +02:00
Tomasz Grabiec
7b1e78ffcd storage_proxy: Fix make_local_reader() for ranges with min/max tokens
shard_of() was undefined for before_all/after_all tokens. Fix by
adding handling for these.
2015-10-25 10:27:58 +02:00
Raphael S. Carvalho
5cdc886f84 tests: add test to read_indexes
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-23 16:57:41 -02:00
Raphael S. Carvalho
af88a6864a sstables: fix read_indexes
read_indexes() will not work for a column family that minimum
index interval is different than sampling level or that sampling
level is lower than BASE_SAMPLING_LEVEl.
That's because the function was using sampling level to determine
the interval between indexes that are stored by index summary.
Instead, method from downsampling will be used to calculate the
effective interval based on both minimum_index_interval and
sampling_level parameters.

Fixes issue #474.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-23 16:57:41 -02:00
Raphael S. Carvalho
e18cf96b01 sstables: convert Downsampling to C++
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-23 16:57:39 -02:00
Pekka Enberg
e48f8d25e2 cql3: Move cf_statement class implementation to source file
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 16:17:17 +03:00
Pekka Enberg
d79d8b00f3 cql3: Move create_keyspace_statement class implementation to source file
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 16:17:17 +03:00
Pekka Enberg
baea79d17d cql3: Move schema_altering_statement class implementation to source file
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 16:17:17 +03:00
Pekka Enberg
6dbee22d2e cql3: Move use_statement class implementation to source file
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 16:17:17 +03:00
Pekka Enberg
ff93a840ae cql3: Remove ifdef'd code from use_statement.hh
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 15:52:02 +03:00
Pekka Enberg
83e6c428be transport: Add messages_fwd.hh and use it
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-23 15:52:02 +03:00
Tomasz Grabiec
7eb0da3ed8 Merge tag 'asias/range_streamer_use_after_free_gossip_print/v1' from seastar-dev.git
range_streamer use after free fix and gossip print cleanups from
Asias.
2015-10-23 14:43:20 +02:00
Asias He
a63871f024 gossip: Print application_state name instead of number
Plus print cleanup.
2015-10-23 17:03:18 +08:00
Asias He
687d88dd0c gossip: Add operator<< operator for application_state 2015-10-23 16:32:36 +08:00
Asias He
80f1b9781a gossip: Simplify make_token_string with boost::adaptors::transformed 2015-10-23 16:13:31 +08:00
Asias He
1ba20f4efd storage_service: Enable single_datacenter_filter in rebuild 2015-10-23 16:13:30 +08:00
Asias He
b172146223 range_streamer: Introduce single_datacenter_filter 2015-10-23 16:13:30 +08:00
Asias He
a934e31379 storage_service: Fix use after free in rebuild
streamer is a stack variable, it is gone when the function returns.
Fix it using a shared pointer.
2015-10-23 16:13:30 +08:00
Asias He
98b34ecc67 boot_strapper: Fix use after free
streamer is a stack variable, it is gone when the function returns.
Fix it using a shared pointer.

Fixes #489
2015-10-23 16:13:30 +08:00
Asias He
e2391b02da storage_service: Add debug info for get_load_map 2015-10-23 16:13:30 +08:00
Avi Kivity
2c16d1f980 Merge "fix nodetool gossipinfo and status" from Asias
"- Implement get_load_map using load_broadcaster
- Fix token in nodetool gossipinfo"
2015-10-23 10:34:13 +03:00
Asias He
bc8d3f0d24 storage_service: Implement get_load_map using load_broadcaster
$nodetool -p 7199 status

Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address    Load       Tokens  Owns    Host ID Rack
UN  127.0.0.1  60711      3       ?  78ce8d76-69f8-44fc-a5ae-b932eb4f641b  rack1
UN  127.0.0.2  66237      3       ?  b1eaaee6-c334-4a65-bc0c-95af49bca0b3  rack1
2015-10-23 11:53:46 +08:00
Asias He
a137006d27 main: Set load_broadcaster for storage_service during startup
Note only storage_service on shard 0 will access load_broadcaster
2015-10-23 11:28:06 +08:00
Asias He
992390feda storage_service: Store load_broadcaster into storage_service
It is needed by get_load_map.
2015-10-23 11:25:51 +08:00
Asias He
270e713fea Revert "API: Workaround for load_map"
This reverts commit 497e403387.
2015-10-23 10:45:54 +08:00
Asias He
6b7ca7e334 gossip: Cleanup versioned_value class 2015-10-23 10:06:19 +08:00
Asias He
5556861ac0 gossip: Fix nodetool gossipinfo
Use dht::global_partitioner().{to_sstring and from_sstring) to handle
tokens.

Before:
$ nodetool -p 7199  gossipinfo
127.0.0.1
  generation:1445528714
  heartbeat:105
  0:NORMAL,TOKENS
  2:c1e6c9ef-22c8-3f93-bca1-ea5810bafd36
  3:datacenter1
  4:rack1
  5:2.1.8
  8:127.0.0.1
  11:0
  12:d24aef9c-fc4e-4290-92f4-1fd317b8883a

After:
$ nodetool -p 7199  gossipinfo
127.0.0.1
  generation:1445528714
  heartbeat:105
  0:NORMAL,-3524784140453853209;2276970246802708341;-4108982606669659076
  2:c1e6c9ef-22c8-3f93-bca1-ea5810bafd36
  3:datacenter1
  4:rack1
  5:2.1.8
  8:127.0.0.1
  11:0
  12:d24aef9c-fc4e-4290-92f4-1fd317b8883a
2015-10-23 09:40:59 +08:00
Raphael S. Carvalho
19f2dc9ef9 import Downsampling.java
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-22 14:44:40 -02:00
Gleb Natapov
5b97604735 load_broadcaster: fix linkage error in debug mode
Also move it to service namespace.
2015-10-22 18:18:05 +02:00
Amnon Heiman
14482d4496 API: Add read, write, range estimated histogram implementation for storage_proxy
This patch adds the implmentation for the read, write and range
estimated histogram and total latency.

After this patch the following url will be available:
/storage_proxy/metrics/read/estimated_histogram/
/storage_proxy/metrics/read
/storage_proxy/metrics/write/estimated_histogram/
/storage_proxy/metrics/write
/storage_proxy/metrics/range/estimated_histogram/
/storage_proxy/metrics/range

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 18:54:45 +03:00
Amnon Heiman
e1168c0a34 API: Add estimated histogram to storage_proxy
This patch close the gap between the storage_proxy read, write and range
metrics and the API.

For each of the metrics there will be a histogram, estimated histogram
and total.

The patch contains the definitions for the following:
get_read_estimated_histogram
get_read_latency
get_write_estimated_histogram
get_write_latency
get_range_estimated_histogram
get_range_latency

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>

need mrege storage_proxy
2015-10-22 18:54:45 +03:00
Amnon Heiman
7b8c557f30 storage_service: Add estimated histogram for read, write and range
This patch adds an estimated histogram for read, write and range to the
proxy_service stats.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 18:54:45 +03:00
Amnon Heiman
a071cdce66 API: Add getters to storage_proxy timers timeout
This patch expose the configuration timeout values of the timers.
The timers will return their values in seconds, the swagger definition
file was modified to reflect the change.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 18:54:11 +03:00
Tomasz Grabiec
5bbc902eec mutation_partition: Drop now unnecessary unconst() usage
This change was actually promised by
f74c665671.
2015-10-22 17:12:03 +02:00
Tomasz Grabiec
c7be350961 mutation_partition: Rename reversion_traits to reversal_traits
As pointed out by Nadav, 'reversion' is from 'revert', 'reversal' is
from 'reverse'.
2015-10-22 18:09:07 +03:00
Tomasz Grabiec
f74c665671 mutation_partition: Add non-const-qualified version of range() and use it 2015-10-22 18:09:07 +03:00
Asias He
6c48ce065e storage_service: Make comment clearer in get_changed_ranges_for_leaving
We are not removing the range. Current node and new node will be
responsible for the range are calculated. We only need to stream data to
node = new node - current node. E.g,

Assume we have node 1 and node 2 in the cluster, RF=2. If we remove node2:

Range (3c 25 fa 7e d2 2a 26 b4 , 81 2a a7 32 29 e5 3a 7c ],
current_replica_endpoints={127.0.0.1, 127.0.0.2} new_replica_endpoints={127.0.0.1}

Range (3c 25 fa 7e d2 2a 26 b4 , 81 2a a7 32 29 e5 3a 7c ] already in all replicas

no data will be streamed to node 1 since it already has it.
2015-10-22 18:08:03 +03:00
Avi Kivity
a699bc20bc Merge "Adding the stream metrics API" from Amnon
"This series adds the stream metrics API, the swagger definition are based on
the StreamMetrics class in origin."
2015-10-22 17:18:01 +03:00
Amnon Heiman
5323b29699 API: Add compaction history to the API
This patch adds a definition and a stub for the compaction history. The
implementation should read fromt the compaction history table and return
an array of results.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 17:16:58 +03:00
Avi Kivity
5d37ee29f8 Merge "Adding log level support to the API" from Amnon
"This series adds an API to get and set the log level.
After this series it will be possible to use the folloing url:
GET/POST:
/system/logger
/system/logger/{name}"
2015-10-22 17:15:41 +03:00
Avi Kivity
b4e5b9dcf1 Merge "Add support to nodetool describecluster"
"This series adds the functionality that is required for nodetool
describecluster

It uses the gossiper for get cluster name and get partitioner.  The
describe_schema_versions functionality is missing and a workaround is used so
the command would work.

After this series an example for nodetool describecluster:
./bin/nodetool describecluster
Cluster Information:
	Name: Test Cluster
	Snitch: org.apache.cassandra.locator.SimpleSnitch
	Partitioner: org.apache.cassandra.dht.Murmur3Partitioner
	Schema versions:
		127.0.0.1: [48c4e6c8-5d6a-3800-9a3a-517d3f7b2f26]"
2015-10-22 17:11:30 +03:00
Gleb Natapov
ece6c68288 convert loadBroadcaster 2015-10-22 17:10:20 +03:00
Avi Kivity
8362622eb8 Merge "Support Ubuntu 14.04LTS" from Takuya 2015-10-22 17:03:04 +03:00
Avi Kivity
0129e42b06 Merge "Mutation diff" from Paweł
"This series add code for computing mutation_partition difference.
For mutations A and B:

diffA = A.difference(B);
diffB = B.difference(A);
AB = A.apply(B);

diffA is the minimal mutation that when applied to B makes it equal
to AB and diffB is the minimal mutation that applied to A results in AB.

Fixes #430."
2015-10-22 16:38:25 +03:00
Avi Kivity
f7087da054 Merge "GET methods for snapshots" from Glauber
"The snapshots API need to expose GET methods so people can
query information on them. Now that taking snapshots is supported,
this relatively simple series implement get_snapshot_details, a
column family method, and wire that up through the storage_service."
2015-10-22 15:23:45 +03:00
Calle Wilund
05de462fa9 commitlog: Make flush/segment delete slightly mode defensive + test tolerant
Fix for (mainly) test failures (use-after free)
I.e. test case test_commitlog_delete_when_over_disk_limit causes
use-after free because test shuts down before a pending flush is done,
and the segment manager is actually gone -> crash writing stats.
Now, we could make the stats a shared pointer, but we should never
allow an operation to outlive the segment_manager.
In normal op, we _almost_ guarantee this with the shutdown() call,
but technically, we could have a flush continuation trailing somewhere.

* Make sure we never delete segments from segment_manager until they are
  fully flushed
* Make test disposal method "clear" be more defensive in flushing and
  clearing out segments
2015-10-22 15:19:24 +03:00
Avi Kivity
9dc8d98146 Merge "Make mutation queries respect reversed order" from Tomasz
"Affects CQL statements like the following one:

   select * from table order by ck desc;

Fixes #480."
2015-10-22 15:08:19 +03:00
Takuya ASADA
a03056a915 dist: add dependency packages and build script for ubuntu 2015-10-22 11:55:50 +00:00
Takuya ASADA
e0604b066a dist: add debian/ directory to build .deb package for Ubuntu 2015-10-22 11:55:50 +00:00
Takuya ASADA
592b64e478 dist: mount hugetlbfs on ubuntu 2015-10-22 11:55:50 +00:00
Takuya ASADA
830041d6be dist: share scripts both on redhat and ubuntu 2015-10-22 11:55:50 +00:00
Avi Kivity
a2577fefb9 Merge "Enable decommission support" from Asias
"Tested with:

- start node 1
- insert value
- start node 2
- insert value
- decommission node2

I can see from the log that data range belongs to node2 is streamed to node1
and cqlsh query node1 returns all the data, and node2 is not in the live node
list from node1's view."
2015-10-22 14:44:24 +03:00
Avi Kivity
5f3a46eabb Merge "load_new_sstables" from Glauber
"This patchset implements load_new_sstables, allowing one to move tables inside the
data directory of a CF, and then call "nodetool refresh" to start using them.

Keep in mind that for Cassandra, this is deemed an unsafe operation:
https://issues.apache.org/jira/browse/CASSANDRA-6245

It is still for us something we should not recommend - unless the CF is totally
empty and not yet used, but we can do a much better job in the safety front.

To guarantee that, the process works in four steps:

1) All writes to this specific column family are disabled. This is a horrible thing to
   do, because dirty memory can grow much more than desired during this. Throughout out
   this implementation, we will try to keep the time during which the writes are disabled
   to its bare minimum.

   While disabling the writes, each shard will tell us about the highest generation number
   it has seen.

2) We will scan all tables that we haven't seen before. Those are any tables found in the
   CF datadir, that are higher than the highest generation number seen so far. We will link
   them to new generation numbers that are sequential to the ones we have so far, and end up
   with a new generation number that is returned to the next step

3) The generation number computed in the previous step is now propagated to all CFs, which
   guarantees that all further writes will pick generation numbers that won't conflict with
   the existing tables. Right after doing that, the writes are resumed.

4) The tables we found in step 2 are passed on to each of the CFs. They can now load those
   tables while operations to the CF proceed normally."
2015-10-22 13:42:24 +03:00
Avi Kivity
2b0a504cbc Merge "Adding row chache statistic to column family" from Amnon
"This series adds row cache statistic to the column family that will be expose
via the API."
2015-10-22 13:38:01 +03:00
Paweł Dziepak
740e2166c5 tests/mutation: add test for mutation diff
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
f78a80dfa3 mutation_partition: add method for computing difference
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
85edc3de07 mutation_partition: compute row difference
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
75df23dd3c types: add collection_type_impl::difference()
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
4440f9b85b mutation_partition: add row_marker::is_live()
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
2aa96eb00f mutation_partition: add insert_row()
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
a064181d7c mutation_partition: add row::with_both_ranges()
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
1c05d7b927 mutation_partition: fix row_marker::apply() for equal timestamps
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Paweł Dziepak
7fab0ee867 mutation_partition: add compare_row_marker_for_merge()
A compare_atomic_cell_for_merge() equivalent intended to be used
with row markers.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:08:53 +02:00
Asias He
04291dec28 storage_service: Enable call to excise 2015-10-22 17:41:02 +08:00
Asias He
ee551d070f storage_service: Enable add_expire_time_if_found in excise and handle_state_removing 2015-10-22 17:41:02 +08:00
Asias He
2137ab5522 storage_service: Implement add_expire_time_if_found 2015-10-22 17:41:02 +08:00
Asias He
e2fbd146d7 storage_service: Print keyspace info unbootstrap in debug 2015-10-22 17:41:02 +08:00
Asias He
affab296b0 storage_service: Fix ranges in stream_hints
Use range = make_open_ended_both_sides to present the entire ring.
2015-10-22 17:41:02 +08:00
Asias He
0d2fb9c99d storage_service: Add extract_expire_time 2015-10-22 17:41:02 +08:00
Asias He
58225216b3 storage_service: Fix immediate return for get_changed_ranges_for_leaving
It is a leftover when get_changed_ranges_for_leaving is get stubbed.
2015-10-22 17:41:02 +08:00
Asias He
fb27d682ad storage_service: Fix use after free for stream_plan
sp is a stack variable, it is gone when the function returns.
Fix it using a shared pointer.
2015-10-22 17:41:02 +08:00
Asias He
69b7028f84 storage_service: Fix token contains in handle_state_leaving
std::includes requires sorted container. get_tokens_for returns
std::unordered_set. Fix by put tokens into std::set.
2015-10-22 17:41:02 +08:00
Asias He
4785798904 storage_service: Kill unimplemented in decommission 2015-10-22 17:41:02 +08:00
Asias He
ce6dd0f8f8 storage_service: Implement start_leaving 2015-10-22 17:41:02 +08:00
Paweł Dziepak
513ab87b47 row_cache: update hit and miss stats in scanning reader
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:25:02 +03:00
Paweł Dziepak
b1b830bcbb row_cache: merge cache_entry::compare and ring_position_compare
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-22 12:25:02 +03:00
Tomasz Grabiec
f1306d3771 tests: Add tests for reversed mutation queries 2015-10-22 10:32:08 +02:00
Tomasz Grabiec
cc5cc7117d mutation_query: Respect 'reversed' partition_slice option
Fixes #480
2015-10-22 10:32:08 +02:00
Tomasz Grabiec
9dbd5a92d0 partition_slice_builder: Introduce reversed() 2015-10-22 10:32:08 +02:00
Amnon Heiman
c130381284 Adding live_scanned and tombstone scaned histogram to column family
This series adds a histogrm to the column family for live scanned and
tombstone scaned.

It expose those histogram via the API instead of the stub implmentation,
currently exist.

The implementation update of the histogram will be added in a different
series.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 11:13:28 +03:00
Amnon Heiman
378a97b66b API: Add row cahe hits and miss per column family
Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-22 11:12:14 +03:00
Glauber Costa
fd8e5c7e4c api: load new sstables
Just a wrapper into the storage_service's homonymous call.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:30:04 +02:00
Glauber Costa
673788ed46 storage_service load_new_sstables.
This is the storage_service implementation of load_new_sstables, and this is
where most of the complication lives.

Keep in mind that for Cassandra, this is deemed an unsafe operation:
https://issues.apache.org/jira/browse/CASSANDRA-6245

It is still for us something we should not recommend - unless the CF is
totally empty and not yet used, but we can do a much better job in the safety front.

To guarantee that, the process works in four steps:

1) All writes to this specific column family are disabled. This is a horrible thing to
   do, because dirty memory can grow much more than desired during this. Throughout out
   this implementation, we will try to keep the time during which the writes are disabled
   to its bare minimum.

   While disabling the writes, each shard will tell us about the highest generation number
   it has seen.

2) We will scan all tables that we haven't seen before. Those are any tables found in the
   CF datadir, that are higher than the highest generation number seen so far. We will link
   them to new generation numbers that are sequential to the ones we have so far, and end up
   with a new generation number that is returned to the next step

3) The generation number computed in the previous step is now propagated to all CFs, which
   guarantees that all further writes will pick generation numbers that won't conflict with
   the existing tables. Right after doing that, the writes are resumed.

4) The tables we found in step 2 are passed on to each of the CFs. They can now load those
   tables while operations to the CF proceed normally.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
36cea4313e column family: load new sstables
CF-level code to load new SSTables. There isn't really a lot of complication
here. We don't even need to repopulate the entire SSTable directory: by
requiring that the external service who is coordinating this tell us explicitly
about the new SSTables found in the scan process, we can just load them
specifically and add them to the SSTable map.

All new tables will start their lifes as shared tables, and will be unshared
if it is possible to do so: this all happens inside add_sstable and there isn't
really anything special in this front.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
54aaa58899 sstable_tests: test reshuffle operation
Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
a8db2b28c7 sstable tests: test set_generation
No code works until it's been tested.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
c5950c7bf7 sstable_test: get rid of frees
They exist. They shouldn't.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
f60021f87f sstable_tests: commonize code to compare two components.
The current codes assumes a particular dir/generation pair. We
will use it for a more generic case. This code could really use some
clean up, by the way. We should do it later.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
61be9fb02d reshuffle tables: mechanism to adjust new sstables' generation number
Before loading new SSTables into the node, we need to make sure that their
generation numbers are sequential (at least if we want to follow Cassandra's
footsteps here).

Note that this is unsafe by design. More information can be found at:
https://issues.apache.org/jira/browse/CASSANDRA-6245

However, we can already to slightly better in two ways:

Unlike Cassandra, this method takes as a parameter a generation number. We
will not touch tables that are before that number at all. That number must be
calculated from all shards as the highest generation number they have seen themselves.
Calling load_new_sstables in the absence of new tables will therefore do nothing,
and will be completely safe.

It will also return the highest generation number found after the reshuffling
process.  New writers should start writing after that. Therefore, new tables
that are created will have a generation number that is higher than any of this,
and will therefore be safe.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
1351c1cc13 database: mechanism to stop writing sstables
During certain operations we need to stop writing SSTables. This is needed when
we want to load new SSTables into the system. They will have to be scanned by all
shards, agreed upon, and in most cases even renamed. Letting SSTables be written
at that point makes it inherently racy - specially with the rename.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:06:22 +02:00
Glauber Costa
29e2ad7fd8 column family: commonize code to calculate the desired SSTable generation
We will reuse this for load_new_sstables.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:43 +02:00
Glauber Costa
3f6d47f1f2 sstables: change the current level of an sstable
This will be used, for instance, when importing an SSTable.
We would like to force all new SSTables to sit at level 0 for
compaction purposes.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
e11b828b6f sstables: allow an sstable to set its generation number
In some situations (restoring a backup from load_new_sstables), we want to
change the SSTable generation number. This patch provides a procedure to
achieve that.

It does so by linking the old files to new ones, and then removing the old
ones.

The reason we link instead of removing, is that we want to make sure that in
case there is a crash in the middle, the old data is still accessible.

If the crash happens after the link is done but before we start removing the
old files, that is fine: we will end up with duplicated data that will
disappear after the next compaction.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
a4d8e99f1c sstables: fix create_links so a TemporaryTOC is generated
That is the way to generate groups of files for the SSTables, so we must do it.
Because the links were mostly used by processes like snapshots and backups
where and external tool would (hopefully) verify the results, it was not that
serious.

But we now plan to use links to bring things into the main directory. It must
absolutely be done right.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
876e770df6 sstables: allow create_links to work with an arbitrary generation
During some situations (restoring a snapshot for instance) we may want a file
to get a different generation. This patch changes the code in create_links
slightly, so that it is able to link not only to a different location, but to
files with a different name, possibly in the same location - that is equivalent
to a generation change.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
27efe8bde9 sstables: make read_toc public
This is done on behalf of load_new_sstables: we would like to know which
components are present in the file, but without triggering the read for the
rest of the metadata.

As noted by Avi, using this directly can leave the SSTable in an inconsistent
state. We will have to fix is later since this is not the first offender.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
fcebf6f72d sstable tests: don't use set_generation method
There is no reason aside from testing for a table to just change its generation
number.

There will be, however, when we support loading new sstables. The method
however needs to be completely rewritten, so let's make sure the tests are not
using that.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:02:42 +02:00
Glauber Costa
f3bad2032d database: fix type for sstable generation.
Avoid using long for it, and let's use a fixed size instead.  Let's do signed
instead of unsigned to avoid upsetting any code that we may have converted.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 18:01:20 +02:00
Calle Wilund
412c2a1e5b storage_proxy: mutate_atomically fix for consistency and BL removal
The change to use consistency_level::ONE in send_batchlog_mutation
sort of fixes #478, but is not 100% correct.
When doing async_remove_from_batchlog, the CL is actually supposed to
be ANY.

Also, we should _not_ remove the batch log mutation from any nodes
if the mutate fails, since having it there in case of failure is sort of
the whole point of it. I.e. async_remove_from_batchlog should not be
called from a "finally", but from a "then".

Refs #478
2015-10-21 16:48:27 +02:00
Tomasz Grabiec
764d913d84 Merge branch 'pdziepak/row-cache-range-query/v4' from seastar-dev.git
From Pawel:

This series enables row cache to serve range queries. In order to achieve
that row cache needs to know whether there are some other partitions in
the specified range that are not cached and need to be read from the sstables.
That information is provied by key_readers, which work very similarly to
mutation_readers, but return only the decorated key of partitions in
range. In case of sstables key_readers is implemented to use partition
index.

Approach like this has the disadvantage of needing to access the disk
even if all partitions in the range are cached. There are (at least) two
solutions ways of dealing with that problem:
 - cache partition index - that will also help in all other places where it
   is neededed
 - add a flag to cache_entry which, when set, indicates that the immediate
   successor of the partition is also in the cache. Such flag would be set
   by mutation reader and cleared during eviction. It will also allow
   newly created mutations from memtable to be moved to cache provided that
   both their successors and predecessors are already there.

The key_reader part of this patchsets adds a lot of new code that probably
won't be used in any other place, but the alternative would be to always
interleave reads from cache with reads from sstables and that would be
more heavy on partition index, which isn't cached.

Fixes #185.
2015-10-21 15:26:45 +02:00
Gleb Natapov
6a2a0d628b storage_proxy: use CL=ONE to write logged batch
This is a regression created by logged batch code rework.

Fixes #478.
2015-10-21 15:29:49 +03:00
Avi Kivity
c69c02c162 Merge 2015-10-21 15:17:32 +03:00
Avi Kivity
c49dd5c576 Merge "move dependencies to /opt/scylladb" from Takuya 2015-10-21 15:17:04 +03:00
Glauber Costa
71c1b2fe69 api: get true snapshot size
Thin wrapper around storage service's facility.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 13:48:44 +02:00
Glauber Costa
c0630bedc2 api: get_snapshot_details
That's basically conversion work between what the storage_service returns
and the json types.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 13:48:44 +02:00
Glauber Costa
cf96d68478 storage_service: true snapshot size
For CFStats, one of the things needed is the size used by the snapshots. Since
the bulk of the work is map-reducing it and adding them together, we will just
call get_snapshot_details for the column family, and just selectively add just
what we need. No need for a separate method here.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 13:48:44 +02:00
Glauber Costa
718fea7048 storage_service: get_snapshot_details
The column family object can, for each column family, provide us with a map between
each snapshots it knows about, and two sizes: the total size, and the "real" (or live)
size, which is how much extra space the snapshot is costing us.

This patch map-reduces all CFs to accumulate that system-wide, and then formats that
into an a map of "snapshot_details". That is a more convenient format to be consumed
by our json generator.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 13:48:44 +02:00
Glauber Costa
77513a40db database: get_snapshot_details
For each of the snapshots available, the api may query for some information:
the total size on disk, and the "real" size. As far as I could understand, the
real size is the size that is used by the SSTables themselves, while the total
size includes also the metadata about the snapshot - like the manifest.json
file.

Details follow:

In the original Cassandra code, total size is:

    long sizeOnDisk = FileUtils.folderSize(snapshot);

folderSize recurses on directories, and adds file.length() on files. Again, my
understanding is that file_size() would give us the same as the length() method
for Java.

The other value, real (or true) size is:

    long trueSize = getTrueAllocatedSizeIn(snapshot);

getTrueAllocatedSizeIn seems to be a tree walker, whose visitor is an instance
of TrueFilesSizeVisitor. What that visitor does, is add up the size of the files
within the tree who are "acceptable".

An acceptable file is a file which:

starts with the same prefix as we want (IOW, belongs to the same SSTable, we
will just test that directly), and is not "alive". The alive list is just the
list of all SSTables in the system that are used by the CFs.

What this tries to do, is to make sure that the trueSnapshotSize is just the
extra space on disk used by the snapshot. Since the snapshots are links, then
if a table goes away, it adds to this size. If it would be there anyway, it does
not.

We can do that in a lot simpler fashion: for each file, we will just look at
the original CF directory, and see if we can find the file there. If we can't,
then it counts towards the trueSize. Even for files that are deleted after
compaction, that "eventually" works, and that simplifies the code tremendously
given that we don't have to neither list all files in the system - as Cassandra
does - or go check other shards for liveness information - as we would have to
do.

The scheme I am proposing may need some tweaks when we support multiple data
directories, as the SSTables may not be directly below the snapshot level.
Still, it would be trivial to inform the CF about their possible locations.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-21 13:48:44 +02:00
Avi Kivity
16006949d0 logalloc: make migrator an object, not a function pointer
The migrator tells lsa how to move an object when it is compacted.
Currently it is a function pointer, which means we must know how to move
the object at compile time.  Making it an object allows us to build the
migration function at runtime, making it suitable for runtime-defined types
(such as tuples and user-defined types).

In the future, we may also store the size there for fixed-size types,
reducing lsa overhead.

C++ variable templates would have made this patch smaller, but unfortunately
they are only supported on gcc 5+.
2015-10-21 11:24:56 +02:00
Avi Kivity
e2cd40e3bc Merge "remove and decommission node support part 2" from Asias
"More preparatory patches for remove and decommission node support:

- stream hints and reanges
- unbootstrap
- replication finished notification"
2015-10-21 12:24:14 +03:00
Takuya ASADA
1bf18679bb dist: add more build dependency for binutils
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 09:02:40 +00:00
Takuya ASADA
613c7e8226 dist: use scylla-* dependency packages on scylla-server.spec
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
29847edd4e dist: move antlr3-C++-devel package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
ad80845a1d dist: move antlr3-tool package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
cb18a305db dist: move ragel package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
b4daf31fcf dist: move ninja-build package to /opt/scylladb, remove unused dependency for re2c
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
91005ba366 dist: move boost package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
2e379179d3 dist: move gcc package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
09099081e1 dist: move isl package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
18a6c25434 dist: move binutils package to /opt/scylladb
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
90666cf558 dist: add scylla-env package for CentOS, to use /opt/scylladb as prefix
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
659624a2ee dist: dependency fix for ninja-build
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Takuya ASADA
7340a5a83a dist: fix srpm not found error
Signed-off-by: Takuya ASADA <syuu@cloudius-systems.com>
2015-10-21 08:49:34 +00:00
Asias He
1271ad6894 storage_service: Implement send_replication_notification 2015-10-21 16:11:33 +08:00
Asias He
56e55cd272 storage_proxy: Register replication_finished verb handler 2015-10-21 16:11:33 +08:00
Asias He
ffce7a7af8 storage_service: Implement confirm_replication 2015-10-21 16:11:33 +08:00
Asias He
1965e8751b messaging_service: Add REPLICATION_FINISHED verb
It is used to send replication finished message by storage_service when
removing a node from a cluster.
2015-10-21 16:11:33 +08:00
Asias He
d903bd0dba storage_service: Implement on_leave_cluster in excise 2015-10-21 14:55:01 +08:00
Asias He
4f57f0cdae storage_service: Enable restore_replica_count in remove_node 2015-10-21 14:55:01 +08:00
Asias He
5b170d1ffe storage_service: Complete handle_state_removing
Implement #if 0'ed code.
2015-10-21 14:55:01 +08:00
Asias He
7d656fe127 storage_service: Enable add_leaving_endpoint in handle_state_leaving 2015-10-21 14:55:01 +08:00
Asias He
d3120b3c2f storage_service: Complete is_replacing logic in handle_state_normal 2015-10-21 14:55:01 +08:00
Asias He
434a9e211e storage_service: Kill one FIXME in handle_state_bootstrap
It is already fixed.
2015-10-21 14:55:01 +08:00
Asias He
6f8f4816a5 storage_service: Implement unbootstrap
All the missing functions for unbootstrap are ready, we can implement
unbootstrap now.
2015-10-21 14:55:01 +08:00
Asias He
8a9374b331 storage_service: Implement stream_hints
Needed by unbootstrap.
2015-10-21 14:55:01 +08:00
Asias He
3f5e9baa17 storage_service: Implement stream_ranges
Needed by unbootstrap.
2015-10-21 14:55:01 +08:00
Asias He
d1eaccd234 storage_service: Implement leave_ring
Needed by unbootstrap.
2015-10-21 14:55:01 +08:00
Asias He
2f86feb581 storage_service: Move send_replication_notification to source file 2015-10-21 14:55:01 +08:00
Avi Kivity
5453cfbab7 Merge "snapshots: take + clear" from Glauber
"This is the code for taking a snapshot, and clearing a snapshot."
2015-10-21 08:59:42 +03:00
Paweł Dziepak
2876c9ebc7 unimplemented: drop RANGE_QUERIES
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
c2b53c5282 row_cache: add scanning_and_populating_reader
This reader enables range queries on row cache. An underlying key_reader
is used to obtain information about partitions that belong to the
specified range and if any of them isn't in the cache an underlying
mutation reader is used to read the missing data.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
9abefbfa28 row_cache: add just_cache_scanning_reader
This mutation reader returns mutations from cache that are in a given
range. There may be other mutations in the system (e.g. in sstables)
that won't be returned, so this reader on its own cannot really satisfy
any query.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
c765b38599 row_cache: add modification counter
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
c1e95dd893 row_cache: pass underlying key_source to row_cache
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
6b73d6bb36 row_cache: add cache_entry::ring_position_compare
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
96a42a9c69 column_family: add sstables_as_key_source()
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
b0edaa5bb7 memtable: add as_key_source()
Needed only for tests.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:53 +02:00
Paweł Dziepak
68e1b1f613 tests/sstables: test sstable key_reader
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:47 +02:00
Paweł Dziepak
7fe6d2dc07 sstables: provide key_reader
In order to get just partition keys stored in the sstable its summary
and index are used.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:47 +02:00
Paweł Dziepak
ca278e6b52 tests/key_reader: add tests for key_readers
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:47 +02:00
Paweł Dziepak
7c480f29c3 key_reader: add filtering key reader
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:47 +02:00
Paweł Dziepak
e683d57768 key_reader: add key_from_mutation_reader
This is a wrapper that allows using mutation_reader as key_reader.
Useful mostly in tests.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:47 +02:00
Paweł Dziepak
5604830389 key_reader: add combined_reader
Combined key reader, just like its mutation equivalents, combines
output from multiple key_readers and provides a single sorted stream
of decorated keys.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:27:32 +02:00
Paweł Dziepak
1f0cb9066b add key_reader interface
key_readers provide an interface analogous to mutation_readers, but the
only data they return are decorated keys.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:26:54 +02:00
Paweł Dziepak
31341787e4 mutation: optimize mutation_opt
Since mutation stores all its data externally and the object itself is
basically just a std::unique_ptr<> there is no need for stdx::optional.
Smart pointer set to nullptr represents a disengaged mutation_opt.

Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:24:11 +02:00
Paweł Dziepak
aed403efc2 mutation_reader: move move_and_disengage to a separate header
Signed-off-by: Paweł Dziepak <pdziepak@scylladb.com>
2015-10-20 20:24:11 +02:00
Avi Kivity
cf734132e7 Merge "Flusing of CF:s without replay positions" from Calle
"Fixes: #469

We occasionally generate memtables that are not empty, yet have no
high replay_position set. (Typical case is CL replay, but apparently
there are others).

Moreover, we can do this repeatedly, and thus get caught in the flush
queue ordering restrictions.

Solve this by treating a flush without replay_position as a flush at the
highest running position, i.e. "last" in queue. Note that this will not
affect the actual flush operation, nor CL callbacks, only anyone waiting
for the operation(s) to complete.

To do this, the flush_queue had its restrictions eased, and some introspection
methods added."
2015-10-20 17:36:57 +03:00
Raphael S. Carvalho
93c1035f6e range: add comment explaining !start and !end in lambda
Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-20 17:23:35 +03:00
Raphael S. Carvalho
c3a9d342f4 range: rename overlap to overlaps
overlaps() is more grammatical.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-20 17:23:35 +03:00
Avi Kivity
f4bd089b83 Merge "remove and decommission node" from Asias
"Preparatory patch for remove and decommission node support"
2015-10-20 17:00:04 +03:00
Glauber Costa
3a95a9cbe6 api: implement clear snapshot
Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:31 +02:00
Glauber Costa
19bb50f450 api: implement take_snapshot
Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:31 +02:00
Glauber Costa
21f84d77fc storage_service: delete a snapshot
This patch provides an storage service api to delete an snapshot.  Because all
keyspaces and CFs are visible in all shards. This will allow us to fetch the
list of keyspaces in the present shard and issue the filesystem operations in
that same shard.

That simplifies the code tremendously, and because there are not any operations
we need to do previous to the fs ones (like in the case of create snapshot), we
need no synchronization. Even easier.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:31 +02:00
Glauber Costa
2f2a4e83e0 storage_service: take a snapshot of a particular column family
Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:30 +02:00
Glauber Costa
fe3164714f storage_service: take a snapshot of a group of keyspaces
Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:30 +02:00
Glauber Costa
d236b01b48 snapshots: check existence of snapshots
We go to the filesystem to check if the snapshot exists. This should make us
robust against deletions of existing snapshots from the filesystem.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:58:26 +02:00
Glauber Costa
d3aef2c1a5 database: support clear snapshot
This allows for us to delete an existing snapshot. It works at the column
family level, and removing it from the list of keyspace snapshots needs to
happen only when all CFs are processed. Therefore, that is provided as a
separate operation.

The filesystem code is a bit ugly: it can be made better by making our file
lister more generic. First step would be to call it walker, not lister...

For now, we'll use the fact that there are mostly two levels in the snapshot
hierarchy to our advantage, and avoid a full recursion - using the same lambda
for all calls would require us to provide a separate class to handle the state,
that's part of making this generic.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:38:14 +02:00
Glauber Costa
500ee99c93 file lister: allow for more than one directory type
There are situations in which we would like to match more than one directory
type.  One example of that, would be a recursive delete operation: we need to
delete the files inside directories and the directories themselves, but we
still don't want a "delete all" since finding anything other than a directory
or a file is an error, and we should treat it as such.

Since there aren't that many times, it should be ok performance wise to just
use a list. I am using an unordered_set here just because it is easy enough,
but we could actually relax it later if needed. In any case, users of the
interface should not worry about that, and that decision is abstracted away
into lister::dir_entry_types.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-20 15:38:14 +02:00
Asias He
9e5ee17f4a storage_service: Implement rebuild 2015-10-20 21:32:30 +08:00
Asias He
31b50a83d1 storage_service: Implement excise 2015-10-20 21:32:30 +08:00
Asias He
0cf112501e storage_service: Implement restore_replica_count 2015-10-20 21:32:30 +08:00
Asias He
0ebcb1ddef storage_service: Stub send_replication_notification
Needed by restore_replica_count.
2015-10-20 21:32:30 +08:00
Asias He
1c480554eb storage_service: Stub get_new_source_ranges
Needed by restore_replica_count.
2015-10-20 21:32:30 +08:00
Asias He
955e766a49 storage_service: Partially implement decommission 2015-10-20 21:32:30 +08:00
Asias He
893849f8af storage_service: Stub unbootstrap 2015-10-20 21:32:30 +08:00
Asias He
9ebae12614 storage_service: Partially implement remove_node
restoreReplicaCount and excise are missing.
2015-10-20 21:32:30 +08:00
Asias He
142f29483a token_metadata: Implement add_leaving_endpoint 2015-10-20 21:32:30 +08:00
Asias He
f1bc882b90 storage_service: Implement get_changed_ranges_for_leaving 2015-10-20 21:32:30 +08:00
Asias He
937474bf14 abstract_replication_strategy: Make calculate_natural_endpoints public
It is used by storage_service.
2015-10-20 21:32:30 +08:00
Asias He
c5e35ac57e storage_service: Enable _replicating_nodes and _removing_node members 2015-10-20 21:32:30 +08:00
Asias He
f30fbd53ff storage_service: Start to use pending_range_calculator_service 2015-10-20 21:32:30 +08:00
Asias He
934c963d85 init: Init pending_range_calculator_service 2015-10-20 21:32:29 +08:00
Asias He
8d6200c036 service: Convert PendingRangeCalculatorService.java to C++ 2015-10-20 21:32:29 +08:00
Asias He
a5d91519f2 service: Import PendingRangeCalculatorService.java 2015-10-20 21:32:29 +08:00
Asias He
c96bc8bbd2 token_metadata: Implement calculate_pending_ranges 2015-10-20 21:32:14 +08:00
Asias He
a6065397d9 token_metadata: Implement clone_after_all_left 2015-10-20 20:38:43 +08:00
Avi Kivity
5abdc4323a Merge seastar upstream
* seastar 46fd389...6af5a0d (2):
  > sharded: do not try to call nonexistent delete callback
  > use real argv0 in dpdk initialization
2015-10-20 15:19:35 +03:00
Tomasz Grabiec
67d0f9c7df lsa: Restore heap invariant before calling _segments.erase()
This is certainly the right thing to do and seems to fix #403. However
I didn't manage to convince myself that this would cause problems for
binomial_heap, given that binomial_heap::erase() calls siftup()
anyway:

    void erase(handle_type handle)
    {
        node_pointer n = handle.node_;
        siftup(n, force_inf());
        top_element = n;
        pop();
    }

    void increase (handle_type handle)
    {
        node_pointer n = handle.node_;
        siftup(n, *this);

        update_top_element();
        sanity_check();
    }
2015-10-20 15:18:05 +03:00
Asias He
08b762111e storage_service: Fix ignored future in on_dead
All the on_xxx interface in i_endpoint_state_change_subscriber are
called within a seastar::async context.
2015-10-20 15:16:03 +03:00
Amnon Heiman
1e8752d55e API: Fix a confusion in the storage service snapshot details
There was a confusion between the snapshot key and the keyspace in the
snapshot details, this fixes it.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-20 13:53:09 +03:00
Avi Kivity
2575a4602e Merge "Fix for snapshots/create_links and shared SSTables" from Glauber
"Those are fixes needed for the snapshotting process itself. I have bundled this
in the create_snapshot series before to avoid a rebase, but since I will have to
rewrite that to get rid of the snapshot manager (and go to the filesystem),
I am sending those out on their own."
2015-10-20 13:49:17 +03:00
Pekka Enberg
3a3c7f7e79 configure.py: Propagate CFLAGS to seastar config
We need to propagate CFLAGS to seastar config for things like
DEBUG_SHARED_PTR to work.
2015-10-20 10:57:26 +03:00
Amnon Heiman
91d396760e API: add a workaround for the get schema_versions
This adds a workaround for the get schema_version, it will return only a
shcema version of the local node, this is a temporary workaround until
describe_schema_versions will be implemented.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-20 10:56:21 +03:00
Amnon Heiman
383d7ccf4d Add the get cluster and partitioner names to the API
This adds the implementation for the get cluster name and get
partitioner name to the storage_service API.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-20 10:54:55 +03:00
Amnon Heiman
77b4fc74cd gossiper need to set the cluster name on all shareds
The API can call any of the gossiper shareds to get the cluster name, so
the initilization needs to set it in all of them.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-20 10:52:14 +03:00
Amnon Heiman
ff67285091 gossiper: make the get cluster name and partitioner public
The API needs the cluster and the partitioner names, so the methods are
now public.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-20 10:21:19 +03:00
Calle Wilund
786d66cacf commitlog: Fix use-after-free
Remove "finally". Just use a then_wrapped. Which it was originally, before
"handle_exception" was introduced to seastar. Oh, the irony...
2015-10-20 09:56:40 +03:00
Calle Wilund
02732f19f2 database: Handle CF flush with no high replay_position
We occasionally generate memtables that are not empty, yet have no
high replay_position set. (Typical case is CL replay, but apparently
there are others).

Moreover, we can do this repeatedly, and thus get caught in the flush
queue ordering restrictions.

Solve this by treating a flush without replay_position as a flush at the
highest running position, i.e. "last" in queue. Note that this will not
affect the actual flush operation, nor CL callbacks, only anyone waiting
for the operation(s) to complete.
2015-10-20 08:24:04 +02:00
Calle Wilund
31fca82213 flush_queue_test: Add test for multiple ops per key 2015-10-20 08:24:04 +02:00
Calle Wilund
62c0be376c flush_queue: Ease key restriction and allow multiple calls on each key
As long as we guarantee that the execution order for the post ops are
upheld, we can allow insertion of multiple ops on the same key.

Implemented by adding a ref count to each position.

The restriction then becomes that an added key must either be larger
than any already existing key, _OR_ already exist. In the latter case,
we still know that we have not finished this position and signaled
"upwards".
2015-10-20 08:24:04 +02:00
Calle Wilund
ca451acb41 commitlog: Fix use-after-free
Remove "finally". Just use a then_wrapped. Which it was originally, before
"handle_exception" was introduced to seastar. Oh, the irony...
2015-10-20 08:02:46 +02:00
Avi Kivity
2ccb5feabd Merge "Support nodetool cfhistogram"
"This series adds the missing estimated histogram to the column family and to
the API so the nodetool cfhistogram would work."
2015-10-19 17:11:46 +03:00
Raphael S. Carvalho
28ef8feffa tests: fix test for leveled compaction
test_setup::do_with_test_directory is missing. For some reason,
the test wasn't failing without it until now. Adding it is the
correct thing to do anyway.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2015-10-19 17:07:08 +03:00
Avi Kivity
f4706c7050 Merge "initial support to leveled compaction" from Raphael
"This patchset introduces leveled compaction to Scylla.
We don't handle all corner cases yet, but we already have the strategy
and compaction working as expected. Test cases were written and I also
tested the stability with a load of cassandra-stress.

Leveled compaction may output more than one sstable because there is
a limit on the size of sstables. 160M by default.
Related to handling of partial compaction, it's still something to be
worked on.

Anyway, it will not be a big problem. Why? Suppose that a leveled
compaction will generate 2 sstables, and scylla is interrupted after
the first sstable is completely written but before the second one is
completely written. The next boot will delete the second sstable,
because it was partially written, but will not do anything with the
first one as it was completely written.
As a result, we will have two sstables with redundant data."
2015-10-19 16:17:45 +03:00
Amnon Heiman
5998ee718a API: Add logger API implementation to the system API
This patch adds the ability to set one or all log levels get a log level
and get all logs name.

After this patch the following url will be available:
GET/POST
/system/logger
/system/logger/{name}

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-19 15:05:46 +03:00
Amnon Heiman
ba1e6adf2a Adding the system swagger definition
The system api will include system related command, currently it holds
the logger related API. It holds definition for the following commands:
get_all_logger_names
set_all_logger_level
get_logger_level
set_logger_level

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-19 14:59:54 +03:00
Amnon Heiman
521d9b62dd Add a level_name function to logger
This is a helper function that returns a log level name. It will be used
by the API to report the log levels.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-19 14:59:54 +03:00
Glauber Costa
218fdebbeb snapshot: do not allow exceptions in snapshot creation hang us
With the distribute-and-sync method we are using, if an exception happens in
the snapshot creation for any reason (think file permissions, etc), that will
just hang the server since our shard won't do the necessary work to
synchronize and note that we done our part (or tried to) in snapshot creation.

Make the then clause a finally, so that the sync part is always executed.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-19 13:37:02 +02:00
Glauber Costa
9083a0e5a7 snapshots: fix generation of snapshots with shared sstables
create_links will fail in one of the shards if one of the SSTables happen to be
shared. It should be fine if the link already exists, so let's just ignore that case.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-19 13:37:01 +02:00
Gleb Natapov
156f760663 storage_proxy: drop Origin's truncate code from comment
Drop already translated code.
2015-10-19 14:06:06 +03:00
Gleb Natapov
ae42ec7832 storage_proxy: actually sort endpoints in get_live_sorted_endpoints() 2015-10-19 13:38:37 +03:00
Avi Kivity
75ab27f683 Revert "Merge "move dependencies to /opt/scylladb" from Takuya"
This reverts commit c96b0453f2, reversing
changes made to b862165279e70300d29a075dc913523d56a616d2; there were some
extra commits on that branch.
2015-10-19 13:31:51 +03:00
Avi Kivity
c96b0453f2 Merge "move dependencies to /opt/scylladb" from Takuya
"This moves all dependency packages to /opt/scylladb."
2015-10-19 13:28:39 +03:00
Takuya ASADA
14fab1e36d dist: use scylla-* dependency packages on scylla-server.spec 2015-10-19 09:11:22 +00:00
Takuya ASADA
39e17e04bc dist: move antlr3-C++-devel package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
71182a0a95 dist: move antlr3-tool package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
1c7d8bc0e9 dist: move ragel package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
95c67a3e2e dist: move ninja-build package to /opt/scylladb, remove unused dependency for re2c 2015-10-19 09:11:22 +00:00
Takuya ASADA
ab8fe49b4f dist: move boost package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
2c7861b7ed dist: move gcc package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
23b69d610c dist: move isl package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
6db2ddc53b dist: move binutils package to /opt/scylladb 2015-10-19 09:11:22 +00:00
Takuya ASADA
f06e50a569 dist: add scylla-env package for CentOS, to use /opt/scylladb as prefix 2015-10-19 09:11:22 +00:00
Calle Wilund
b862165279 commitlog_test: Modify test_allocation_failure to not require huge segment
Explicitly use up all the memory in the system as best as we can instead
Still not super reliable, but should have less side effects. And work better
with pre-allocated segment files
2015-10-19 11:32:35 +03:00
Calle Wilund
681718f738 commitlog_test: Modify test_allocation_failure to not require huge segment
Explicitly use up all the memory in the system as best as we can instead
Still not super reliable, but should have less side effects. And work better
with pre-allocated segment files
2015-10-19 10:30:57 +02:00
Avi Kivity
eed43b276c tests: use workspace-local directory for commitlog
Can't rely on default /var/lib/scylla to be there or accessible.
2015-10-19 10:21:16 +02:00
Tomasz Grabiec
19d7d30e67 Replace references to 'urchin' with 'scylla' 2015-10-19 11:08:05 +03:00
Takuya ASADA
ca43a5f2ca dist: dependency fix for ninja-build 2015-10-19 06:59:15 +00:00
Takuya ASADA
721d0f9f64 dist: fix srpm not found error 2015-10-19 06:52:48 +00:00
Takuya ASADA
78813d9617 dist: create rpmbuild dirs 2015-10-19 06:51:03 +00:00
Vlad Zolotarov
7492b662c8 locator::gossiping_property_file_snitch: do_withicate file descriptor in property_file_was_modified()
file::stat() requires "this" to be valid will the end of the call.

Fixes issue #464

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-19 06:51:03 +00:00
Vlad Zolotarov
8c4ce0efee locator::production_snitch_base: fix production_snitch_base signature
Make production_snitch_base constructor signature consistent with
the rest of production snitches.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-19 06:51:03 +00:00
Vlad Zolotarov
4b8b3e7841 locator::production_snitch_base: cleanup
Don't keep the file descriptor beyond load_property_file() scope.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-19 06:51:03 +00:00
Vlad Zolotarov
9dfc08cf9f locator::gossiping_property_file_snitch: use empty string as a default config file name
A non-empty default value of a configuration file name was preventing
the db::config::get_conf_dir() to kick in when a default snitch constructor
was used (this is the way it's always used from scylla).

Fixes issue #459

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-19 06:51:03 +00:00
Avi Kivity
ce046d07da tests: create directories for user column families as well 2015-10-19 06:51:03 +00:00
Avi Kivity
f63002a75e tests: initialize system keyspace (and its directories) for cql_test_env
Now that columnb familiy directories are not created on demand, the tests
started to fail.
2015-10-19 06:51:03 +00:00
Raphael S. Carvalho
dfc95587d6 db: do not ignore compaction strategy class
When building the in-memory schema for a column family, we were
ignoring compaction strategy class because of a bug in the
existing code. Example: suppose that you create a column family
with leveled compaction strategy. This option would be ignored
and the default strategy (size-tiered) would be used instead.
Found this problem while working on leveled compaction.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-19 06:51:03 +00:00
Glauber Costa
c8a6883987 sstables: remove outdated comment
We already write all components. The FIXME is fixed.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-19 06:51:03 +00:00
Avi Kivity
dd2bf81131 tests: disable collectd
No need to blast collectd metrics during test runs.
2015-10-19 09:05:48 +03:00
Avi Kivity
268f7acd11 Merge snitch fixes from Vlad
"This series cleans up a few places in the snitches
code that has been noticed during the work on issues #464
and #459.

The last patch actually fixes the issue #464"
2015-10-18 17:21:30 +03:00
Vlad Zolotarov
fe5e983152 locator::gossiping_property_file_snitch: do_withicate file descriptor in property_file_was_modified()
file::stat() requires "this" to be valid will the end of the call.

Fixes issue #464

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-18 16:58:27 +03:00
Vlad Zolotarov
15606fc8d3 locator::production_snitch_base: fix production_snitch_base signature
Make production_snitch_base constructor signature consistent with
the rest of production snitches.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-18 16:58:27 +03:00
Vlad Zolotarov
5712aa4d48 locator::production_snitch_base: cleanup
Don't keep the file descriptor beyond load_property_file() scope.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-18 16:58:27 +03:00
Vlad Zolotarov
f113a57ba1 locator::gossiping_property_file_snitch: use empty string as a default config file name
A non-empty default value of a configuration file name was preventing
the db::config::get_conf_dir() to kick in when a default snitch constructor
was used (this is the way it's always used from scylla).

Fixes issue #459

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-18 16:56:12 +03:00
Avi Kivity
bb67258c68 tests: create directories for user column families as well 2015-10-18 14:45:42 +03:00
Avi Kivity
9fd73417ae tests: initialize system keyspace (and its directories) for cql_test_env
Now that columnb familiy directories are not created on demand, the tests
started to fail.
2015-10-18 12:25:36 +03:00
Raphael S. Carvalho
a21af32eed db: do not ignore compaction strategy class
When building the in-memory schema for a column family, we were
ignoring compaction strategy class because of a bug in the
existing code. Example: suppose that you create a column family
with leveled compaction strategy. This option would be ignored
and the default strategy (size-tiered) would be used instead.
Found this problem while working on leveled compaction.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-18 11:06:37 +03:00
Glauber Costa
f1c681de60 sstables: remove outdated comment
We already write all components. The FIXME is fixed.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-17 15:28:55 +03:00
Avi Kivity
82f3f76e74 Merge "remove on-demand creation of SSTable directory" from Glauber
"Let's do it better and create the directories when the tables are first
created."
2015-10-17 15:23:56 +03:00
Glauber Costa
c814be253a sstables: no longer touch directory when writing SSTables
After the previous two patches, the CF directory where the SSTable will live is
guaranteed to always exist: system CFs' are touched at boot while newly created
tables' are touched when the creation mutations are announced.

With that in place, there is no more need for the recursive touch in the
SSTables path.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-17 13:08:07 +02:00
Glauber Costa
c3e68ad5a4 guarantee that CF directories exist for system tables
This is done in a single shard, so it lives in main.cc

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-17 13:08:07 +02:00
Glauber Costa
e99e418238 schema_tables: make sure CF directory exists upon creation
In Cassandra, when you create a new column family, a directory for it
immediately appears under the KS directory.

In the past, we have made a decision to delay that creation until the first
SSTable is created, which works well in general.

There is a problem, however, for backup restoration: the standard procedure to
call loadNewSSTables is to do that in an empty directory. But the directory
simply won't be there until we create the first SSTable: bummer!

In the current incarnation of the code in schema_tables.cc, there is already
some code that runs on CPU0 only. That is a perfect place for the directory
creation. So let's do it.

After this patch, a directory for the CF appears right after the CF creation.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-17 13:08:07 +02:00
Glauber Costa
df857eb8c6 database: touch directories for the column family
Current code calls make_directory, which will fail if the directory already exists.
We didn't use this code path much before, but once we start creating CF directories
on CF creation - and not on SSTable creation, that will become our default method.

Use touch_directory instead

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-17 13:08:07 +02:00
Raphael S. Carvalho
e555ad6370 tests: add tests for leveled compaction
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-16 01:57:08 -03:00
Raphael S. Carvalho
06e9836a66 wire up support for leveled compaction strategy
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-16 01:57:04 -03:00
Raphael S. Carvalho
35b75e9b67 adapt compaction procedure to support leveled strategy
Adapt our compaction code to start writing a new sstable if the
one being written reached its maximum size. Leveled strategy works
with that concept. If a strategy other than leveled is being used,
everything will work as before.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-16 01:54:52 -03:00
Raphael S. Carvalho
fbec0d0254 convert LeveledManifest to C++
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-16 01:46:15 -03:00
Raphael S. Carvalho
683e29e0bd tests: add test for range overlap
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:34:58 -03:00
Raphael S. Carvalho
936575efd2 dht: introduce comparator for token
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:34:50 -03:00
Raphael S. Carvalho
24f9c2f85e range: add method to check if two ranges overlap
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:29:54 -03:00
Raphael S. Carvalho
cc2e0dc5d8 sstables: implement function to get sstable level
Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:29:54 -03:00
Raphael S. Carvalho
b8e392e6fe sstables: add function to compare sstable by age
Leveled strategy prefers choosing older level-0 sstables as
candidates.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:29:50 -03:00
Raphael S. Carvalho
1d043936af sstables: add function to compare sstables by first key
Used by leveled strategy to sort a list of sstables with the
same level.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:25:08 -03:00
Raphael S. Carvalho
d4eb09704f sstables: add method to get first and last as decorated keys
Useful for leveled strategy which looks for overlapping sstables
by checking if token range overlaps.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:25:04 -03:00
Raphael S. Carvalho
0d8b4af9a0 import LeveledManifest.java
LeveledManifest implements the Leveled compaction strategy.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-15 19:24:58 -03:00
Avi Kivity
c8cc8a0b0f Merge seastar upstream
* seastar 8207f2c...46fd389 (1):
  > rwlock: drop extranous '}'
2015-10-15 17:19:28 +03:00
Gleb Natapov
f37979eeff Make exception string generation code less verbose 2015-10-15 17:14:51 +03:00
Gleb Natapov
510ed4a1a0 Fix operator<< for std::exception_ptr to receive reference to an object 2015-10-15 17:14:50 +03:00
Avi Kivity
bd5ca7b998 Merge seastar upstream
* seastar a2523ae...8207f2c (3):
  > rwlock: provide lock / unlock semantics
  > with_lock: run a function under a lock
  > rwlock: add documentation to the rwlock module
2015-10-15 17:02:50 +03:00
Calle Wilund
7d93861b28 commitlog_test: test fix
Fixes spurious failures in test_commitlog_discard_completed_segments
* Do explicit sync on all segments to prevent async flushed from keeping
  segements alive.
* Use counter instead of actual file counting to avoid racing with
  pre-allocation of segments
2015-10-15 17:01:11 +03:00
Amnon Heiman
1acd47ddce API: Adding implementation for the stream manager metrics
This adds an implementation for the stream manager metrics.

And the following url will be available:
/stream_manager/metrics/outbound
/stream_manager/metrics/incoming/{peer}
/stream_manager/metrics/incoming
/stream_manager/metrics/outgoing/{peer}
/stream_manager/metrics/outgoing

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-15 16:04:36 +03:00
Amnon Heiman
164ccd0525 API: Adding the stream manager Swagger definition
This adds the swagger definition file for the stream manager. The API is
based on the StreamManagerMBean and the StreamMetrics.
The following commands where added:
get_current_streams
get_current_streams_state
get_all_active_streams_outbound
get_total_incoming_bytes
get_all_total_incoming_bytes
get_total_outgoing_bytes
get_all_total_outgoing_bytes
2015-10-15 16:04:11 +03:00
Pekka Enberg
87fae37c9c dist/docker: Add missing "hostname" package
The Fedora base image has changed so we need to add "hostname" that's
used by the Docker-specific launch script to our image.

Fixes Scylla startup.

Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 13:46:53 +03:00
Avi Kivity
a611a235ee Merge "Flush queue bugfixes" from Calle
"Fixes the crashes in debug mode with the flush queue test, and
simplifies and cleans up the queue itself.

Aforementioned crashes happened due to reordering with the signalling
loop in previous version. A task completing could race with a reordered
loop continuation in who would get to signal and remove an item.

Rewritten to use much simpler promise chaining instead (which also allows
return value to propagate from Pre- to post op), ensuring only one actor
modifies the queue entry."
2015-10-15 13:04:40 +03:00
Avi Kivity
67eb176029 Merge "Invalidate CQL prepared statements on schema changes" from Pekka
"This series converts MigrationSubscriber to C++ and wires it up to
invalidate CQL prepared statements on schema changes that affect them."
2015-10-15 11:44:13 +03:00
Pekka Enberg
e77fbfe709 cql3/query_processor: Wire up migration subscriber
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 09:18:53 +03:00
Pekka Enberg
f659e7bc10 cql3: Convert MigrationSubscriber to C++
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 09:18:52 +03:00
Pekka Enberg
3a30486d30 cql3/query_processor: Implement invalidate_prepared_statement()
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 09:18:52 +03:00
Pekka Enberg
c80deeb6fe cql3/query_processor: Add get_query_processor() helper
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 09:18:52 +03:00
Pekka Enberg
1890d276b9 cql3: Add depends_on_{keyspace|column_family} helper to cql_statement
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-15 09:18:52 +03:00
Calle Wilund
ea0f3504c2 flush_queue_test: Clean up and enhance the test a little
Now also tests:

* Value propagation
* Queue wait
2015-10-15 02:15:24 +02:00
Calle Wilund
cd9f5e38f7 flush_queue: Fix task reordering bug, simplify code, allow value propagation
Previous version dit looping on post execution and signaling of waiters.
This could "race" with an op just finishing if task reordering happened.

This version simplifies the code significantly (and raises the question why
it was not written like this in the first place... Shame on me) by simpy
building a promise-dependency chain between _previous_ queue items and next
instead.

Also, the code now handles propagation of return value from the "Func" pre-op
to the "Post" op, with exceptions automatically handled.
2015-10-15 02:10:26 +02:00
Avi Kivity
849464670c commitlog: make new segments more xfs-friendly
xfs doesn't like writes beyond eof (exactly at eof is fine), and due
to continuation reordering, we sometimes do that.

Fix by pre-truncating the segment to its maximum size.
2015-10-14 17:32:59 +03:00
Calle Wilund
206acd8b5b commitlog: Make reader handle pre-allocated files
Silently ignore, and assume eof if reading zeroed file or chunk header data
Reading entries already deal with this.
2015-10-14 17:32:23 +03:00
Calle Wilund
2729d5dd71 commitlog: ensure file size remains <= max_size
Re-check file size overflow after each cycle() call (new buffer),
otherwise we could write more, in the case we are storing a mutation
larger than current buffer size (current pos + sizeof(mut) < max_size, but
after cycle required by sizeof(mut) > buf_remain, the former might not be
true anymore.
2015-10-14 17:32:22 +03:00
Avi Kivity
6a31daffd6 Merge "Unify logged and unlogged batch write code paths" from Gleb
"Logic duplication bothered me for a long time. This series consolidates both
cases as much as possible."
2015-10-14 17:26:40 +03:00
Gleb Natapov
19770268be storage_proxy: use common write code to write batch log mutations.
Reworks write code further so it can be used to write batch log
mutations.
2015-10-14 17:12:57 +03:00
Gleb Natapov
db49a196da storage_proxy: remove code duplication between logged and unlogged batches
Currently logged batch has most of the logic on unlogged batch
duplicated. This patch rework unlogged batch code in such a way that
it can be reused.
2015-10-14 17:12:57 +03:00
Gleb Natapov
c6644d5721 storage_proxy: remove outdated comment 2015-10-14 17:12:57 +03:00
Gleb Natapov
77ceeee2a8 storage_proxy: move array instead of copy it. 2015-10-14 17:12:57 +03:00
Avi Kivity
77daa7a59f Merge "Flush queue ordering" from Calle
"Adds a small utility queue and through this enforces memtable flush ordering
such that a flush may _run_ unchecked, however the "post" operation may
execute once all "lower numbered" (i.e. lower replay position) post ops
has finished.

This means that:
a.) Callbacks to commitlog are now guaranteed to fulfill ordering criteria
b.) Calling column_family::flush() and waiting for the result will also
     wait for any previously initiated flushes to finish. But not those
     initiated _after_."
2015-10-14 15:13:24 +03:00
Calle Wilund
012ab24469 column_family: Add flush queue object to act as ordering guarantee 2015-10-14 14:07:40 +02:00
Calle Wilund
d8658d4536 flush_queue_test
Small test to verify at least some integrity of the util in question
2015-10-14 14:07:39 +02:00
Calle Wilund
4540036a01 Add "flush_queue" helper structure
Small utility to order operation->post operation
so that the "post" step is guaranteed to only be run
when all "post"-ops for lower valued keys (T) have been completed

This is a generalized utility mainly to be testable.
2015-10-14 14:07:38 +02:00
Avi Kivity
ed2481db7f Merge branch-0.10 2015-10-14 15:03:19 +03:00
Asias He
c58ae5432c storage_service: Fix nodetool info return wrong gossiper status
Before:
$ nodetool info
ID                     : a5adfbbf-cfd8-4c88-ab6b-6a34ccc2857c
Gossip active          : false

After:
$ nodetool info
ID                     : a5adfbbf-cfd8-4c88-ab6b-6a34ccc2857c
Gossip active          : true

Fix #354.
2015-10-14 12:37:51 +03:00
Avi Kivity
1a439f2259 Merge seastar upstream
* seastar 78e3924...a2523ae (7):
  > core: fix pipe unread
  > Merge 'xfs-extents'
  > Merge "separate-dma-alignment"
  > output_stream: wait for stream to be taken out of poller in case final flush returns exception.
  > reactor: Use more widely compatible xfs include
  > readme: Add xfslibs-dev to Ubuntu deps
  > pipe: add unread() operation
2015-10-14 11:49:11 +03:00
Pekka Enberg
921dc9ab9f cql3: Add keyspace() and column_family() to select_statement
Signed-off-by: Pekka Enberg <penberg@scylladb.com>
2015-10-14 09:12:40 +03:00
Avi Kivity
cd6054253c Merge "fix consumer parser" from Raphael
Reviewed-by: Nadav Har'El <nyh@scylladb.com>
2015-10-13 18:53:27 +03:00
Raphael S. Carvalho
d05a5fbeb4 tests: add testcase for bug on consumer parser
problem described by commit:
3926748594

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-13 11:49:57 -03:00
Raphael S. Carvalho
3926748594 sstable: fix consumer parser
The first problem is the while loop around the code that processes prestate.
That's wrong because there may be a need to read more data before continuing
to process a prestate.
The second problem is the code assumption that a prestate will be processed
at once, and then unconditionally process the current state.
Both problems are likely to happen when reading a large buffer because more
than one read may be required.

Signed-off-by: Raphael S. Carvalho <raphaelsc@cloudius-systems.com>
2015-10-13 11:45:10 -03:00
Avi Kivity
c1cfec3e5a dht: mark boot_strapper logger static
Or it violates the ODR and causes link errors.
2015-10-13 16:42:42 +03:00
Tomasz Grabiec
11eb9a6260 range: Fix range::contains()
A range open-ended on both sides should contain all wrapping ranges.

Spotted by Avi.
2015-10-13 12:14:54 +03:00
Nadav Har'El
39f70a043d main: don't warn twice about the same directory
I was mildly annoyed by seeing two warnings about the same directory not
being XFS, when the sstable directory and the commitlog directory are the
same one (I don't know if this is typical, but this is what I do in all
my tests...). So I wrote this trivial patch to make sure not to test the
same directory twice.

Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
2015-10-13 11:23:55 +03:00
Avi Kivity
eed11583cb Merge "Add node support" from Asias
"With this, a new node can stream data from existing nodes when joins the cluster.

I tested with the following:

  1) stat a node 1

  2) insert data into node 1

  3) start node 2

I can see from the logger that data is streamed correctly from node 1
to node 2."
2015-10-13 11:06:11 +03:00
Asias He
cf9d9e2ced boot_strapper: Enable range_streamer code in bootstrap
Add code to actually stream data from other nodes during bootstrap.

I tested with the following:

   1) stat a node 1

   2) insert data into node 1

   3) start node 2

I can see from the logger that data is streamed correctly from node 1
to node 2.
2015-10-13 15:54:18 +08:00
Asias He
0d1e5c3961 boot_strapper: Add debug info for get_bootstrap_tokens
Print the token generated for the node who is bootstrapping.
2015-10-13 15:48:53 +08:00
Asias He
e92a759dad locator: Add debug info for abstract_replication_strategy::get_address_ranges
It is useful to check relations between token and its primary range.
2015-10-13 15:46:36 +08:00
Asias He
dc02d76aee range_streamer: Implement fetch_async
It is used by boot_strapper::bootstrap() in bootstrap process to start
the streaming.
2015-10-13 15:45:56 +08:00
Asias He
887c0a36ec range_streamer: Implement add_ranges
It is used by boot_strapper::bootstrap() in bootstrap process.
2015-10-13 15:45:56 +08:00
Asias He
1c1f9bed09 range_streamer: Implement use_strict_sources_for_ranges 2015-10-13 15:45:55 +08:00
Asias He
43d4e62b5a range_streamer: Implement add_source_filter 2015-10-13 15:45:55 +08:00
Asias He
d47ea88aa8 range_streamer: Implement get_all_ranges_with_strict_sources_for 2015-10-13 15:45:55 +08:00
Asias He
84de936e43 range_streamer: Implement get_all_ranges_with_sources_for 2015-10-13 15:45:55 +08:00
Asias He
944e28cd6c range_streamer: Implement get_range_fetch_map 2015-10-13 15:45:55 +08:00
Asias He
d986a4d875 range_streamer: Add constructor 2015-10-13 15:45:55 +08:00
Asias He
1d6c081766 range_streamer: Add i_source_filter and failure_detector_source_filter
It is used to filter out unwanted node.
2015-10-13 15:45:55 +08:00
Asias He
c8b9a6fa06 dht: Convert RangeStreamer to C++ 2015-10-13 15:45:55 +08:00
Asias He
b95521194e dht: Import dht/RangeStreamer 2015-10-13 15:45:55 +08:00
Asias He
b1c92f377d token_metadata: Add get_pending_ranges
One version returns only the ranges
   std::vector<range<token>>

Another version returns a map
   std::unordered_map<range<token>, std::unordered_set<inet_address>>
which is converted from
   std::unordered_multimap<range<token>, inet_address>

They are needed by token_metadata::pending_endpoints_for,
storage_service::get_all_ranges_with_strict_sources_for and
storage_service::decommission.
2015-10-13 15:45:55 +08:00
Asias He
b860f6a393 token_metadata: Add get_pending_ranges_mm
Helper for get_pending_ranges.
2015-10-13 15:45:55 +08:00
Asias He
c96d826fe0 token_metadata: Introduce _pending_ranges member 2015-10-13 15:45:55 +08:00
Asias He
da072b8814 token_metadata: Remove duplicated sortedTokens
It is implemented already.
2015-10-13 15:45:55 +08:00
Asias He
d820c83141 locator: Add abstract_replication_strategy::get_pending_address_ranges
Given the current token_metadata and the new token which will be
inserted into the ring after bootstrap, calculate the ranges this new
node will be responsible for.

This is needed by boot_strapper::bootstrap().
2015-10-13 15:45:55 +08:00
Asias He
1adb27e283 token_metadata: Add clone_only_token_map
Needed by get_pending_address_ranges.
2015-10-13 15:45:55 +08:00
Asias He
527edd69ae locator: Add abstract_replication_strategy::get_range_addresses
Needed by range_streamer::get_all_ranges_with_sources_for.
2015-10-13 15:45:55 +08:00
Asias He
044dcf43de locator: Add abstract_replication_strategy::get_address_ranges
Needed by get_pending_address_ranges.
2015-10-13 15:45:55 +08:00
Asias He
3d0d02816d token_metadata: Add get_primary_ranges_for and get_primary_range_for
Given tokens, return ranges the tokens present. For example, with t1 and
t2, it returns ranges:

(token before t1, t1]
(token before t2, t2]
2015-10-13 15:45:55 +08:00
Asias He
542b1394d7 token_metadata: Add get_predecessor
It is used to get the previous token of this token in the ring.
2015-10-13 15:45:55 +08:00
Asias He
ddfd417c13 locator: Make calculate_natural_endpoints take extra token_metadata parameter
When adding/removing a node, we need to use a temporary token_metadata
with pending tokens.
2015-10-13 15:45:55 +08:00
Asias He
7959c12073 stream_session: Support column_families is empty case
An empty column_families means to get all the column families.
2015-10-13 15:44:59 +08:00
Tomasz Grabiec
a383f91b68 range: Implement range::contains() which takes another range 2015-10-13 15:44:36 +08:00
Avi Kivity
0498cebc58 Merge seastar upstream
* seastar c2e86d5...78e3924 (2):
  > fix output stream batching
  > rpc: server connection shutdown fix

Adjust transport/server.cc for the demise of output_stream::batch_flush()
2015-10-12 14:00:40 +03:00
Avi Kivity
b8c8473505 Merge seastar upstream
* seastar 1995676...c2e86d5 (3):
  > doc: add Seastar tutorial
  > resource: increase default reserve memory
  > http client: moved http_response_parser.rl from apps/seawreck into http directory
2015-10-12 10:29:10 +03:00
Amnon Heiman
6fd3c81db5 keyspace clean up should be a POST not a GET 2015-10-11 15:51:56 +03:00
Avi Kivity
e252475e67 Merge "locator: Adding EC2Snitch" from Vlad
"This series adds EC2Snich.

Since both GossipingPropertyFileSnitch and EC2SnitchXXX snitches family
are using the same property file it was logical to share the corresponding
code. Most of this series does just that... "
2015-10-11 14:55:26 +03:00
Glauber Costa
f03480c054 avoid exception when processing caching_options
While trying to debug an unrelated bug, I was annoyed by the fact that parsing
caching options keep throwing exceptions all the time. Those exceptions have no
reason to happen: we try to convert the value to a number, and if we fail we
fall back to one of the two blessed strings.

We could just as easily just test for those strings beforehand and avoid all of
that.

While we're on it, the exception message should show the value of "r", not "k".

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-11 14:53:55 +03:00
Avi Kivity
2b87c8c372 build: allow defaulting test binaries not to strip debug information
Useful for continuous integration, which has enough disk space.
2015-10-11 12:25:20 +03:00
Glauber Costa
b2fef14ada do not calculate truncation time independently
Currently, we are calculating truncated_at during truncate() independently for
each shard. It will work if we're lucky, but it is fairly easy to trigger cases
in which each shard will end up with a slightly different time.

The main problem here, is that this time is used as the snapshot name when auto
snapshots are enabled. Previous to my last fixes, this would just generate two
separate directories in this case, which is wrong but not severe.

But after the fix, this means that both shards will wait for one another to
synchronize and this will hang the database.

Fix this by making sure that the truncation time is calculated before
invoke_on_all in all needed places.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-09 17:17:11 +03:00
Vlad Zolotarov
c30c1bb1ec tests: added ec2_snitch_test
Checks the following:
   - That EC2Snich is able to receive the availability zone from EC2.
   - That the resulting DC and RACK values are distributed among all
     shards.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:20 +03:00
Vlad Zolotarov
38f77bbfe5 locator: add ec2_snitch
This snitch will read the EC2 availability zone and set the DC
and RACK as follows:

If availability zone is "us-east-1d", then
DC="us-east" and  RACK="1d".

If cassandra-rackdc.properties contains "dc_suffix" field then
DC will be appended with its value.

For instance if dc_suffix=_1_cassandra, then in the example above

DC=us-east_1_cassandra

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:20 +03:00
Vlad Zolotarov
1d63ec4143 conf: added cassandra-rackdc.properties
This is a configuration file used by GossipingPropertyFileSnitch and
EC2SnitchXXX snitches family.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:20 +03:00
Vlad Zolotarov
afd44a6e08 locator::gossiping_property_file_snitch: initialize i_endpoint_snitch::io_cpu_id() in the constructor
This is just cleaner.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
2febae90c9 locator::production_snitch_base: unify property file parsing facilities
- Move property file parsing code into production_snitch_base class.
   - Make a parsing code more general:
      - Save the parsed keys in the hash table.
      - Check only two types of errors:
         - Repeating keys.
         - Add a set of all supported keys and add the check for a key
           being supported.
   - Added production_snitch_base.cc file.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
2db219f074 locator::gossiping_property_file_snitch: remove extra "namespace locator"
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
0cfdca55f3 locator::gossiping_property_file_snitch: make get_name() public as it should be
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
ba68436f2f locator::gossiping_property_file_snitch: get rid of warn() and err() wrappers
Use logger() accessor instead for a better resemblance with the Origin.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
d196b034e2 locator::snitch_base: Add a default snitch_base::stop() method
Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
2015-10-08 20:57:19 +03:00
Vlad Zolotarov
de6cf8db51 db::config: add get_conf_dir()
This function returns the directory containing the configuration
files. It takes into an account the evironment variables as follows:
   - If SCYLLA_CONF is defines - this is the directory
   - else if SCYLLA_HOME is defines, then $SCYLLA_HOME/conf is the directory
   - else "conf" is a directory, namely the configuration files should be
     looked at ./conf

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>

New in v2:
   - Updated get_conf_dir() description.
2015-10-08 20:57:11 +03:00
Avi Kivity
0c8f906b2d Merge "Fixes for snapshots" from Glauber 2015-10-08 18:21:54 +03:00
Glauber Costa
1549a43823 snapshots: fix json type
We are generating a general object ({}), whereas Cassandra 2.1.x generates an
array ([]). Let's do that as well to avoid surprising parsers.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-08 16:54:51 +02:00
Glauber Costa
cc343eb928 snapshots: handle jsondir creation for empty files case
We still need to write a manifest when there are no files in the snapshot.
But because we have never reached the touch_directory part in the sstables
loop for that case, nobody would have created jsondir in that case.

Since now all the file handling is done in the seal_snapshot phase, we should
just make sure the directory exists before initiating any other disk activity.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-08 16:54:51 +02:00
Glauber Costa
efdfc78c0c snapshots: get rid of empty tables optimization
We currently have one optimization that returns early when there are no tables
to be snapshotted.

However, because of the way we are writing the manifest now, this will cause
the shard that happens to have tables to be waiting forever. So we should get
rid of it. All shards need to pass through the synchronization point.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-08 16:54:51 +02:00
Glauber Costa
0776ca1c52 snapshots: don't hash pending snapshots by snapshot name
If we are hashing more than one CF, the snapshot themselves will all have the same name.
This will cause the files from one of them to spill towards the other when writing the manifest.

The proper hash is the jsondir: that one is unique per manifest file.

Signed-off-by: Glauber Costa <glommer@scylladb.com>
2015-10-08 16:54:51 +02:00
Avi Kivity
e7f58491c3 version: mark master branch as development version 2015-10-08 15:31:50 +03:00
Amnon Heiman
0ec0a5703b API: column family estimated histograms
This patch fix an issue with the read latency estimated historam
implementation and add a call to the estimated number of sstable
histogram.

The later is not yet implemented on the datbase side.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-08 14:59:17 +03:00
Amnon Heiman
6d90eebfb9 column family: Add estimated histogram impl
This patch adds the read and write latency estimated histogram support
and add an estimatd histogram to the number of sstable that were used in
a read.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-08 14:59:17 +03:00
Amnon Heiman
9c16b56b65 estimated_histogram to support sampling
Taking time messurment of an operation can cause peformence degredation,
this patch adds sampling support for the estimated histogram.

It allows to add a sample with a counter that holds what is the actual
total number so far. So the samplling will be counted as multiple
entries in the estimated histogram.

The totatl count of the entries in the histogram will equal the _count
parameter.

Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
2015-10-08 14:59:17 +03:00
374 changed files with 20545 additions and 6153 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
build
build.ninja
cscope.*
/debian/

2
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "seastar"]
path = seastar
url = ../seastar
url = ../scylla-seastar
ignore = dirty
[submodule "swagger-ui"]
path = swagger-ui

76
ORIGIN
View File

@@ -1 +1,77 @@
http://git-wip-us.apache.org/repos/asf/cassandra.git trunk (bf599fb5b062cbcc652da78b7d699e7a01b949ad)
import = bf599fb5b062cbcc652da78b7d699e7a01b949ad
Y = Already in scylla
$ git log --oneline import..cassandra-2.1.11 -- gms/
Y 484e645 Mark node as dead even if already left
d0c166f Add trampled commit back
ba5837e Merge branch 'cassandra-2.0' into cassandra-2.1
718e47f Forgot a damn c/r
a7282e4 Merge branch 'cassandra-2.0' into cassandra-2.1
Y ae4cd69 Print versions for gossip states in gossipinfo.
Y 7fba3d2 Don't mark nodes down before the max local pause interval once paused.
c2142e6 Merge branch 'cassandra-2.0' into cassandra-2.1
ba9a69e checkForEndpointCollision fails for legitimate collisions, finalized list of statuses and nits, CASSANDRA-9765
54470a2 checkForEndpointCollision fails for legitimate collisions, improved version after CR, CASSANDRA-9765
2c9b490 checkForEndpointCollision fails for legitimate collisions, CASSANDRA-9765
4c15970 Merge branch 'cassandra-2.0' into cassandra-2.1
ad8047a ArrivalWindow should use primitives
Y 4012134 Failure detector detects and ignores local pauses
9bcdd0f Merge branch 'cassandra-2.0' into cassandra-2.1
cefaa4e Close incoming connections when MessagingService is stopped
ea1beda Merge branch 'cassandra-2.0' into cassandra-2.1
08dbbd6 Ignore gossip SYNs after shutdown
3c17ac6 Merge branch 'cassandra-2.0' into cassandra-2.1
a64bc43 lists work better when you initialize them
543a899 change list to arraylist
730d4d4 Merge branch 'cassandra-2.0' into cassandra-2.1
e3e2de0 change list to arraylist
f7884c5 Merge branch 'cassandra-2.0' into cassandra-2.1
Y 84b2846 remove redundant state
4f2c372 Merge branch 'cassandra-2.0' into cassandra-2.1
Y b2c62bb Add shutdown gossip state to prevent timeouts during rolling restarts
Y def4835 Add missing follow on fix for 7816 only applied to cassandra-2.1 branch in 763130bdbde2f4cec2e8973bcd5203caf51cc89f
Y 763130b Followup commit for 7816
1376b8e Merge branch 'cassandra-2.0' into cassandra-2.1
Y 2199a87 Fix duplicate up/down messages sent to native clients
136042e Merge branch 'cassandra-2.0' into cassandra-2.1
Y eb9c5bb Improve FD logging when the arrival time is ignored.
$ git log --oneline import..cassandra-2.1.11 -- service/StorageService.java
92c5787 Keep StorageServiceMBean interface stable
6039d0e Fix DC and Rack in nodetool info
a2f0da0 Merge branch 'cassandra-2.0' into cassandra-2.1
c4de752 Follow-up to CASSANDRA-10238
e889ee4 2i key cache load fails
4b1d59e Merge branch 'cassandra-2.0' into cassandra-2.1
257cdaa Fix consolidating racks violating the RF contract
Y 27754c0 refuse to decomission if not in state NORMAL patch by Jan Karlsson and Stefania for CASSANDRA-8741
Y 5bc56c3 refuse to decomission if not in state NORMAL patch by Jan Karlsson and Stefania for CASSANDRA-8741
Y 8f9ca07 Cannot replace token does not exist - DN node removed as Fat Client
c2142e6 Merge branch 'cassandra-2.0' into cassandra-2.1
54470a2 checkForEndpointCollision fails for legitimate collisions, improved version after CR, CASSANDRA-9765
1eccced Handle corrupt files on startup
2c9b490 checkForEndpointCollision fails for legitimate collisions, CASSANDRA-9765
c4b5260 Merge branch 'cassandra-2.0' into cassandra-2.1
Y 52dbc3f Can't transition from write survey to normal mode
9966419 Make rebuild only run one at a time
d693ca1 Merge branch 'cassandra-2.0' into cassandra-2.1
be9eff5 Add option to not validate atoms during scrub
2a4daaf followup fix for 8564
93478ab Wait for anticompaction to finish
9e9846e Fix for harmless exceptions being logged as ERROR
6d06f32 Fix anticompaction blocking ANTI_ENTROPY stage
4f2c372 Merge branch 'cassandra-2.0' into cassandra-2.1
Y b2c62bb Add shutdown gossip state to prevent timeouts during rolling restarts
Y cba1b68 Fix failed bootstrap/replace attempts being persisted in system.peers
f59df28 Allow takeColumnFamilySnapshot to take a list of tables patch by Sachin Jarin; reviewed by Nick Bailey for CASSANDRA-8348
Y ac46747 Fix failed bootstrap/replace attempts being persisted in system.peers
5abab57 Merge branch 'cassandra-2.0' into cassandra-2.1
0ff9c3c Allow reusing snapshot tags across different column families.
f9c57a5 Merge branch 'cassandra-2.0' into cassandra-2.1
Y b296c55 Fix MOVED_NODE client event
bbb3fc7 Merge branch 'cassandra-2.0' into cassandra-2.1
37eb2a0 Fix NPE in nodetool getendpoints with bad ks/cf
f8b43d4 Merge branch 'cassandra-2.0' into cassandra-2.1
e20810c Remove C* specific class from JMX API

View File

@@ -11,13 +11,37 @@ git submodule init
git submodule update --recursive
```
### Building scylla on Fedora
Installing required packages:
### Building and Running Scylla on Fedora
* Installing required packages:
```
sudo yum install yaml-cpp-devel lz4-devel zlib-devel snappy-devel jsoncpp-devel thrift-devel antlr3-tool antlr3-C++-devel libasan libubsan
```
* Build Scylla
```
./configure.py --mode=release --with=scylla --disable-xen
ninja build/release/scylla -j2 # you can use more cpus if you have tons of RAM
```
* Run Scylla
```
./build/release/scylla
```
* run Scylla with one CPU and ./tmp as data directory
```
./build/release/scylla --datadir tmp --commitlog-directory tmp --smp 1
```
* For more run options:
```
./build/release/scylla --help
```
## Building Fedora RPM
As a pre-requisite, you need to install [Mock](https://fedoraproject.org/wiki/Mock) on your machine:
@@ -56,5 +80,17 @@ docker build -t <image-name> .
Run the image with:
```
docker run -i -t <image name>
docker run -p $(hostname -i):9042:9042 -i -t <image name>
```
## Contributing to Scylla
Do not send pull requests.
Send patches to the mailing list address scylladb-dev@googlegroups.com.
Be sure to subscribe.
In order for your patches to be merged, you must sign the Contributor's
License Agreement, protecting your rights and ours. See
http://www.scylladb.com/opensource/cla/.

View File

@@ -1,6 +1,6 @@
#!/bin/sh
VERSION=0.10
VERSION=0.13.2
if test -f version
then

View File

@@ -579,30 +579,6 @@
}
]
},
{
"path":"/column_family/sstables/snapshots_size/{name}",
"operations":[
{
"method":"GET",
"summary":"the size of SSTables in 'snapshots' subdirectory which aren't live anymore",
"type":"double",
"nickname":"true_snapshots_size",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The column family name in keysspace:name format",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
}
]
},
{
"path":"/column_family/metrics/memtable_columns_count/{name}",
"operations":[
@@ -2041,7 +2017,7 @@
]
},
{
"path":"/column_family/metrics/true_snapshots_size/{name}",
"path":"/column_family/metrics/snapshots_size/{name}",
"operations":[
{
"method":"GET",

View File

@@ -15,7 +15,7 @@
"summary":"get List of running compactions",
"type":"array",
"items":{
"type":"jsonmap"
"type":"summary"
},
"nickname":"get_compactions",
"produces":[
@@ -27,16 +27,35 @@
]
},
{
"path":"/compaction_manager/compaction_summary",
"path":"/compaction_manager/compaction_history",
"operations":[
{
"method":"GET",
"summary":"get compaction summary",
"summary":"get List of the compaction history",
"type":"array",
"items":{
"type":"string"
"type":"history"
},
"nickname":"get_compaction_summary",
"nickname":"get_compaction_history",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/compaction_manager/compaction_info",
"operations":[
{
"method":"GET",
"summary":"get a list of all active compaction info",
"type":"array",
"items":{
"type":"compaction_info"
},
"nickname":"get_compaction_info",
"produces":[
"application/json"
],
@@ -155,32 +174,112 @@
}
],
"models":{
"mapper":{
"id":"mapper",
"description":"A key value mapping",
"row_merged":{
"id":"row_merged",
"description":"A row merged information",
"properties":{
"key":{
"type":"string",
"description":"The key"
"type":"int",
"description":"The number of sstable"
},
"value":{
"type":"string",
"description":"The value"
"type":"long",
"description":"The number or row compacted"
}
}
},
"jsonmap":{
"id":"jsonmap",
"description":"A json representation of a map as a list of key value",
"compaction_info" :{
"id": "compaction_info",
"description":"A key value mapping",
"properties":{
"operation_type":{
"type":"string",
"description":"The operation type"
},
"completed":{
"type":"long",
"description":"The current completed"
},
"total":{
"type":"long",
"description":"The total to compact"
},
"unit":{
"type":"string",
"description":"The compacted unit"
}
}
},
"summary":{
"id":"summary",
"description":"A compaction summary object",
"properties":{
"value":{
"type":"array",
"items":{
"type":"mapper"
},
"description":"A list of key, value mapping"
"id":{
"type":"string",
"description":"The UUID"
},
"ks":{
"type":"string",
"description":"The keyspace name"
},
"cf":{
"type":"string",
"description":"The column family name"
},
"completed":{
"type":"long",
"description":"The number of units completed"
},
"total":{
"type":"long",
"description":"The total number of units"
},
"task_type":{
"type":"string",
"description":"The task compaction type"
},
"unit":{
"type":"string",
"description":"The units being used"
}
}
},
"history": {
"id":"history",
"description":"Compaction history information",
"properties":{
"id":{
"type":"string",
"description":"The UUID"
},
"cf":{
"type":"string",
"description":"The column family name"
},
"ks":{
"type":"string",
"description":"The keyspace name"
},
"compacted_at":{
"type":"long",
"description":"The time of compaction"
},
"bytes_in":{
"type":"long",
"description":"Bytes in"
},
"bytes_out":{
"type":"long",
"description":"Bytes out"
},
"rows_merged":{
"type":"array",
"items":{
"type":"row_merged"
},
"description":"The merged rows"
}
}
}
}
}
}

View File

@@ -48,7 +48,10 @@
{
"method":"GET",
"summary":"Get all endpoint states",
"type":"string",
"type":"array",
"items":{
"type":"endpoint_state"
},
"nickname":"get_all_endpoint_states",
"produces":[
"application/json"
@@ -148,6 +151,53 @@
"description": "The value"
}
}
},
"endpoint_state": {
"id": "states",
"description": "Holds an endpoint state",
"properties": {
"addrs": {
"type": "string",
"description": "The endpoint address"
},
"generation": {
"type": "int",
"description": "The heart beat generation"
},
"version": {
"type": "int",
"description": "The heart beat version"
},
"update_time": {
"type": "long",
"description": "The update timestamp"
},
"is_alive": {
"type": "boolean",
"description": "Is the endpoint alive"
},
"application_state" : {
"type":"array",
"items":{
"type":"version_value"
},
"description": "Is the endpoint alive"
}
}
},
"version_value": {
"id": "version_value",
"description": "Holds a version value for an application state",
"properties": {
"application_state": {
"type": "int",
"description": "The application state enum index"
},
"value": {
"type": "string",
"description": "The version value"
}
}
}
}
}

View File

@@ -8,13 +8,16 @@
],
"apis":[
{
"path":"/messaging_service/totaltimeouts",
"path":"/messaging_service/messages/timeout",
"operations":[
{
"method":"GET",
"summary":"Total number of timeouts happened on this node",
"type":"long",
"nickname":"get_totaltimeouts",
"summary":"Get the number of timeout messages",
"type":"array",
"items":{
"type":"message_counter"
},
"nickname":"get_timeout_messages",
"produces":[
"application/json"
],
@@ -25,7 +28,7 @@
]
},
{
"path":"/messaging_service/messages/dropped",
"path":"/messaging_service/messages/dropped_by_ver",
"operations":[
{
"method":"GET",
@@ -34,6 +37,25 @@
"items":{
"type":"verb_counter"
},
"nickname":"get_dropped_messages_by_ver",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/messaging_service/messages/dropped",
"operations":[
{
"method":"GET",
"summary":"Get the number of messages that were dropped before sending",
"type":"array",
"items":{
"type":"message_counter"
},
"nickname":"get_dropped_messages",
"produces":[
"application/json"
@@ -143,6 +165,49 @@
]
}
]
},
{
"path":"/messaging_service/messages/respond_completed",
"operations":[
{
"method":"GET",
"summary":"Get the number of completed respond messages",
"type":"array",
"items":{
"type":"message_counter"
},
"nickname":"get_respond_completed_messages",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/messaging_service/version",
"operations":[
{
"method":"GET",
"summary":"Get the version number",
"type":"int",
"nickname":"get_version",
"produces":[
"application/json"
],
"parameters":[
{
"name":"addr",
"description":"Address",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"query"
}
]
}
]
}
],
"models":{
@@ -150,10 +215,10 @@
"id":"message_counter",
"description":"Holds command counters",
"properties":{
"count":{
"value":{
"type":"long"
},
"ip":{
"key":{
"type":"string"
}
}

View File

@@ -193,8 +193,8 @@
"operations":[
{
"method":"GET",
"summary":"Get the RPC timeout",
"type":"long",
"summary":"Get the RPC timeout in seconds",
"type":"double",
"nickname":"get_rpc_timeout",
"produces":[
"application/json"
@@ -214,10 +214,10 @@
"parameters":[
{
"name":"timeout",
"description":"Timeout in millis",
"description":"Timeout in seconds",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -229,8 +229,8 @@
"operations":[
{
"method":"GET",
"summary":"Get the read RPC timeout",
"type":"long",
"summary":"Get the read RPC timeout in seconds",
"type":"double",
"nickname":"get_read_rpc_timeout",
"produces":[
"application/json"
@@ -250,10 +250,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout_in_millis",
"description":"The timeout in second",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -265,8 +265,8 @@
"operations":[
{
"method":"GET",
"summary":"Get the write RPC timeout",
"type":"long",
"summary":"Get the write RPC timeout in seconds",
"type":"double",
"nickname":"get_write_rpc_timeout",
"produces":[
"application/json"
@@ -286,10 +286,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout in millisecond",
"description":"timeout in seconds",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -301,8 +301,8 @@
"operations":[
{
"method":"GET",
"summary":"Get counter write rpc timeout",
"type":"long",
"summary":"Get counter write rpc timeout in seconds",
"type":"double",
"nickname":"get_counter_write_rpc_timeout",
"produces":[
"application/json"
@@ -322,10 +322,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout in millisecond",
"description":"timeout in seconds",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -337,8 +337,8 @@
"operations":[
{
"method":"GET",
"summary":"Get CAS contention timeout",
"type":"long",
"summary":"Get CAS contention timeout in seconds",
"type":"double",
"nickname":"get_cas_contention_timeout",
"produces":[
"application/json"
@@ -358,10 +358,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout in millisecond",
"description":"timeout in second",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -373,8 +373,8 @@
"operations":[
{
"method":"GET",
"summary":"Get range rpc timeout",
"type":"long",
"summary":"Get range rpc timeout in seconds",
"type":"double",
"nickname":"get_range_rpc_timeout",
"produces":[
"application/json"
@@ -394,10 +394,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout in millisecond",
"description":"timeout in second",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -409,8 +409,8 @@
"operations":[
{
"method":"GET",
"summary":"Get truncate rpc timeout",
"type":"long",
"summary":"Get truncate rpc timeout in seconds",
"type":"double",
"nickname":"get_truncate_rpc_timeout",
"produces":[
"application/json"
@@ -430,10 +430,10 @@
"parameters":[
{
"name":"timeout",
"description":"timeout in millisecond",
"description":"timeout in second",
"required":true,
"allowMultiple":false,
"type":"long",
"type":"double",
"paramType":"query"
}
]
@@ -717,7 +717,7 @@
]
},
{
"path": "/storage_proxy/metrics/read/latency/histogram",
"path": "/storage_proxy/metrics/read/histogram",
"operations": [
{
"method": "GET",
@@ -732,7 +732,7 @@
]
},
{
"path": "/storage_proxy/metrics/range/latency/histogram",
"path": "/storage_proxy/metrics/range/histogram",
"operations": [
{
"method": "GET",
@@ -807,7 +807,7 @@
]
},
{
"path": "/storage_proxy/metrics/write/latency/histogram",
"path": "/storage_proxy/metrics/write/histogram",
"operations": [
{
"method": "GET",
@@ -820,7 +820,103 @@
"parameters": []
}
]
}
},
{
"path":"/storage_proxy/metrics/read/estimated_histogram/",
"operations":[
{
"method":"GET",
"summary":"Get read estimated latency",
"$ref":"#/utils/estimated_histogram",
"nickname":"get_read_estimated_histogram",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_proxy/metrics/read",
"operations":[
{
"method":"GET",
"summary":"Get read latency",
"type":"int",
"nickname":"get_read_latency",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_proxy/metrics/write/estimated_histogram/",
"operations":[
{
"method":"GET",
"summary":"Get write estimated latency",
"$ref":"#/utils/estimated_histogram",
"nickname":"get_write_estimated_histogram",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_proxy/metrics/write",
"operations":[
{
"method":"GET",
"summary":"Get write latency",
"type":"int",
"nickname":"get_write_latency",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_proxy/metrics/range/estimated_histogram/",
"operations":[
{
"method":"GET",
"summary":"Get range estimated latency",
"$ref":"#/utils/estimated_histogram",
"nickname":"get_range_estimated_histogram",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_proxy/metrics/range",
"operations":[
{
"method":"GET",
"summary":"Get range latency",
"type":"int",
"nickname":"get_range_latency",
"produces":[
"application/json"
],
"parameters":[
]
}
]
}
],
"models":{
"mapper_list":{

View File

@@ -290,6 +290,25 @@
}
]
},
{
"path":"/storage_service/describe_ring/",
"operations":[
{
"method":"GET",
"summary":"The TokenRange for a any keyspace",
"type":"array",
"items":{
"type":"token_range"
},
"nickname":"describe_any_ring",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/storage_service/describe_ring/{keyspace}",
"operations":[
@@ -298,9 +317,9 @@
"summary":"The TokenRange for a given keyspace",
"type":"array",
"items":{
"type":"string"
"type":"token_range"
},
"nickname":"describe_ring_jmx",
"nickname":"describe_ring",
"produces":[
"application/json"
],
@@ -311,7 +330,7 @@
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"query"
"paramType":"path"
}
]
}
@@ -609,7 +628,7 @@
"path":"/storage_service/keyspace_cleanup/{keyspace}",
"operations":[
{
"method":"GET",
"method":"POST",
"summary":"Trigger a cleanup of keys on a single keyspace",
"type":"int",
"nickname":"force_keyspace_cleanup",
@@ -890,8 +909,8 @@
],
"parameters":[
{
"name":"token",
"description":"The token to remove",
"name":"host_id",
"description":"Remove the node with host_id from the cluster",
"required":true,
"allowMultiple":false,
"type":"string",
@@ -1969,9 +1988,9 @@
"id":"snapshot",
"description":"Snapshot detail",
"properties":{
"key":{
"ks":{
"type":"string",
"description":"The key snapshot key"
"description":"The key space snapshot key"
},
"cf":{
"type":"string",
@@ -1993,7 +2012,7 @@
"properties":{
"key":{
"type":"string",
"description":"The keyspace"
"description":"The snapshot key"
},
"value":{
"type":"array",
@@ -2003,6 +2022,59 @@
"description":"The column family"
}
}
},
"endpoint_detail":{
"id":"endpoint_detail",
"description":"Endpoint detail",
"properties":{
"host":{
"type":"string",
"description":"The endpoint host"
},
"datacenter":{
"type":"string",
"description":"The endpoint datacenter"
},
"rack":{
"type":"string",
"description":"The endpoint rack"
}
}
},
"token_range":{
"id":"token_range",
"description":"Endpoint range information",
"properties":{
"start_token":{
"type":"string",
"description":"The range start token"
},
"end_token":{
"type":"string",
"description":"The range start token"
},
"endpoints":{
"type":"array",
"items":{
"type":"string"
},
"description":"The endpoints"
},
"rpc_endpoints":{
"type":"array",
"items":{
"type":"string"
},
"description":"The rpc endpoints"
},
"endpoint_details":{
"type":"array",
"items":{
"type":"endpoint_detail"
},
"description":"The endpoint details"
}
}
}
}
}

View File

@@ -25,6 +25,102 @@
]
}
]
},
{
"path":"/stream_manager/metrics/outbound",
"operations":[
{
"method":"GET",
"summary":"Get number of active outbound streams",
"type":"int",
"nickname":"get_all_active_streams_outbound",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/stream_manager/metrics/incoming/{peer}",
"operations":[
{
"method":"GET",
"summary":"Get total incoming bytes",
"type":"int",
"nickname":"get_total_incoming_bytes",
"produces":[
"application/json"
],
"parameters":[
{
"name":"peer",
"description":"The stream peer",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
}
]
},
{
"path":"/stream_manager/metrics/incoming",
"operations":[
{
"method":"GET",
"summary":"Get all total incoming bytes",
"type":"int",
"nickname":"get_all_total_incoming_bytes",
"produces":[
"application/json"
],
"parameters":[
]
}
]
},
{
"path":"/stream_manager/metrics/outgoing/{peer}",
"operations":[
{
"method":"GET",
"summary":"Get total outgoing bytes",
"type":"int",
"nickname":"get_total_outgoing_bytes",
"produces":[
"application/json"
],
"parameters":[
{
"name":"peer",
"description":"The stream peer",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
}
]
},
{
"path":"/stream_manager/metrics/outgoing",
"operations":[
{
"method":"GET",
"summary":"Get all total outgoing bytes",
"type":"int",
"nickname":"get_all_total_outgoing_bytes",
"produces":[
"application/json"
],
"parameters":[
]
}
]
}
],
"models":{

114
api/api-doc/system.json Normal file
View File

@@ -0,0 +1,114 @@
{
"apiVersion":"0.0.1",
"swaggerVersion":"1.2",
"basePath":"{{Protocol}}://{{Host}}",
"resourcePath":"/system",
"produces":[
"application/json"
],
"apis":[
{
"path":"/system/logger",
"operations":[
{
"method":"GET",
"summary":"Get all logger names",
"type":"array",
"items":{
"type":"string"
},
"nickname":"get_all_logger_names",
"produces":[
"application/json"
],
"parameters":[
]
},
{
"method":"POST",
"summary":"Set all logger level",
"type":"void",
"nickname":"set_all_logger_level",
"produces":[
"application/json"
],
"parameters":[
{
"name":"level",
"description":"The new log level",
"required":true,
"allowMultiple":false,
"type":"string",
"enum":[
"error",
"warn",
"info",
"debug",
"trace"
],
"paramType":"query"
}
]
}
]
},
{
"path":"/system/logger/{name}",
"operations":[
{
"method":"GET",
"summary":"Get logger level",
"type":"string",
"nickname":"get_logger_level",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The logger to query about",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
}
]
},
{
"method":"POST",
"summary":"Set logger level",
"type":"void",
"nickname":"set_logger_level",
"produces":[
"application/json"
],
"parameters":[
{
"name":"name",
"description":"The logger to query about",
"required":true,
"allowMultiple":false,
"type":"string",
"paramType":"path"
},
{
"name":"level",
"description":"The new log level",
"required":true,
"allowMultiple":false,
"type":"string",
"enum":[
"error",
"warn",
"info",
"debug",
"trace"
],
"paramType":"query"
}
]
}
]
}
]
}

View File

@@ -38,6 +38,7 @@
#include "hinted_handoff.hh"
#include "http/exception.hh"
#include "stream_manager.hh"
#include "system.hh"
namespace api {
@@ -108,6 +109,10 @@ future<> set_server(http_context& ctx) {
rb->register_function(r, "stream_manager",
"The stream manager API");
set_stream_manager(ctx, r);
rb->register_function(r, "system",
"The system related API");
set_system(ctx, r);
});
}

View File

@@ -128,47 +128,54 @@ inline double pow2(double a) {
return a * a;
}
inline httpd::utils_json::histogram add_histogram(httpd::utils_json::histogram res,
// FIXME: Move to utils::ihistogram::operator+=()
inline utils::ihistogram add_histogram(utils::ihistogram res,
const utils::ihistogram& val) {
if (!res.count._set) {
res = val;
return res;
if (res.count == 0) {
return val;
}
if (val.count == 0) {
return res;
return std::move(res);
}
if (res.min() > val.min) {
if (res.min > val.min) {
res.min = val.min;
}
if (res.max() < val.max) {
if (res.max < val.max) {
res.max = val.max;
}
double ncount = res.count() + val.count;
double ncount = res.count + val.count;
// To get an estimated sum we take the estimated mean
// and multiply it by the true count
res.sum = res.sum() + val.mean * val.count;
double a = res.count()/ncount;
res.sum = res.sum + val.mean * val.count;
double a = res.count/ncount;
double b = val.count/ncount;
double mean = a * res.mean() + b * val.mean;
double mean = a * res.mean + b * val.mean;
res.variance = (res.variance() + pow2(res.mean() - mean) )* a +
res.variance = (res.variance + pow2(res.mean - mean) )* a +
(val.variance + pow2(val.mean -mean))* b;
res.mean = mean;
res.count = res.count() + val.count;
res.count = res.count + val.count;
for (auto i : val.sample) {
res.sample.push(i);
res.sample.push_back(i);
}
return res;
}
inline
httpd::utils_json::histogram to_json(const utils::ihistogram& val) {
httpd::utils_json::histogram h;
h = val;
return h;
}
template<class T, class F>
future<json::json_return_type> sum_histogram_stats(distributed<T>& d, utils::ihistogram F::*f) {
return d.map_reduce0([f](const T& p) {return p.get_stats().*f;}, httpd::utils_json::histogram(),
add_histogram).then([](const httpd::utils_json::histogram& val) {
return make_ready_future<json::json_return_type>(val);
return d.map_reduce0([f](const T& p) {return p.get_stats().*f;}, utils::ihistogram(),
add_histogram).then([](const utils::ihistogram& val) {
return make_ready_future<json::json_return_type>(to_json(val));
});
}

View File

@@ -110,23 +110,25 @@ static future<json::json_return_type> get_cf_histogram(http_context& ctx, const
utils::ihistogram column_family::stats::*f) {
utils::UUID uuid = get_uuid(name, ctx.db.local());
return ctx.db.map_reduce0([f, uuid](const database& p) {return p.find_column_family(uuid).get_stats().*f;},
httpd::utils_json::histogram(),
utils::ihistogram(),
add_histogram)
.then([](const httpd::utils_json::histogram& val) {
return make_ready_future<json::json_return_type>(val);
.then([](const utils::ihistogram& val) {
return make_ready_future<json::json_return_type>(to_json(val));
});
}
static future<json::json_return_type> get_cf_histogram(http_context& ctx, utils::ihistogram column_family::stats::*f) {
std::function<httpd::utils_json::histogram(const database&)> fun = [f] (const database& db) {
httpd::utils_json::histogram res;
std::function<utils::ihistogram(const database&)> fun = [f] (const database& db) {
utils::ihistogram res;
for (auto i : db.get_column_families()) {
res = add_histogram(res, i.second->get_stats().*f);
}
return res;
};
return ctx.db.map(fun).then([](const std::vector<httpd::utils_json::histogram> &res) {
return make_ready_future<json::json_return_type>(res);
return ctx.db.map(fun).then([](const std::vector<utils::ihistogram> &res) {
std::vector<httpd::utils_json::histogram> r;
boost::copy(res | boost::adaptors::transformed(to_json), std::back_inserter(r));
return make_ready_future<json::json_return_type>(r);
});
}
@@ -370,7 +372,7 @@ void set_column_family(http_context& ctx, routes& r) {
});
cf::get_write_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::reads);
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::writes);
});
cf::get_all_write_latency_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
@@ -589,11 +591,16 @@ void set_column_family(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(0);
});
cf::get_true_snapshots_size.set(r, [] (std::unique_ptr<request> req) {
//TBD
// FIXME
//auto id = get_uuid(req->param["name"], ctx.db.local());
return make_ready_future<json::json_return_type>(0);
cf::get_true_snapshots_size.set(r, [&ctx] (std::unique_ptr<request> req) {
auto uuid = get_uuid(req->param["name"], ctx.db.local());
return ctx.db.local().find_column_family(uuid).get_snapshot_details().then([](
const std::unordered_map<sstring, column_family::snapshot_details>& sd) {
int64_t res = 0;
for (auto i : sd) {
res += i.second.total;
}
return make_ready_future<json::json_return_type>(res);
});
});
cf::get_all_true_snapshots_size.set(r, [] (std::unique_ptr<request> req) {
@@ -615,30 +622,29 @@ void set_column_family(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(0);
});
cf::get_row_cache_hit.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
//auto id = get_uuid(req->param["name"], ctx.db.local());
return make_ready_future<json::json_return_type>(0);
cf::get_row_cache_hit.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, req->param["name"], 0, [](const column_family& cf) {
return cf.get_row_cache().stats().hits;
}, std::plus<int64_t>());
});
cf::get_all_row_cache_hit.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
cf::get_all_row_cache_hit.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
return cf.get_row_cache().stats().hits;
}, std::plus<int64_t>());
});
cf::get_row_cache_miss.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
//auto id = get_uuid(req->param["name"], ctx.db.local());
return make_ready_future<json::json_return_type>(0);
cf::get_row_cache_miss.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, req->param["name"], 0, [](const column_family& cf) {
return cf.get_row_cache().stats().misses;
}, std::plus<int64_t>());
});
cf::get_all_row_cache_miss.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
cf::get_all_row_cache_miss.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, 0, [](const column_family& cf) {
return cf.get_row_cache().stats().misses;
}, std::plus<int64_t>());
});
cf::get_cas_prepare.set(r, [] (std::unique_ptr<request> req) {
@@ -662,41 +668,19 @@ void set_column_family(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(0);
});
cf::get_sstables_per_read_histogram.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
//auto id = get_uuid(req->param["name"], ctx.db.local());
std::vector<double> res;
return make_ready_future<json::json_return_type>(res);
cf::get_sstables_per_read_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
return map_reduce_cf(ctx, req->param["name"], sstables::estimated_histogram(0), [](column_family& cf) {
return cf.get_stats().estimated_sstable_per_read;
},
sstables::merge, utils_json::estimated_histogram());
});
cf::get_tombstone_scanned_histogram.set(r, [] (std::unique_ptr<request> req) {
//TBD
// FIXME
//auto id = get_uuid(req->param["name"], ctx.db.local());
httpd::utils_json::histogram res;
res.count = 0;
res.mean = 0;
res.max = 0;
res.min = 0;
res.sum = 0;
res.variance = 0;
return make_ready_future<json::json_return_type>(res);
cf::get_tombstone_scanned_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::tombstone_scanned);
});
cf::get_live_scanned_histogram.set(r, [] (std::unique_ptr<request> req) {
//TBD
// FIXME
//auto id = get_uuid(req->param["name"], ctx.db.local());
//std::vector<double> res;
httpd::utils_json::histogram res;
res.count = 0;
res.mean = 0;
res.max = 0;
res.min = 0;
res.sum = 0;
res.variance = 0;
return make_ready_future<json::json_return_type>(res);
cf::get_live_scanned_histogram.set(r, [&ctx] (std::unique_ptr<request> req) {
return get_cf_histogram(ctx, req->param["name"], &column_family::stats::live_scanned);
});
cf::get_col_update_time_delta_histogram.set(r, [] (std::unique_ptr<request> req) {

View File

@@ -26,11 +26,11 @@ namespace api {
using namespace scollectd;
namespace cm = httpd::compaction_manager_json;
using namespace json;
static future<json::json_return_type> get_cm_stats(http_context& ctx,
int64_t compaction_manager::stats::*f) {
return ctx.db.map_reduce0([&](database& db) {
return ctx.db.map_reduce0([f](database& db) {
return db.get_compaction_manager().get_stats().*f;
}, int64_t(0), std::plus<int64_t>()).then([](const int64_t& res) {
return make_ready_future<json::json_return_type>(res);
@@ -40,27 +40,23 @@ static future<json::json_return_type> get_cm_stats(http_context& ctx,
void set_compaction_manager(http_context& ctx, routes& r) {
cm::get_compactions.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
std::vector<cm::jsonmap> map;
// FIXME
warn(unimplemented::cause::API);
std::vector<cm::summary> map;
return make_ready_future<json::json_return_type>(map);
});
cm::get_compaction_summary.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
std::vector<sstring> res;
return make_ready_future<json::json_return_type>(res);
});
cm::force_user_defined_compaction.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>("");
// FIXME
warn(unimplemented::cause::API);
return make_ready_future<json::json_return_type>(json_void());
});
cm::stop_compaction.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
// FIXME
warn(unimplemented::cause::API);
return make_ready_future<json::json_return_type>("");
});
@@ -81,11 +77,26 @@ void set_compaction_manager(http_context& ctx, routes& r) {
cm::get_bytes_compacted.set(r, [] (std::unique_ptr<request> req) {
//TBD
unimplemented();
// FIXME
warn(unimplemented::cause::API);
return make_ready_future<json::json_return_type>(0);
});
cm::get_compaction_history.set(r, [] (std::unique_ptr<request> req) {
//TBD
// FIXME
warn(unimplemented::cause::API);
std::vector<cm::history> res;
return make_ready_future<json::json_return_type>(res);
});
cm::get_compaction_info.set(r, [] (std::unique_ptr<request> req) {
//TBD
// FIXME
warn(unimplemented::cause::API);
std::vector<cm::compaction_info> res;
return make_ready_future<json::json_return_type>(res);
});
}

View File

@@ -22,15 +22,33 @@
#include "failure_detector.hh"
#include "api/api-doc/failure_detector.json.hh"
#include "gms/failure_detector.hh"
#include "gms/application_state.hh"
#include "gms/gossiper.hh"
namespace api {
namespace fd = httpd::failure_detector_json;
void set_failure_detector(http_context& ctx, routes& r) {
fd::get_all_endpoint_states.set(r, [](std::unique_ptr<request> req) {
return gms::get_all_endpoint_states().then([](const sstring& str) {
return make_ready_future<json::json_return_type>(str);
});
std::vector<fd::endpoint_state> res;
for (auto i : gms::get_local_gossiper().endpoint_state_map) {
fd::endpoint_state val;
val.addrs = boost::lexical_cast<std::string>(i.first);
val.is_alive = i.second.is_alive();
val.generation = i.second.get_heart_beat_state().get_generation();
val.version = i.second.get_heart_beat_state().get_heart_beat_version();
val.update_time = i.second.get_update_timestamp().time_since_epoch().count();
for (auto a : i.second.get_application_state_map()) {
fd::version_value version_val;
// We return the enum index and not it's name to stay compatible to origin
// method that the state index are static but the name can be changed.
version_val.application_state = static_cast<std::underlying_type<gms::application_state>::type>(a.first);
version_val.value = a.second.value;
val.application_state.push(version_val);
}
res.push_back(val);
}
return make_ready_future<json::json_return_type>(res);
});
fd::get_up_endpoint_count.set(r, [](std::unique_ptr<request> req) {

View File

@@ -27,47 +27,43 @@ namespace api {
using namespace json;
void set_gossiper(http_context& ctx, routes& r) {
httpd::gossiper_json::get_down_endpoint.set(r, [](std::unique_ptr<request> req) {
return gms::get_unreachable_members().then([](std::set<gms::inet_address> res) {
return make_ready_future<json::json_return_type>(container_to_vec(res));
});
httpd::gossiper_json::get_down_endpoint.set(r, [] (const_req req) {
auto res = gms::get_local_gossiper().get_unreachable_members();
return container_to_vec(res);
});
httpd::gossiper_json::get_live_endpoint.set(r, [](std::unique_ptr<request> req) {
return gms::get_live_members().then([](std::set<gms::inet_address> res) {
return make_ready_future<json::json_return_type>(container_to_vec(res));
});
httpd::gossiper_json::get_live_endpoint.set(r, [] (const_req req) {
auto res = gms::get_local_gossiper().get_live_members();
return container_to_vec(res);
});
httpd::gossiper_json::get_endpoint_downtime.set(r, [](std::unique_ptr<request> req) {
httpd::gossiper_json::get_endpoint_downtime.set(r, [] (const_req req) {
gms::inet_address ep(req.param["addr"]);
return gms::get_local_gossiper().get_endpoint_downtime(ep);
});
httpd::gossiper_json::get_current_generation_number.set(r, [] (std::unique_ptr<request> req) {
gms::inet_address ep(req->param["addr"]);
return gms::get_endpoint_downtime(ep).then([](int64_t res) {
return gms::get_local_gossiper().get_current_generation_number(ep).then([] (int res) {
return make_ready_future<json::json_return_type>(res);
});
});
httpd::gossiper_json::get_current_generation_number.set(r, [](std::unique_ptr<request> req) {
httpd::gossiper_json::get_current_heart_beat_version.set(r, [] (std::unique_ptr<request> req) {
gms::inet_address ep(req->param["addr"]);
return gms::get_current_generation_number(ep).then([](int res) {
return make_ready_future<json::json_return_type>(res);
});
});
httpd::gossiper_json::get_current_heart_beat_version.set(r, [](std::unique_ptr<request> req) {
gms::inet_address ep(req->param["addr"]);
return gms::get_current_heart_beat_version(ep).then([](int res) {
return gms::get_local_gossiper().get_current_heart_beat_version(ep).then([] (int res) {
return make_ready_future<json::json_return_type>(res);
});
});
httpd::gossiper_json::assassinate_endpoint.set(r, [](std::unique_ptr<request> req) {
if (req->get_query_param("unsafe") != "True") {
return gms::assassinate_endpoint(req->param["addr"]).then([] {
return make_ready_future<json::json_return_type>(json_void());
return gms::get_local_gossiper().assassinate_endpoint(req->param["addr"]).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
}
return gms::unsafe_assassinate_endpoint(req->param["addr"]).then([] {
return make_ready_future<json::json_return_type>(json_void());
return gms::get_local_gossiper().unsafe_assassinate_endpoint(req->param["addr"]).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
}

View File

@@ -41,8 +41,8 @@ std::vector<message_counter> map_to_message_counters(
std::vector<message_counter> res;
for (auto i : map) {
res.push_back(message_counter());
res.back().ip = boost::lexical_cast<sstring>(i.first);
res.back().count = i.second;
res.back().key = boost::lexical_cast<sstring>(i.first);
res.back().value = i.second;
}
return res;
}
@@ -70,12 +70,39 @@ future_json_function get_client_getter(std::function<uint64_t(const shard_info&)
};
}
future_json_function get_server_getter(std::function<uint64_t(const rpc::stats&)> f) {
return [f](std::unique_ptr<request> req) {
using map_type = std::unordered_map<gms::inet_address, uint64_t>;
auto get_shard_map = [f](messaging_service& ms) {
std::unordered_map<gms::inet_address, unsigned long> map;
ms.foreach_server_connection_stats([&map, f] (const rpc::client_info& info, const rpc::stats& stats) mutable {
map[gms::inet_address(net::ipv4_address(info.addr))] = f(stats);
});
return map;
};
return get_messaging_service().map_reduce0(get_shard_map, map_type(), map_sum<map_type>).
then([](map_type&& map) {
return make_ready_future<json::json_return_type>(map_to_message_counters(map));
});
};
}
void set_messaging_service(http_context& ctx, routes& r) {
get_timeout_messages.set(r, get_client_getter([](const shard_info& c) {
return c.get_stats().timeout;
}));
get_sent_messages.set(r, get_client_getter([](const shard_info& c) {
return c.get_stats().sent_messages;
}));
get_dropped_messages.set(r, get_client_getter([](const shard_info& c) {
// We don't have the same drop message mechanism
// as origin has.
// hence we can always return 0
return 0;
}));
get_exception_messages.set(r, get_client_getter([](const shard_info& c) {
return c.get_stats().exception_received;
}));
@@ -84,11 +111,19 @@ void set_messaging_service(http_context& ctx, routes& r) {
return c.get_stats().pending;
}));
get_respond_pending_messages.set(r, get_client_getter([](const shard_info& c) {
return c.get_stats().wait_reply;
get_respond_pending_messages.set(r, get_server_getter([](const rpc::stats& c) {
return c.pending;
}));
get_dropped_messages.set(r, [](std::unique_ptr<request> req) {
get_respond_completed_messages.set(r, get_server_getter([](const rpc::stats& c) {
return c.sent_messages;
}));
get_version.set(r, [](const_req req) {
return net::get_local_messaging_service().get_raw_version(req.get_query_param("addr"));
});
get_dropped_messages_by_ver.set(r, [](std::unique_ptr<request> req) {
shared_ptr<std::vector<uint64_t>> map = make_shared<std::vector<uint64_t>>(num_verb, 0);
return net::get_messaging_service().map_reduce([map](const uint64_t* local_map) mutable {

View File

@@ -23,6 +23,9 @@
#include "service/storage_proxy.hh"
#include "api/api-doc/storage_proxy.json.hh"
#include "api/api-doc/utils.json.hh"
#include "service/storage_service.hh"
#include "db/config.hh"
#include "utils/histogram.hh"
namespace api {
@@ -30,6 +33,23 @@ namespace sp = httpd::storage_proxy_json;
using proxy = service::storage_proxy;
using namespace json;
static future<json::json_return_type> sum_estimated_histogram(http_context& ctx, sstables::estimated_histogram proxy::stats::*f) {
return ctx.sp.map_reduce0([f](const proxy& p) {return p.get_stats().*f;}, sstables::estimated_histogram(),
sstables::merge).then([](const sstables::estimated_histogram& val) {
utils_json::estimated_histogram res;
res = val;
return make_ready_future<json::json_return_type>(res);
});
}
static future<json::json_return_type> total_latency(http_context& ctx, utils::ihistogram proxy::stats::*f) {
return ctx.sp.map_reduce0([f](const proxy& p) {return (p.get_stats().*f).mean * (p.get_stats().*f).count;}, 0.0,
std::plus<double>()).then([](double val) {
int64_t res = val;
return make_ready_future<json::json_return_type>(res);
});
}
void set_storage_proxy(http_context& ctx, routes& r) {
sp::get_total_hints.set(r, [](std::unique_ptr<request> req) {
//TBD
@@ -39,7 +59,9 @@ void set_storage_proxy(http_context& ctx, routes& r) {
sp::get_hinted_handoff_enabled.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
// FIXME
// hinted handoff is not supported currently,
// so we should return false
return make_ready_future<json::json_return_type>(false);
});
@@ -96,10 +118,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(0);
});
sp::get_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(1);
sp::get_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().request_timeout_in_ms()/1000.0;
});
sp::set_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -109,10 +129,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_read_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_read_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().read_request_timeout_in_ms()/1000.0;
});
sp::set_read_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -122,10 +140,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_write_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_write_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().write_request_timeout_in_ms()/1000.0;
});
sp::set_write_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -135,11 +151,10 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_counter_write_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_counter_write_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().counter_write_request_timeout_in_ms()/1000.0;
});
sp::set_counter_write_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
@@ -147,10 +162,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_cas_contention_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_cas_contention_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().cas_contention_timeout_in_ms()/1000.0;
});
sp::set_cas_contention_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -160,10 +173,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_range_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_range_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().range_request_timeout_in_ms()/1000.0;
});
sp::set_range_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -173,10 +184,8 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_truncate_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_truncate_rpc_timeout.set(r, [&ctx](const_req req) {
return ctx.db.local().get_config().truncate_request_timeout_in_ms()/1000.0;
});
sp::set_truncate_rpc_timeout.set(r, [](std::unique_ptr<request> req) {
@@ -192,28 +201,28 @@ void set_storage_proxy(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
sp::get_read_repair_attempted.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_read_repair_attempted.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_stats(ctx.sp, &proxy::stats::read_repair_attempts);
});
sp::get_read_repair_repaired_blocking.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_read_repair_repaired_blocking.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_stats(ctx.sp, &proxy::stats::read_repair_repaired_blocking);
});
sp::get_read_repair_repaired_background.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
sp::get_read_repair_repaired_background.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_stats(ctx.sp, &proxy::stats::read_repair_repaired_background);
});
sp::get_schema_versions.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
// FIXME
// describe_schema_versions is not implemented yet
// this is a work around
std::vector<sp::mapper_list> res;
sp::mapper_list entry;
entry.key = boost::lexical_cast<std::string>(utils::fb_utilities::get_broadcast_address());
entry.value.push(service::get_local_storage_service().get_schema_version());
res.push_back(entry);
return make_ready_future<json::json_return_type>(res);
});
@@ -316,6 +325,29 @@ void set_storage_proxy(http_context& ctx, routes& r) {
sp::get_read_metrics_latency_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_histogram_stats(ctx.sp, &proxy::stats::read);
});
sp::get_read_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_estimated_histogram(ctx, &proxy::stats::estimated_read);
});
sp::get_read_latency.set(r, [&ctx](std::unique_ptr<request> req) {
return total_latency(ctx, &proxy::stats::read);
});
sp::get_write_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_estimated_histogram(ctx, &proxy::stats::estimated_write);
});
sp::get_write_latency.set(r, [&ctx](std::unique_ptr<request> req) {
return total_latency(ctx, &proxy::stats::write);
});
sp::get_range_estimated_histogram.set(r, [&ctx](std::unique_ptr<request> req) {
return sum_histogram_stats(ctx.sp, &proxy::stats::read);
});
sp::get_range_latency.set(r, [&ctx](std::unique_ptr<request> req) {
return total_latency(ctx, &proxy::stats::range);
});
}
}

View File

@@ -30,8 +30,6 @@
#include "repair/repair.hh"
#include "locator/snitch_base.hh"
#include "column_family.hh"
#include <unordered_map>
#include "utils/fb_utilities.hh"
namespace api {
@@ -45,6 +43,29 @@ static sstring validate_keyspace(http_context& ctx, const parameters& param) {
throw bad_param_exception("Keyspace " + param["keyspace"] + " Does not exist");
}
static std::vector<ss::token_range> describe_ring(const sstring& keyspace) {
std::vector<ss::token_range> res;
for (auto d : service::get_local_storage_service().describe_ring(keyspace)) {
ss::token_range r;
r.start_token = d._start_token;
r.end_token = d._end_token;
r.endpoints = d._endpoints;
r.rpc_endpoints = d._rpc_endpoints;
for (auto det : d._endpoint_details) {
ss::endpoint_detail ed;
ed.host = det._host;
ed.datacenter = det._datacenter;
if (det._rack != "") {
ed.rack = det._rack;
}
r.endpoint_details.push(ed);
}
res.push_back(r);
}
return res;
}
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) {
@@ -52,28 +73,25 @@ void set_storage_service(http_context& ctx, routes& r) {
});
});
ss::get_tokens.set(r, [](std::unique_ptr<request> req) {
return service::sorted_tokens().then([](const std::vector<dht::token>& tokens) {
return make_ready_future<json::json_return_type>(container_to_vec(tokens));
});
ss::get_tokens.set(r, [] (const_req req) {
auto tokens = service::get_local_storage_service().get_token_metadata().sorted_tokens();
return container_to_vec(tokens);
});
ss::get_node_tokens.set(r, [](std::unique_ptr<request> req) {
gms::inet_address addr(req->param["endpoint"]);
return service::get_tokens(addr).then([](const std::vector<dht::token>& tokens) {
return make_ready_future<json::json_return_type>(container_to_vec(tokens));
});
ss::get_node_tokens.set(r, [] (const_req req) {
gms::inet_address addr(req.param["endpoint"]);
auto tokens = service::get_local_storage_service().get_token_metadata().get_tokens(addr);
return container_to_vec(tokens);
});
ss::get_commitlog.set(r, [&ctx](const_req req) {
return ctx.db.local().commitlog()->active_config().commit_log_location;
});
ss::get_token_endpoint.set(r, [](std::unique_ptr<request> req) {
return service::get_token_to_endpoint().then([] (const std::map<dht::token, gms::inet_address>& tokens){
std::vector<storage_service_json::mapper> res;
return make_ready_future<json::json_return_type>(map_to_key_value(tokens, res));
});
ss::get_token_endpoint.set(r, [] (const_req req) {
auto token_to_ep = service::get_local_storage_service().get_token_metadata().get_token_to_endpoint();
std::vector<storage_service_json::mapper> res;
return map_to_key_value(token_to_ep, res);
});
ss::get_leaving_nodes.set(r, [](const_req req) {
@@ -130,12 +148,13 @@ void set_storage_service(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(res);
});
ss::describe_ring_jmx.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto keyspace = validate_keyspace(ctx, req->param);
std::vector<sstring> res;
return make_ready_future<json::json_return_type>(res);
ss::describe_any_ring.set(r, [&ctx](const_req req) {
return describe_ring("");
});
ss::describe_ring.set(r, [&ctx](const_req req) {
auto keyspace = validate_keyspace(ctx, req.param);
return describe_ring(keyspace);
});
ss::get_host_id_map.set(r, [](const_req req) {
@@ -148,74 +167,82 @@ void set_storage_service(http_context& ctx, routes& r) {
return get_cf_stats(ctx, &column_family::stats::live_disk_space_used);
});
ss::get_load_map.set(r, [&ctx](std::unique_ptr<request> req) {
// FIXME
// The function should return a mapping between inet address
// and the load (disk space used)
// in origin the implementation is based on the load broadcast
// we do not currently support.
// As a workaround, the local load is calculated (this part is similar
// to origin) and a map with a single entry is return.
return ctx.db.map_reduce0([](database& db) {
int64_t res = 0;
for (auto i : db.get_column_families()) {
res += i.second->get_stats().live_disk_space_used;
}
return res;
}, 0, std::plus<int64_t>()).then([](int64_t size) {
ss::get_load_map.set(r, [] (std::unique_ptr<request> req) {
return service::get_local_storage_service().get_load_map().then([] (auto&& load_map) {
std::vector<ss::mapper> res;
std::unordered_map<gms::inet_address, double> load_map;
load_map[utils::fb_utilities::get_broadcast_address()] = size;
return make_ready_future<json::json_return_type>(map_to_key_value(load_map, res));
});
});
ss::get_current_generation_number.set(r, [](std::unique_ptr<request> req) {
gms::inet_address ep(utils::fb_utilities::get_broadcast_address());
return gms::get_current_generation_number(ep).then([](int res) {
return gms::get_local_gossiper().get_current_generation_number(ep).then([](int res) {
return make_ready_future<json::json_return_type>(res);
});
});
ss::get_natural_endpoints.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto keyspace = validate_keyspace(ctx, req->param);
auto column_family = req->get_query_param("cf");
auto key = req->get_query_param("key");
std::vector<sstring> res;
return make_ready_future<json::json_return_type>(res);
ss::get_natural_endpoints.set(r, [&ctx](const_req req) {
auto keyspace = validate_keyspace(ctx, req.param);
return container_to_vec(service::get_local_storage_service().get_natural_endpoints(keyspace, req.get_query_param("cf"),
req.get_query_param("key")));
});
ss::get_snapshot_details.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
std::vector<ss::snapshots> res;
return make_ready_future<json::json_return_type>(res);
return service::get_local_storage_service().get_snapshot_details().then([] (auto result) {
std::vector<ss::snapshots> res;
for (auto& map: result) {
ss::snapshots all_snapshots;
all_snapshots.key = map.first;
std::vector<ss::snapshot> snapshot;
for (auto& cf: map.second) {
ss::snapshot s;
s.ks = cf.ks;
s.cf = cf.cf;
s.live = cf.live;
s.total = cf.total;
snapshot.push_back(std::move(s));
}
all_snapshots.value = std::move(snapshot);
res.push_back(std::move(all_snapshots));
}
return make_ready_future<json::json_return_type>(std::move(res));
});
});
ss::take_snapshot.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto tag = req->get_query_param("tag");
auto keyname = req->get_query_param("kn");
auto column_family = req->get_query_param("cf");
return make_ready_future<json::json_return_type>(json_void());
std::vector<sstring> keynames = split(req->get_query_param("kn"), ",");
auto resp = make_ready_future<>();
if (column_family.empty()) {
resp = service::get_local_storage_service().take_snapshot(tag, keynames);
} else {
if (keynames.size() > 1) {
throw httpd::bad_param_exception("Only one keyspace allowed when specifying a column family");
}
resp = service::get_local_storage_service().take_column_family_snapshot(keynames[0], column_family, tag);
}
return resp.then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
ss::del_snapshot.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto tag = req->get_query_param("tag");
auto keyname = req->get_query_param("kn");
return make_ready_future<json::json_return_type>(json_void());
std::vector<sstring> keynames = split(req->get_query_param("kn"), ",");
return service::get_local_storage_service().clear_snapshot(tag, keynames).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
ss::true_snapshots_size.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(0);
return service::get_local_storage_service().true_snapshots_size().then([] (int64_t size) {
return make_ready_future<json::json_return_type>(size);
});
});
ss::force_keyspace_compaction.set(r, [&ctx](std::unique_ptr<request> req) {
@@ -239,10 +266,14 @@ void set_storage_service(http_context& ctx, routes& r) {
ss::force_keyspace_cleanup.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
// FIXME
// the nodetool clean up is used in many tests
// this workaround willl let it work until
// a cleanup is implemented
warn(unimplemented::cause::API);
auto keyspace = validate_keyspace(ctx, req->param);
auto column_family = req->get_query_param("cf");
return make_ready_future<json::json_return_type>(json_void());
return make_ready_future<json::json_return_type>(0);
});
ss::scrub.set(r, [&ctx](std::unique_ptr<request> req) {
@@ -330,17 +361,16 @@ void set_storage_service(http_context& ctx, routes& r) {
});
});
ss::move.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
ss::move.set(r, [] (std::unique_ptr<request> req) {
auto new_token = req->get_query_param("new_token");
return make_ready_future<json::json_return_type>(json_void());
return service::get_local_storage_service().move(new_token).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
ss::remove_node.set(r, [](std::unique_ptr<request> req) {
// FIXME: This api is incorrect. remove_node takes a host id string parameter instead of token.
auto host_id = req->get_query_param("token");
return service::get_local_storage_service().remove_node(std::move(host_id)).then([] {
auto host_id = req->get_query_param("host_id");
return service::get_local_storage_service().remove_node(host_id).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
@@ -440,8 +470,10 @@ void set_storage_service(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
ss::is_initialized.set(r, [](const_req req) {
return service::get_local_storage_service().is_initialized();
ss::is_initialized.set(r, [](std::unique_ptr<request> req) {
return service::get_local_storage_service().is_initialized().then([] (bool initialized) {
return make_ready_future<json::json_return_type>(initialized);
});
});
ss::stop_rpc_server.set(r, [](std::unique_ptr<request> req) {
@@ -456,8 +488,10 @@ void set_storage_service(http_context& ctx, routes& r) {
});
});
ss::is_rpc_server_running.set(r, [](const_req req) {
return service::get_local_storage_service().is_rpc_server_running();
ss::is_rpc_server_running.set(r, [] (std::unique_ptr<request> req) {
return service::get_local_storage_service().is_rpc_server_running().then([] (bool running) {
return make_ready_future<json::json_return_type>(running);
});
});
ss::start_native_transport.set(r, [](std::unique_ptr<request> req) {
@@ -472,8 +506,10 @@ void set_storage_service(http_context& ctx, routes& r) {
});
});
ss::is_native_transport_running.set(r, [](const_req req) {
return service::get_local_storage_service().is_native_transport_running();
ss::is_native_transport_running.set(r, [] (std::unique_ptr<request> req) {
return service::get_local_storage_service().is_native_transport_running().then([] (bool running) {
return make_ready_future<json::json_return_type>(running);
});
});
ss::join_ring.set(r, [](std::unique_ptr<request> req) {
@@ -482,8 +518,10 @@ void set_storage_service(http_context& ctx, routes& r) {
});
});
ss::is_joined.set(r, [](const_req req) {
return service::get_local_storage_service().is_joined();
ss::is_joined.set(r, [] (std::unique_ptr<request> req) {
return service::get_local_storage_service().is_joined().then([] (bool is_joined) {
return make_ready_future<json::json_return_type>(is_joined);
});
});
ss::set_stream_throughput_mb_per_sec.set(r, [](std::unique_ptr<request> req) {
@@ -575,11 +613,16 @@ void set_storage_service(http_context& ctx, routes& r) {
});
ss::load_new_ss_tables.set(r, [&ctx](std::unique_ptr<request> req) {
//TBD
unimplemented();
auto keyspace = validate_keyspace(ctx, req->param);
auto column_family = req->get_query_param("cf");
return make_ready_future<json::json_return_type>(json_void());
auto ks = validate_keyspace(ctx, req->param);
auto cf = req->get_query_param("cf");
// No need to add the keyspace, since all we want is to avoid always sending this to the same
// CPU. Even then I am being overzealous here. This is not something that happens all the time.
auto coordinator = std::hash<sstring>()(cf) % smp::count;
return service::get_storage_service().invoke_on(coordinator, [ks = std::move(ks), cf = std::move(cf)] (service::storage_service& s) {
return s.load_new_sstables(ks, cf);
}).then([] {
return make_ready_future<json::json_return_type>(json_void());
});
});
ss::sample_key_range.set(r, [](std::unique_ptr<request> req) {
@@ -631,16 +674,12 @@ void set_storage_service(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(json_void());
});
ss::get_cluster_name.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(json_void());
ss::get_cluster_name.set(r, [](const_req req) {
return gms::get_local_gossiper().get_cluster_name();
});
ss::get_partitioner_name.set(r, [](std::unique_ptr<request> req) {
//TBD
unimplemented();
return make_ready_future<json::json_return_type>(json_void());
ss::get_partitioner_name.set(r, [](const_req req) {
return gms::get_local_gossiper().get_partitioner_name();
});
ss::get_tombstone_warn_threshold.set(r, [](std::unique_ptr<request> req) {
@@ -711,17 +750,19 @@ void set_storage_service(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(0);
});
ss::get_ownership.set(r, [](const_req req) {
auto tokens = service::get_local_storage_service().get_ownership();
std::vector<storage_service_json::mapper> res;
return map_to_key_value(tokens, res);
ss::get_ownership.set(r, [] (std::unique_ptr<request> req) {
return service::get_local_storage_service().get_ownership().then([] (auto&& ownership) {
std::vector<storage_service_json::mapper> res;
return make_ready_future<json::json_return_type>(map_to_key_value(ownership, res));
});
});
ss::get_effective_ownership.set(r, [&ctx](const_req req) {
auto tokens = service::get_local_storage_service().effective_ownership(
(req.param["keyspace"] == "null")? "" : validate_keyspace(ctx, req.param));
std::vector<storage_service_json::mapper> res;
return map_to_key_value(tokens, res);
ss::get_effective_ownership.set(r, [&ctx] (std::unique_ptr<request> req) {
auto keyspace_name = req->param["keyspace"] == "null" ? "" : validate_keyspace(ctx, req->param);
return service::get_local_storage_service().effective_ownership(keyspace_name).then([] (auto&& ownership) {
std::vector<storage_service_json::mapper> res;
return make_ready_future<json::json_return_type>(map_to_key_value(ownership, res));
});
});
}

View File

@@ -24,6 +24,7 @@
#include "streaming/stream_result_future.hh"
#include "api/api-doc/stream_manager.json.hh"
#include <vector>
#include "gms/gossiper.hh"
namespace api {
@@ -97,6 +98,80 @@ void set_stream_manager(http_context& ctx, routes& r) {
return make_ready_future<json::json_return_type>(res);
});
});
hs::get_all_active_streams_outbound.set(r, [](std::unique_ptr<request> req) {
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
return stream.get_initiated_streams().size();
}, 0, std::plus<int64_t>()).then([](int64_t res) {
return make_ready_future<json::json_return_type>(res);
});
});
hs::get_total_incoming_bytes.set(r, [](std::unique_ptr<request> req) {
gms::inet_address ep(req->param["peer"]);
utils::UUID plan_id = gms::get_local_gossiper().get_host_id(ep);
return streaming::get_stream_manager().map_reduce0([plan_id](streaming::stream_manager& stream) {
int64_t res = 0;
streaming::stream_result_future* s = stream.get_receiving_stream(plan_id).get();
if (s != nullptr) {
for (auto si: s->get_coordinator()->get_all_session_info()) {
res += si.get_total_size_received();
}
}
return res;
}, 0, std::plus<int64_t>()).then([](int64_t res) {
return make_ready_future<json::json_return_type>(res);
});
});
hs::get_all_total_incoming_bytes.set(r, [](std::unique_ptr<request> req) {
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
int64_t res = 0;
for (auto s : stream.get_receiving_streams()) {
if (s.second.get() != nullptr) {
for (auto si: s.second.get()->get_coordinator()->get_all_session_info()) {
res += si.get_total_size_received();
}
}
}
return res;
}, 0, std::plus<int64_t>()).then([](int64_t res) {
return make_ready_future<json::json_return_type>(res);
});
});
hs::get_total_outgoing_bytes.set(r, [](std::unique_ptr<request> req) {
gms::inet_address ep(req->param["peer"]);
utils::UUID plan_id = gms::get_local_gossiper().get_host_id(ep);
return streaming::get_stream_manager().map_reduce0([plan_id](streaming::stream_manager& stream) {
int64_t res = 0;
streaming::stream_result_future* s = stream.get_sending_stream(plan_id).get();
if (s != nullptr) {
for (auto si: s->get_coordinator()->get_all_session_info()) {
res += si.get_total_size_received();
}
}
return res;
}, 0, std::plus<int64_t>()).then([](int64_t res) {
return make_ready_future<json::json_return_type>(res);
});
});
hs::get_all_total_outgoing_bytes.set(r, [](std::unique_ptr<request> req) {
return streaming::get_stream_manager().map_reduce0([](streaming::stream_manager& stream) {
int64_t res = 0;
for (auto s : stream.get_initiated_streams()) {
if (s.second.get() != nullptr) {
for (auto si: s.second.get()->get_coordinator()->get_all_session_info()) {
res += si.get_total_size_received();
}
}
}
return res;
}, 0, std::plus<int64_t>()).then([](int64_t res) {
return make_ready_future<json::json_return_type>(res);
});
});
}
}

70
api/system.cc Normal file
View File

@@ -0,0 +1,70 @@
/*
* Copyright 2015 Cloudius Systems
*/
/*
* 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 "api/api-doc/system.json.hh"
#include "api/api.hh"
#include "http/exception.hh"
#include "log.hh"
namespace api {
namespace hs = httpd::system_json;
void set_system(http_context& ctx, routes& r) {
hs::get_all_logger_names.set(r, [](const_req req) {
return logging::logger_registry().get_all_logger_names();
});
hs::set_all_logger_level.set(r, [](const_req req) {
try {
logging::log_level level = boost::lexical_cast<logging::log_level>(std::string(req.get_query_param("level")));
logging::logger_registry().set_all_loggers_level(level);
} catch (boost::bad_lexical_cast& e) {
throw bad_param_exception("Unknown logging level " + req.get_query_param("level"));
}
return json::json_void();
});
hs::get_logger_level.set(r, [](const_req req) {
try {
return logging::level_name(logging::logger_registry().get_logger_level(req.param["name"]));
} catch (std::out_of_range& e) {
throw bad_param_exception("Unknown logger name " + req.param["name"]);
}
// just to keep the compiler happy
return sstring();
});
hs::set_logger_level.set(r, [](const_req req) {
try {
logging::log_level level = boost::lexical_cast<logging::log_level>(std::string(req.get_query_param("level")));
logging::logger_registry().set_logger_level(req.param["name"], level);
} catch (std::out_of_range& e) {
throw bad_param_exception("Unknown logger name " + req.param["name"]);
} catch (boost::bad_lexical_cast& e) {
throw bad_param_exception("Unknown logging level " + req.get_query_param("level"));
}
return json::json_void();
});
}
}

30
api/system.hh Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright 2015 Cloudius Systems
*/
/*
* 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 "api.hh"
namespace api {
void set_system(http_context& ctx, routes& r);
}

View File

@@ -234,6 +234,8 @@ public:
friend std::ostream& operator<<(std::ostream& os, const atomic_cell& ac);
};
class collection_mutation_view;
// Represents a mutation of a collection. Actual format is determined by collection type,
// and is:
// set: list of atomic_cell
@@ -241,20 +243,30 @@ public:
// list: tbd, probably ugly
class collection_mutation {
public:
struct view {
bytes_view data;
bytes_view serialize() const { return data; }
static view from_bytes(bytes_view v) { return { v }; }
};
struct one {
managed_bytes data;
one() {}
one(managed_bytes b) : data(std::move(b)) {}
one(view v) : data(v.data) {}
operator view() const { return { data }; }
};
managed_bytes data;
collection_mutation() {}
collection_mutation(managed_bytes b) : data(std::move(b)) {}
collection_mutation(collection_mutation_view v);
operator collection_mutation_view() const;
};
class collection_mutation_view {
public:
bytes_view data;
bytes_view serialize() const { return data; }
static collection_mutation_view from_bytes(bytes_view v) { return { v }; }
};
inline
collection_mutation::collection_mutation(collection_mutation_view v)
: data(v.data) {
}
inline
collection_mutation::operator collection_mutation_view() const {
return { data };
}
namespace db {
template<typename T>
class serializer;
@@ -274,15 +286,15 @@ public:
atomic_cell_or_collection(atomic_cell ac) : _data(std::move(ac._data)) {}
static atomic_cell_or_collection from_atomic_cell(atomic_cell data) { return { std::move(data._data) }; }
atomic_cell_view as_atomic_cell() const { return atomic_cell_view::from_bytes(_data); }
atomic_cell_or_collection(collection_mutation::one cm) : _data(std::move(cm.data)) {}
atomic_cell_or_collection(collection_mutation cm) : _data(std::move(cm.data)) {}
explicit operator bool() const {
return !_data.empty();
}
static atomic_cell_or_collection from_collection_mutation(collection_mutation::one data) {
static atomic_cell_or_collection from_collection_mutation(collection_mutation data) {
return std::move(data.data);
}
collection_mutation::view as_collection_mutation() const {
return collection_mutation::view{_data};
collection_mutation_view as_collection_mutation() const {
return collection_mutation_view{_data};
}
bytes_view serialize() const {
return _data;

View File

@@ -33,8 +33,10 @@
*
*/
class bytes_ostream {
public:
using size_type = bytes::size_type;
using value_type = bytes::value_type;
private:
static_assert(sizeof(value_type) == 1, "value_type is assumed to be one byte long");
struct chunk {
// FIXME: group fragment pointers to reduce pointer chasing when packetizing
@@ -117,13 +119,13 @@ private:
};
}
public:
bytes_ostream()
bytes_ostream() noexcept
: _begin()
, _current(nullptr)
, _size(0)
{ }
bytes_ostream(bytes_ostream&& o)
bytes_ostream(bytes_ostream&& o) noexcept
: _begin(std::move(o._begin))
, _current(o._current)
, _size(o._size)
@@ -148,7 +150,7 @@ public:
return *this;
}
bytes_ostream& operator=(bytes_ostream&& o) {
bytes_ostream& operator=(bytes_ostream&& o) noexcept {
_size = o._size;
_begin = std::move(o._begin);
_current = o._current;

View File

@@ -43,11 +43,13 @@ class caching_options {
throw exceptions::configuration_exception("Invalid key value: " + k);
}
try {
boost::lexical_cast<unsigned long>(r);
} catch (boost::bad_lexical_cast& e) {
if ((r != "ALL") && (r != "NONE")) {
throw exceptions::configuration_exception("Invalid key value: " + k);
if ((r == "ALL") || (r == "NONE")) {
return;
} else {
try {
boost::lexical_cast<unsigned long>(r);
} catch (boost::bad_lexical_cast& e) {
throw exceptions::configuration_exception("Invalid key value: " + r);
}
}
}

View File

@@ -29,7 +29,8 @@ enum class compaction_strategy_type {
null,
major,
size_tiered,
// FIXME: Add support to LevelTiered, and DateTiered.
leveled,
// FIXME: Add support to DateTiered.
};
class compaction_strategy_impl;
@@ -54,20 +55,26 @@ public:
return "MajorCompactionStrategy";
case compaction_strategy_type::size_tiered:
return "SizeTieredCompactionStrategy";
case compaction_strategy_type::leveled:
return "LeveledCompactionStrategy";
default:
throw std::runtime_error("Invalid Compaction Strategy");
}
}
static compaction_strategy_type type(const sstring& name) {
if (name == "NullCompactionStrategy") {
auto pos = name.find("org.apache.cassandra.db.compaction.");
sstring short_name = (pos == sstring::npos) ? name : name.substr(pos + 35);
if (short_name == "NullCompactionStrategy") {
return compaction_strategy_type::null;
} else if (name == "MajorCompactionStrategy") {
} else if (short_name == "MajorCompactionStrategy") {
return compaction_strategy_type::major;
} else if (name == "SizeTieredCompactionStrategy") {
} else if (short_name == "SizeTieredCompactionStrategy") {
return compaction_strategy_type::size_tiered;
} else if (short_name == "LeveledCompactionStrategy") {
return compaction_strategy_type::leveled;
} else {
throw exceptions::configuration_exception(sprint("Unable to find compaction strategy class 'org.apache.cassandra.db.compaction.%s", name));
throw exceptions::configuration_exception(sprint("Unable to find compaction strategy class '%s'", name));
}
}

View File

@@ -159,7 +159,7 @@ public:
}
return ::serialize_value(*this, values);
}
bytes serialize_value_deep(const std::vector<boost::any>& values) {
bytes serialize_value_deep(const std::vector<data_value>& values) {
// TODO: Optimize
std::vector<bytes> partial;
partial.reserve(values.size());

View File

@@ -0,0 +1,15 @@
#
# cassandra-rackdc.properties
#
# The lines may include white spaces at the beginning and the end.
# The rack and data center names may also include white spaces.
# All trailing and leading white spaces will be trimmed.
#
# dc=my_data_center
# rack=my_rack
# prefer_local=<false | true>
# dc_suffix=<Data Center name suffix, used by EC2SnitchXXX snitches>
#

View File

@@ -409,15 +409,16 @@ partitioner: org.apache.cassandra.dht.Murmur3Partitioner
# offheap_objects: native memory, eliminating nio buffer heap overhead
# memtable_allocation_type: heap_buffers
# Total space to use for commitlogs. Since commitlog segments are
# mmapped, and hence use up address space, the default size is 32
# on 32-bit JVMs, and 8192 on 64-bit JVMs.
# Total space to use for commitlogs.
#
# If space gets above this value (it will round up to the next nearest
# segment multiple), Scylla will flush every dirty CF in the oldest
# segment and remove it. So a small total commitlog space will tend
# to cause more flush activity on less-active columnfamilies.
commitlog_total_space_in_mb: 8192
#
# A value of -1 (default) will automatically equate it to the total amount of memory
# available for Scylla.
commitlog_total_space_in_mb: -1
# This sets the amount of memtable flush writer threads. These will
# be blocked by disk io, and each one will hold a memtable in memory

View File

@@ -132,7 +132,7 @@ modes = {
},
}
urchin_tests = [
scylla_tests = [
'tests/mutation_test',
'tests/range_test',
'tests/types_test',
@@ -152,6 +152,7 @@ urchin_tests = [
'tests/cql_query_test',
'tests/storage_proxy_test',
'tests/mutation_reader_test',
'tests/key_reader_test',
'tests/mutation_query_test',
'tests/row_cache_test',
'tests/test-serialization',
@@ -169,6 +170,7 @@ urchin_tests = [
'tests/compound_test',
'tests/config_test',
'tests/gossiping_property_file_snitch_test',
'tests/ec2_snitch_test',
'tests/snitch_reset_test',
'tests/network_topology_strategy_test',
'tests/query_processor_test',
@@ -180,13 +182,14 @@ urchin_tests = [
'tests/logalloc_test',
'tests/managed_vector_test',
'tests/crc_test',
'tests/flush_queue_test',
]
apps = [
'scylla',
]
tests = urchin_tests
tests = scylla_tests
all_artifacts = apps + tests
@@ -216,18 +219,20 @@ arg_parser.add_argument('--debuginfo', action = 'store', dest = 'debuginfo', typ
help = 'Enable(1)/disable(0)compiler debug information generation')
arg_parser.add_argument('--static-stdc++', dest = 'staticcxx', action = 'store_true',
help = 'Link libgcc and libstdc++ statically')
arg_parser.add_argument('--tests-debuginfo', action = 'store', dest = 'tests_debuginfo', type = int, default = 0,
help = 'Enable(1)/disable(0)compiler debug information generation for tests')
add_tristate(arg_parser, name = 'hwloc', dest = 'hwloc', help = 'hwloc support')
add_tristate(arg_parser, name = 'xen', dest = 'xen', help = 'Xen support')
args = arg_parser.parse_args()
defines = []
urchin_libs = '-llz4 -lsnappy -lz -lboost_thread -lcryptopp -lrt -lyaml-cpp -lboost_date_time'
scylla_libs = '-llz4 -lsnappy -lz -lboost_thread -lcryptopp -lrt -lyaml-cpp -lboost_date_time'
extra_cxxflags = {}
cassandra_interface = Thrift(source = 'interface/cassandra.thrift', service = 'Cassandra')
urchin_core = (['database.cc',
scylla_core = (['database.cc',
'schema.cc',
'bytes.cc',
'mutation.cc',
@@ -242,6 +247,7 @@ urchin_core = (['database.cc',
'mutation_partition_serializer.cc',
'mutation_reader.cc',
'mutation_query.cc',
'key_reader.cc',
'keys.cc',
'sstables/sstables.cc',
'sstables/compress.cc',
@@ -266,6 +272,8 @@ urchin_core = (['database.cc',
'cql3/maps.cc',
'cql3/functions/functions.cc',
'cql3/statements/cf_prop_defs.cc',
'cql3/statements/cf_statement.cc',
'cql3/statements/create_keyspace_statement.cc',
'cql3/statements/create_table_statement.cc',
'cql3/statements/drop_keyspace_statement.cc',
'cql3/statements/drop_table_statement.cc',
@@ -339,10 +347,12 @@ urchin_core = (['database.cc',
'gms/gossip_digest_ack.cc',
'gms/gossip_digest_ack2.cc',
'gms/endpoint_state.cc',
'gms/application_state.cc',
'dht/i_partitioner.cc',
'dht/murmur3_partitioner.cc',
'dht/byte_ordered_partitioner.cc',
'dht/boot_strapper.cc',
'dht/range_streamer.cc',
'unimplemented.cc',
'query.cc',
'query-result-set.cc',
@@ -356,9 +366,16 @@ urchin_core = (['database.cc',
'locator/simple_snitch.cc',
'locator/rack_inferring_snitch.cc',
'locator/gossiping_property_file_snitch.cc',
'locator/production_snitch_base.cc',
'locator/ec2_snitch.cc',
'locator/ec2_multi_region_snitch.cc',
'message/messaging_service.cc',
'service/migration_task.cc',
'service/storage_service.cc',
'service/pending_range_calculator_service.cc',
'service/load_broadcaster.cc',
'service/pager/paging_state.cc',
'service/pager/query_pagers.cc',
'streaming/streaming.cc',
'streaming/stream_task.cc',
'streaming/stream_session.cc',
@@ -379,11 +396,13 @@ urchin_core = (['database.cc',
'streaming/messages/file_message_header.cc',
'streaming/messages/outgoing_file_message.cc',
'streaming/messages/incoming_file_message.cc',
'streaming/stream_session_state.cc',
'gc_clock.cc',
'partition_slice_builder.cc',
'init.cc',
'repair/repair.cc',
'exceptions/exceptions.cc',
'dns.cc',
]
+ [Antlr3Grammar('cql3/Cql.g')]
+ [Thrift('interface/cassandra.thrift', 'Cassandra')]
@@ -419,22 +438,24 @@ api = ['api/api.cc',
'api/lsa.cc',
'api/api-doc/stream_manager.json',
'api/stream_manager.cc',
'api/api-doc/system.json',
'api/system.cc'
]
urchin_tests_dependencies = urchin_core + [
scylla_tests_dependencies = scylla_core + [
'tests/cql_test_env.cc',
'tests/cql_assertions.cc',
'tests/result_set_assertions.cc',
'tests/mutation_source_test.cc',
]
urchin_tests_seastar_deps = [
scylla_tests_seastar_deps = [
'seastar/tests/test-utils.cc',
'seastar/tests/test_runner.cc',
]
deps = {
'scylla': ['main.cc'] + urchin_core + api,
'scylla': ['main.cc'] + scylla_core + api,
}
tests_not_using_seastar_test_framework = set([
@@ -464,13 +485,13 @@ tests_not_using_seastar_test_framework = set([
])
for t in tests_not_using_seastar_test_framework:
if not t in urchin_tests:
raise Exception("Test %s not found in urchin_tests" % (t))
if not t in scylla_tests:
raise Exception("Test %s not found in scylla_tests" % (t))
for t in urchin_tests:
deps[t] = urchin_tests_dependencies + [t + '.cc']
for t in scylla_tests:
deps[t] = scylla_tests_dependencies + [t + '.cc']
if t not in tests_not_using_seastar_test_framework:
deps[t] += urchin_tests_seastar_deps
deps[t] += scylla_tests_seastar_deps
deps['tests/sstable_test'] += ['tests/sstable_datafile_test.cc']
@@ -491,6 +512,7 @@ warnings = [w
warnings = ' '.join(warnings)
dbgflag = debug_flag(args.cxx) if args.debuginfo else ''
tests_link_rule = 'link' if args.tests_debuginfo else 'link_stripped'
if args.so:
args.pie = '-shared'
@@ -531,7 +553,8 @@ if args.dpdk:
elif args.dpdk_target:
seastar_flags += ['--dpdk-target', args.dpdk_target]
seastar_flags += ['--compiler', args.cxx, '--cflags=-march=nehalem']
seastar_cflags = args.user_cflags + " -march=nehalem"
seastar_flags += ['--compiler', args.cxx, '--cflags=%s' % (seastar_cflags)]
status = subprocess.call(['./configure.py'] + seastar_flags, cwd = 'seastar')
@@ -665,7 +688,7 @@ with open(buildfile, 'w') as f:
# So we strip the tests by default; The user can very
# quickly re-link the test unstripped by adding a "_g"
# to the test name, e.g., "ninja build/release/testname_g"
f.write('build $builddir/{}/{}: link_stripped.{} {} {}\n'.format(mode, binary, mode, str.join(' ', objs),
f.write('build $builddir/{}/{}: {}.{} {} {}\n'.format(mode, binary, tests_link_rule, mode, str.join(' ', objs),
'seastar/build/{}/libseastar.a'.format(mode)))
if has_thrift:
f.write(' libs = -lthrift -lboost_system $libs\n')

View File

@@ -856,7 +856,7 @@ dropIndexStatement returns [DropIndexStatement expr]
* TRUNCATE <CF>;
*/
truncateStatement returns [::shared_ptr<truncate_statement> stmt]
: K_TRUNCATE cf=columnFamilyName { $stmt = ::make_shared<truncate_statement>(cf); }
: K_TRUNCATE (K_COLUMNFAMILY)? cf=columnFamilyName { $stmt = ::make_shared<truncate_statement>(cf); }
;
#if 0
@@ -1224,8 +1224,8 @@ properties[::shared_ptr<cql3::statements::property_definitions> props]
;
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()); } }
| map=mapLiteral { try { $props->add_property(k->to_string(), convert_property_map(map)); } catch (exceptions::syntax_exception e) { add_recognition_error(e.what()); } })
: 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

@@ -80,7 +80,7 @@ int64_t attributes::get_timestamp(int64_t now, const query_options& options) {
} catch (marshal_exception e) {
throw exceptions::invalid_request_exception("Invalid timestamp value");
}
return boost::any_cast<int64_t>(data_type_for<int64_t>()->deserialize(*tval));
return value_cast<int64_t>(data_type_for<int64_t>()->deserialize(*tval));
}
int32_t attributes::get_time_to_live(const query_options& options) {
@@ -99,7 +99,7 @@ int32_t attributes::get_time_to_live(const query_options& options) {
throw exceptions::invalid_request_exception("Invalid TTL value");
}
auto ttl = boost::any_cast<int32_t>(data_type_for<int32_t>()->deserialize(*tval));
auto ttl = value_cast<int32_t>(data_type_for<int32_t>()->deserialize(*tval));
if (ttl < 0) {
throw exceptions::invalid_request_exception("A TTL must be greater or equal to 0");
}

View File

@@ -160,7 +160,7 @@ void constants::deleter::execute(mutation& m, const exploded_clustering_prefix&
auto ctype = static_pointer_cast<const collection_type_impl>(column.type);
m.set_cell(prefix, column, atomic_cell_or_collection::from_collection_mutation(ctype->serialize_mutation_form(coll_m)));
} else {
m.set_cell(prefix, column, params.make_dead_cell());
m.set_cell(prefix, column, make_dead_cell(params));
}
}

View File

@@ -197,7 +197,7 @@ public:
virtual void execute(mutation& m, const exploded_clustering_prefix& prefix, const update_parameters& params) override {
auto value = _t->bind_and_get(params._options);
auto cell = value ? params.make_cell(*value) : params.make_dead_cell();
auto cell = value ? make_cell(*value, params) : make_dead_cell(params);
m.set_cell(prefix, column, std::move(cell));
}
};

View File

@@ -98,6 +98,10 @@ public:
execute_internal(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) = 0;
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const = 0;
virtual bool depends_on_keyspace(const sstring& ks_name) const = 0;
virtual bool depends_on_column_family(const sstring& cf_name) const = 0;
};
}

View File

@@ -90,7 +90,7 @@ public:
if (!values[0]) {
return;
}
_sum += boost::any_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
_sum += value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
}
};
@@ -132,7 +132,7 @@ public:
return;
}
++_count;
_sum += boost::any_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
_sum += value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
}
};
@@ -169,7 +169,7 @@ public:
if (!values[0]) {
return;
}
auto val = boost::any_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
auto val = value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
if (!_max) {
_max = val;
} else {
@@ -216,7 +216,7 @@ public:
if (!values[0]) {
return;
}
auto val = boost::any_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
auto val = value_cast<Type>(data_type_for<Type>()->deserialize(*values[0]));
if (!_min) {
_min = val;
} else {

View File

@@ -50,6 +50,11 @@ functions::init() {
if (type == cql3_type::varchar || type == cql3_type::blob) {
continue;
}
// counters are not supported yet
if (type->is_counter()) {
warn(unimplemented::cause::COUNTERS);
continue;
}
declare(make_to_blob_function(type->get_type()));
declare(make_from_blob_function(type->get_type()));

View File

@@ -71,10 +71,10 @@ make_min_timeuuid_fct() {
return {};
}
auto ts_obj = timestamp_type->deserialize(*bb);
if (ts_obj.empty()) {
if (ts_obj.is_null()) {
return {};
}
auto ts = boost::any_cast<db_clock::time_point>(ts_obj);
auto ts = value_cast<db_clock::time_point>(ts_obj);
auto uuid = utils::UUID_gen::min_time_UUID(ts.time_since_epoch().count());
return {timeuuid_type->decompose(uuid)};
});
@@ -91,10 +91,10 @@ make_max_timeuuid_fct() {
return {};
}
auto ts_obj = timestamp_type->deserialize(*bb);
if (ts_obj.empty()) {
if (ts_obj.is_null()) {
return {};
}
auto ts = boost::any_cast<db_clock::time_point>(ts_obj);
auto ts = value_cast<db_clock::time_point>(ts_obj);
auto uuid = utils::UUID_gen::max_time_UUID(ts.time_since_epoch().count());
return {timeuuid_type->decompose(uuid)};
});

View File

@@ -54,7 +54,7 @@ shared_ptr<function>
make_uuid_fct() {
return make_native_scalar_function<false>("uuid", uuid_type, {},
[] (serialization_format sf, const std::vector<bytes_opt>& parameters) -> bytes_opt {
return {uuid_type->decompose(boost::any(utils::make_random_uuid()))};
return {uuid_type->decompose(utils::make_random_uuid())};
});
}

View File

@@ -113,12 +113,12 @@ lists::value::from_serialized(bytes_view v, list_type type, serialization_format
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
// FIXME: deserializeForNativeProtocol()?!
auto l = boost::any_cast<list_type_impl::native_type>(type->deserialize(v, sf));
auto l = value_cast<list_type_impl::native_type>(type->deserialize(v, sf));
std::vector<bytes_opt> elements;
elements.reserve(l.size());
for (auto&& element : l) {
// elements can be null in lists that represent a set of IN values
elements.push_back(element.empty() ? bytes_opt() : bytes_opt(type->get_elements_type()->decompose(element)));
elements.push_back(element.is_null() ? bytes_opt() : bytes_opt(type->get_elements_type()->decompose(element)));
}
return value(std::move(elements));
} catch (marshal_exception& e) {
@@ -272,9 +272,9 @@ lists::setter_by_index::execute(mutation& m, const exploded_clustering_prefix& p
auto existing_list_opt = params.get_prefetched_list(m.key(), row_key, column);
if (!existing_list_opt) {
throw exceptions::invalid_request_exception(sprint("List index %d out of bound, list has size 0", idx));
throw exceptions::invalid_request_exception("Attempted to set an element on a list which is null");
}
collection_mutation::view existing_list_ser = *existing_list_opt;
collection_mutation_view existing_list_ser = *existing_list_opt;
auto ltype = dynamic_pointer_cast<const list_type_impl>(column.type);
collection_type_impl::mutation_view existing_list = ltype->deserialize_mutation_form(existing_list_ser);
// we verified that index is an int32_type
@@ -339,7 +339,7 @@ lists::do_append(shared_ptr<term> t,
} else {
auto&& to_add = list_value->_elements;
auto deref = [] (const bytes_opt& v) { return *v; };
auto&& newv = collection_mutation::one{list_type_impl::pack(
auto&& newv = collection_mutation{list_type_impl::pack(
boost::make_transform_iterator(to_add.begin(), deref),
boost::make_transform_iterator(to_add.end(), deref),
to_add.size(), serialization_format::internal())};
@@ -448,7 +448,7 @@ lists::discarder_by_index::execute(mutation& m, const exploded_clustering_prefix
auto&& existing_list = params.get_prefetched_list(m.key(), row_key, column);
int32_t idx = read_simple_exactly<int32_t>(*cvalue->_bytes);
if (!existing_list) {
throw exceptions::invalid_request_exception("List does not exist");
throw exceptions::invalid_request_exception("Attempted to delete an element from a list which is null");
}
auto&& deserialized = ltype->deserialize_mutation_form(*existing_list);
if (idx < 0 || size_t(idx) >= deserialized.cells.size()) {

View File

@@ -161,7 +161,7 @@ maps::value::from_serialized(bytes_view value, map_type type, serialization_form
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
// FIXME: deserialize_for_native_protocol?!
auto m = boost::any_cast<map_type_impl::native_type>(type->deserialize(value, sf));
auto m = value_cast<map_type_impl::native_type>(type->deserialize(value, sf));
std::map<bytes, bytes, serialized_compare> map(type->get_keys_type()->as_less_comparator());
for (auto&& e : m) {
map.emplace(type->get_keys_type()->decompose(e.first),
@@ -350,10 +350,8 @@ maps::discarder_by_key::execute(mutation& m, const exploded_clustering_prefix& p
if (!key) {
throw exceptions::invalid_request_exception("Invalid null map key");
}
auto ckey = dynamic_pointer_cast<constants::value>(std::move(key));
assert(ckey);
collection_type_impl::mutation mut;
mut.cells.emplace_back(*ckey->_bytes, params.make_dead_cell());
mut.cells.emplace_back(*key->get(params._options), params.make_dead_cell());
auto mtype = static_cast<const map_type_impl*>(column.type.get());
m.set_cell(prefix, column, mtype->serialize_mutation_form(mut));
}

View File

@@ -216,7 +216,7 @@ operation::element_deletion::prepare(database& db, const sstring& keyspace, cons
return make_shared<lists::discarder_by_index>(receiver, std::move(idx));
} else if (&ctype->_kind == &collection_type_impl::kind::set) {
auto&& elt = _element->prepare(db, keyspace, sets::value_spec_of(receiver.column_specification));
return make_shared<sets::discarder>(receiver, std::move(elt));
return make_shared<sets::element_discarder>(receiver, std::move(elt));
} else if (&ctype->_kind == &collection_type_impl::kind::map) {
auto&& key = _element->prepare(db, keyspace, maps::key_spec_of(*receiver.column_specification));
return make_shared<maps::discarder_by_key>(receiver, std::move(key));

View File

@@ -45,6 +45,7 @@
#include "exceptions/exceptions.hh"
#include "database_fwd.hh"
#include "term.hh"
#include "update_parameters.hh"
#include <experimental/optional>
@@ -86,6 +87,14 @@ public:
virtual ~operation() {}
atomic_cell make_dead_cell(const update_parameters& params) const {
return params.make_dead_cell();
}
atomic_cell make_cell(bytes_view value, const update_parameters& params) const {
return params.make_cell(value);
}
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const {
return _t && _t->uses_function(ks_name, function_name);
}

View File

@@ -56,14 +56,15 @@ using namespace transport::messages;
logging::logger log("query_processor");
distributed<query_processor> _the_query_processor;
const sstring query_processor::CQL_VERSION = "3.2.0";
class query_processor::internal_state {
service::client_state _cs;
service::query_state _qs;
public:
internal_state()
: _cs(service::client_state::internal_tag()), _qs(_cs) {
: _qs(service::client_state{service::client_state::internal_tag()}) {
}
operator service::query_state&() {
return _qs;
@@ -72,14 +73,13 @@ public:
return _qs;
}
operator service::client_state&() {
return _cs;
return _qs.get_client_state();
}
operator const service::client_state&() const {
return _cs;
return _qs.get_client_state();
}
api::timestamp_type next_timestamp() {
return _cs.get_timestamp();
return _qs.get_client_state().get_timestamp();
}
};
@@ -89,12 +89,23 @@ api::timestamp_type query_processor::next_timestamp() {
query_processor::query_processor(distributed<service::storage_proxy>& proxy,
distributed<database>& db)
: _proxy(proxy), _db(db), _internal_state(new internal_state()) {
: _migration_subscriber{std::make_unique<migration_subscriber>(this)}
, _proxy(proxy)
, _db(db)
, _internal_state(new internal_state())
{
service::get_local_migration_manager().register_listener(_migration_subscriber.get());
}
query_processor::~query_processor()
{}
future<> query_processor::stop()
{
service::get_local_migration_manager().unregister_listener(_migration_subscriber.get());
return make_ready_future<>();
}
future<::shared_ptr<result_message>>
query_processor::process(const sstring_view& query_string, service::query_state& query_state, query_options& options)
{
@@ -212,6 +223,11 @@ query_processor::store_prepared_statement(const std::experimental::string_view&
}
}
void query_processor::invalidate_prepared_statement(bytes statement_id)
{
_prepared_statements.erase(statement_id);
}
static bytes md5_calculate(const std::experimental::string_view& s)
{
constexpr size_t size = CryptoPP::Weak1::MD5::DIGESTSIZE;
@@ -284,7 +300,7 @@ query_processor::parse_statement(const sstring_view& query)
query_options query_processor::make_internal_options(
::shared_ptr<statements::parsed_statement::prepared> p,
const std::initializer_list<boost::any>& values) {
const std::initializer_list<data_value>& values) {
if (p->bound_names.size() != values.size()) {
throw std::invalid_argument(sprint("Invalid number of values. Expecting %d but got %d", p->bound_names.size(), values.size()));
}
@@ -292,9 +308,9 @@ query_options query_processor::make_internal_options(
std::vector<bytes_opt> bound_values;
for (auto& v : values) {
auto& n = *ni++;
if (v.type() == typeid(bytes)) {
bound_values.push_back({boost::any_cast<bytes>(v)});
} else if (v.empty()) {
if (v.type() == bytes_type) {
bound_values.push_back({value_cast<bytes>(v)});
} else if (v.is_null()) {
bound_values.push_back({});
} else {
bound_values.push_back({n->type->decompose(v)});
@@ -317,7 +333,7 @@ query_options query_processor::make_internal_options(
future<::shared_ptr<untyped_result_set>> query_processor::execute_internal(
const std::experimental::string_view& query_string,
const std::initializer_list<boost::any>& values) {
const std::initializer_list<data_value>& values) {
auto p = prepare_internal(query_string);
auto opts = make_internal_options(p, values);
return do_with(std::move(opts),
@@ -338,5 +354,97 @@ query_processor::process_batch(::shared_ptr<statements::batch_statement> batch,
return batch->execute(_proxy, query_state, options);
}
query_processor::migration_subscriber::migration_subscriber(query_processor* qp)
: _qp{qp}
{
}
void query_processor::migration_subscriber::on_create_keyspace(const sstring& ks_name)
{
}
void query_processor::migration_subscriber::on_create_column_family(const sstring& ks_name, const sstring& cf_name)
{
}
void query_processor::migration_subscriber::on_create_user_type(const sstring& ks_name, const sstring& type_name)
{
}
void query_processor::migration_subscriber::on_create_function(const sstring& ks_name, const sstring& function_name)
{
log.warn("{} event ignored", __func__);
}
void query_processor::migration_subscriber::on_create_aggregate(const sstring& ks_name, const sstring& aggregate_name)
{
log.warn("{} event ignored", __func__);
}
void query_processor::migration_subscriber::on_update_keyspace(const sstring& ks_name)
{
}
void query_processor::migration_subscriber::on_update_column_family(const sstring& ks_name, const sstring& cf_name)
{
}
void query_processor::migration_subscriber::on_update_user_type(const sstring& ks_name, const sstring& type_name)
{
}
void query_processor::migration_subscriber::on_update_function(const sstring& ks_name, const sstring& function_name)
{
}
void query_processor::migration_subscriber::on_update_aggregate(const sstring& ks_name, const sstring& aggregate_name)
{
}
void query_processor::migration_subscriber::on_drop_keyspace(const sstring& ks_name)
{
remove_invalid_prepared_statements(ks_name, std::experimental::nullopt);
}
void query_processor::migration_subscriber::on_drop_column_family(const sstring& ks_name, const sstring& cf_name)
{
remove_invalid_prepared_statements(ks_name, cf_name);
}
void query_processor::migration_subscriber::on_drop_user_type(const sstring& ks_name, const sstring& type_name)
{
}
void query_processor::migration_subscriber::on_drop_function(const sstring& ks_name, const sstring& function_name)
{
log.warn("{} event ignored", __func__);
}
void query_processor::migration_subscriber::on_drop_aggregate(const sstring& ks_name, const sstring& aggregate_name)
{
log.warn("{} event ignored", __func__);
}
void query_processor::migration_subscriber::remove_invalid_prepared_statements(sstring ks_name, std::experimental::optional<sstring> cf_name)
{
std::vector<bytes> invalid;
for (auto& kv : _qp->_prepared_statements) {
auto id = kv.first;
auto stmt = kv.second;
if (should_invalidate(ks_name, cf_name, stmt->statement)) {
invalid.emplace_back(id);
}
}
for (auto& id : invalid) {
get_query_processor().invoke_on_all([id] (auto& qp) {
qp.invalidate_prepared_statement(id);
});
}
}
bool query_processor::migration_subscriber::should_invalidate(sstring ks_name, std::experimental::optional<sstring> cf_name, ::shared_ptr<cql_statement> statement)
{
return statement->depends_on_keyspace(ks_name) && (!cf_name || statement->depends_on_column_family(*cf_name));
}
}

View File

@@ -48,6 +48,7 @@
#include "exceptions/exceptions.hh"
#include "cql3/query_options.hh"
#include "cql3/statements/cf_statement.hh"
#include "service/migration_manager.hh"
#include "service/query_state.hh"
#include "log.hh"
#include "core/distributed.hh"
@@ -61,7 +62,10 @@ class batch_statement;
}
class query_processor {
public:
class migration_subscriber;
private:
std::unique_ptr<migration_subscriber> _migration_subscriber;
distributed<service::storage_proxy>& _proxy;
distributed<database>& _db;
@@ -319,12 +323,12 @@ public:
#endif
private:
::shared_ptr<statements::parsed_statement::prepared> prepare_internal(const std::experimental::string_view& query);
query_options make_internal_options(::shared_ptr<statements::parsed_statement::prepared>, const std::initializer_list<boost::any>&);
query_options make_internal_options(::shared_ptr<statements::parsed_statement::prepared>, const std::initializer_list<data_value>&);
public:
future<::shared_ptr<untyped_result_set>> execute_internal(
const std::experimental::string_view& query_string,
const std::initializer_list<boost::any>& = { });
const std::initializer_list<data_value>& = { });
/*
* This function provides a timestamp that is guaranteed to be higher than any timestamp
@@ -423,6 +427,8 @@ private:
future<::shared_ptr<transport::messages::result_message::prepared>>
store_prepared_statement(const std::experimental::string_view& query_string, const sstring& keyspace, ::shared_ptr<statements::parsed_statement::prepared> prepared, bool for_thrift);
void invalidate_prepared_statement(bytes statement_id);
#if 0
public ResultMessage processPrepared(CQLStatement statement, QueryState queryState, QueryOptions options)
throws RequestExecutionException, RequestValidationException
@@ -461,111 +467,48 @@ public:
{
return meter.measureDeep(key);
}
private static class MigrationSubscriber implements IMigrationListener
{
private void removeInvalidPreparedStatements(String ksName, String cfName)
{
removeInvalidPreparedStatements(preparedStatements.values().iterator(), ksName, cfName);
removeInvalidPreparedStatements(thriftPreparedStatements.values().iterator(), ksName, cfName);
}
private void removeInvalidPreparedStatements(Iterator<ParsedStatement.Prepared> iterator, String ksName, String cfName)
{
while (iterator.hasNext())
{
if (shouldInvalidate(ksName, cfName, iterator.next().statement))
iterator.remove();
}
}
private boolean shouldInvalidate(String ksName, String cfName, CQLStatement statement)
{
String statementKsName;
String statementCfName;
if (statement instanceof ModificationStatement)
{
ModificationStatement modificationStatement = ((ModificationStatement) statement);
statementKsName = modificationStatement.keyspace();
statementCfName = modificationStatement.columnFamily();
}
else if (statement instanceof SelectStatement)
{
SelectStatement selectStatement = ((SelectStatement) statement);
statementKsName = selectStatement.keyspace();
statementCfName = selectStatement.columnFamily();
}
else
{
return false;
}
return ksName.equals(statementKsName) && (cfName == null || cfName.equals(statementCfName));
}
public void onCreateKeyspace(String ksName) { }
public void onCreateColumnFamily(String ksName, String cfName) { }
public void onCreateUserType(String ksName, String typeName) { }
public void onCreateFunction(String ksName, String functionName) {
if (Functions.getOverloadCount(new FunctionName(ksName, functionName)) > 1)
{
// in case there are other overloads, we have to remove all overloads since argument type
// matching may change (due to type casting)
removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, functionName);
removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, functionName);
}
}
public void onCreateAggregate(String ksName, String aggregateName) {
if (Functions.getOverloadCount(new FunctionName(ksName, aggregateName)) > 1)
{
// in case there are other overloads, we have to remove all overloads since argument type
// matching may change (due to type casting)
removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, aggregateName);
removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, aggregateName);
}
}
public void onUpdateKeyspace(String ksName) { }
public void onUpdateColumnFamily(String ksName, String cfName) { }
public void onUpdateUserType(String ksName, String typeName) { }
public void onUpdateFunction(String ksName, String functionName) { }
public void onUpdateAggregate(String ksName, String aggregateName) { }
public void onDropKeyspace(String ksName)
{
removeInvalidPreparedStatements(ksName, null);
}
public void onDropColumnFamily(String ksName, String cfName)
{
removeInvalidPreparedStatements(ksName, cfName);
}
public void onDropUserType(String ksName, String typeName) { }
public void onDropFunction(String ksName, String functionName) {
removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, functionName);
removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, functionName);
}
public void onDropAggregate(String ksName, String aggregateName)
{
removeInvalidPreparedStatementsForFunction(preparedStatements.values().iterator(), ksName, aggregateName);
removeInvalidPreparedStatementsForFunction(thriftPreparedStatements.values().iterator(), ksName, aggregateName);
}
private void removeInvalidPreparedStatementsForFunction(Iterator<ParsedStatement.Prepared> iterator,
String ksName, String functionName)
{
while (iterator.hasNext())
if (iterator.next().statement.usesFunction(ksName, functionName))
iterator.remove();
}
}
#endif
public:
future<> stop() {
return make_ready_future<>();
}
future<> stop();
friend class migration_subscriber;
};
class query_processor::migration_subscriber : public service::migration_listener {
query_processor* _qp;
public:
migration_subscriber(query_processor* qp);
virtual void on_create_keyspace(const sstring& ks_name) override;
virtual void on_create_column_family(const sstring& ks_name, const sstring& cf_name) override;
virtual void on_create_user_type(const sstring& ks_name, const sstring& type_name) override;
virtual void on_create_function(const sstring& ks_name, const sstring& function_name) override;
virtual void on_create_aggregate(const sstring& ks_name, const sstring& aggregate_name) override;
virtual void on_update_keyspace(const sstring& ks_name) override;
virtual void on_update_column_family(const sstring& ks_name, const sstring& cf_name) override;
virtual void on_update_user_type(const sstring& ks_name, const sstring& type_name) override;
virtual void on_update_function(const sstring& ks_name, const sstring& function_name) override;
virtual void on_update_aggregate(const sstring& ks_name, const sstring& aggregate_name) override;
virtual void on_drop_keyspace(const sstring& ks_name) override;
virtual void on_drop_column_family(const sstring& ks_name, const sstring& cf_name) override;
virtual void on_drop_user_type(const sstring& ks_name, const sstring& type_name) override;
virtual void on_drop_function(const sstring& ks_name, const sstring& function_name) override;
virtual void on_drop_aggregate(const sstring& ks_name, const sstring& aggregate_name) override;
private:
void remove_invalid_prepared_statements(sstring ks_name, std::experimental::optional<sstring> cf_name);
bool should_invalidate(sstring ks_name, std::experimental::optional<sstring> cf_name, ::shared_ptr<cql_statement> statement);
};
extern distributed<query_processor> _the_query_processor;
inline distributed<query_processor>& get_query_processor() {
return _the_query_processor;
}
inline query_processor& get_local_query_processor() {
return _the_query_processor.local();
}
}

View File

@@ -80,7 +80,7 @@ public:
private:
const uint32_t _column_count;
::shared_ptr<service::pager::paging_state> _paging_state;
::shared_ptr<const service::pager::paging_state> _paging_state;
public:
metadata(std::vector<::shared_ptr<column_specification>> names_)
@@ -88,7 +88,7 @@ public:
{ }
metadata(flag_enum_set flags, std::vector<::shared_ptr<column_specification>> names_, uint32_t column_count,
::shared_ptr<service::pager::paging_state> paging_state)
::shared_ptr<const service::pager::paging_state> paging_state)
: _flags(flags)
, names(std::move(names_))
, _column_count(column_count)
@@ -121,7 +121,7 @@ private:
}
public:
void set_has_more_pages(::shared_ptr<service::pager::paging_state> paging_state) {
void set_has_more_pages(::shared_ptr<const service::pager::paging_state> paging_state) {
if (!paging_state) {
return;
}
@@ -342,6 +342,10 @@ public:
std::sort(_rows.begin(), _rows.end(), std::forward<RowComparator>(cmp));
}
metadata& get_metadata() {
return *_metadata;
}
const metadata& get_metadata() const {
return *_metadata;
}

View File

@@ -125,7 +125,7 @@ protected:
}
};
std::unique_ptr<selectors> new_selectors() {
std::unique_ptr<selectors> new_selectors() const override {
return std::make_unique<simple_selectors>();
}
};
@@ -196,7 +196,7 @@ protected:
}
};
std::unique_ptr<selectors> new_selectors() {
std::unique_ptr<selectors> new_selectors() const override {
return std::make_unique<selectors_with_processing>(_factories);
}
};
@@ -252,7 +252,7 @@ selection::collect_metadata(schema_ptr schema, const std::vector<::shared_ptr<ra
return r;
}
result_set_builder::result_set_builder(selection& s, db_clock::time_point now, serialization_format sf)
result_set_builder::result_set_builder(const selection& s, db_clock::time_point now, serialization_format sf)
: _result_set(std::make_unique<result_set>(::make_shared<metadata>(*(s.get_result_metadata()))))
, _selectors(s.new_selectors())
, _now(now)
@@ -295,7 +295,7 @@ void result_set_builder::add(const column_definition& def, const query::result_a
}
}
void result_set_builder::add(const column_definition& def, collection_mutation::view c) {
void result_set_builder::add(const column_definition& def, collection_mutation_view c) {
auto&& ctype = static_cast<const collection_type_impl*>(def.type.get());
current->emplace_back(ctype->to_value(c, _serialization_format));
// timestamps, ttls meaningless for collections
@@ -330,6 +330,94 @@ std::unique_ptr<result_set> result_set_builder::build() {
return std::move(_result_set);
}
result_set_builder::visitor::visitor(
cql3::selection::result_set_builder& builder, const schema& s,
const selection& selection)
: _builder(builder), _schema(s), _selection(selection), _row_count(0) {
}
void result_set_builder::visitor::add_value(const column_definition& def,
query::result_row_view::iterator_type& i) {
if (def.type->is_multi_cell()) {
auto cell = i.next_collection_cell();
if (!cell) {
_builder.add_empty();
return;
}
_builder.add(def, *cell);
} else {
auto cell = i.next_atomic_cell();
if (!cell) {
_builder.add_empty();
return;
}
_builder.add(def, *cell);
}
}
void result_set_builder::visitor::accept_new_partition(const partition_key& key,
uint32_t row_count) {
_partition_key = key.explode(_schema);
_row_count = row_count;
}
void result_set_builder::visitor::accept_new_partition(uint32_t row_count) {
_row_count = row_count;
}
void result_set_builder::visitor::accept_new_row(const clustering_key& key,
const query::result_row_view& static_row,
const query::result_row_view& row) {
_clustering_key = key.explode(_schema);
accept_new_row(static_row, row);
}
void result_set_builder::visitor::accept_new_row(
const query::result_row_view& static_row,
const query::result_row_view& row) {
auto static_row_iterator = static_row.iterator();
auto row_iterator = row.iterator();
_builder.new_row();
for (auto&& def : _selection.get_columns()) {
switch (def->kind) {
case column_kind::partition_key:
_builder.add(_partition_key[def->component_index()]);
break;
case column_kind::clustering_key:
_builder.add(_clustering_key[def->component_index()]);
break;
case column_kind::regular_column:
add_value(*def, row_iterator);
break;
case column_kind::compact_column:
add_value(*def, row_iterator);
break;
case column_kind::static_column:
add_value(*def, static_row_iterator);
break;
default:
assert(0);
}
}
}
void result_set_builder::visitor::accept_partition_end(
const query::result_row_view& static_row) {
if (_row_count == 0) {
_builder.new_row();
auto static_row_iterator = static_row.iterator();
for (auto&& def : _selection.get_columns()) {
if (def->is_partition_key()) {
_builder.add(_partition_key[def->component_index()]);
} else if (def->is_static()) {
add_value(*def, static_row_iterator);
} else {
_builder.add_empty();
}
}
}
}
api::timestamp_type result_set_builder::timestamp_of(size_t idx) {
return _timestamps[idx];
}

View File

@@ -161,7 +161,7 @@ public:
return std::find(_columns.begin(), _columns.end(), &def) != _columns.end();
}
::shared_ptr<metadata> get_result_metadata() {
::shared_ptr<metadata> get_result_metadata() const {
return _metadata;
}
@@ -186,16 +186,16 @@ private:
public:
static ::shared_ptr<selection> from_selectors(database& db, schema_ptr schema, const std::vector<::shared_ptr<raw_selector>>& raw_selectors);
virtual std::unique_ptr<selectors> new_selectors() = 0;
virtual std::unique_ptr<selectors> new_selectors() const = 0;
/**
* Returns a range of CQL3 columns this selection needs.
*/
auto const& get_columns() {
auto const& get_columns() const {
return _columns;
}
uint32_t get_column_count() {
uint32_t get_column_count() const {
return _columns.size();
}
@@ -238,15 +238,39 @@ private:
const db_clock::time_point _now;
serialization_format _serialization_format;
public:
result_set_builder(selection& s, db_clock::time_point now, serialization_format sf);
result_set_builder(const selection& s, db_clock::time_point now, serialization_format sf);
void add_empty();
void add(bytes_opt value);
void add(const column_definition& def, const query::result_atomic_cell_view& c);
void add(const column_definition& def, collection_mutation::view c);
void add(const column_definition& def, collection_mutation_view c);
void new_row();
std::unique_ptr<result_set> build();
api::timestamp_type timestamp_of(size_t idx);
int32_t ttl_of(size_t idx);
// Implements ResultVisitor concept from query.hh
class visitor {
protected:
result_set_builder& _builder;
const schema& _schema;
const selection& _selection;
uint32_t _row_count;
std::vector<bytes> _partition_key;
std::vector<bytes> _clustering_key;
public:
visitor(cql3::selection::result_set_builder& builder, const schema& s, const selection&);
visitor(visitor&&) = default;
void add_value(const column_definition& def, query::result_row_view::iterator_type& i);
void accept_new_partition(const partition_key& key, uint32_t row_count);
void accept_new_partition(uint32_t row_count);
void accept_new_row(const clustering_key& key,
const query::result_row_view& static_row,
const query::result_row_view& row);
void accept_new_row(const query::result_row_view& static_row,
const query::result_row_view& row);
void accept_partition_end(const query::result_row_view& static_row);
};
private:
bytes_opt get_value(data_type t, query::result_atomic_cell_view c);
};

View File

@@ -125,7 +125,7 @@ sets::value::from_serialized(bytes_view v, set_type type, serialization_format s
// Collections have this small hack that validate cannot be called on a serialized object,
// but compose does the validation (so we're fine).
// FIXME: deserializeForNativeProtocol?!
auto s = boost::any_cast<set_type_impl::native_type>(type->deserialize(v, sf));
auto s = value_cast<set_type_impl::native_type>(type->deserialize(v, sf));
std::set<bytes, serialized_compare> elements(type->get_elements_type()->as_less_comparator());
for (auto&& element : s) {
elements.insert(elements.end(), type->get_elements_type()->decompose(element));
@@ -284,16 +284,11 @@ sets::discarder::execute(mutation& m, const exploded_clustering_prefix& row_key,
auto kill = [&] (bytes idx) {
mut.cells.push_back({std::move(idx), params.make_dead_cell()});
};
// This can be either a set or a single element
auto cvalue = dynamic_pointer_cast<constants::value>(value);
if (cvalue) {
kill(cvalue->_bytes ? *cvalue->_bytes : bytes());
} else {
auto svalue = static_pointer_cast<sets::value>(value);
mut.cells.reserve(svalue->_elements.size());
for (auto&& e : svalue->_elements) {
kill(e);
}
auto svalue = dynamic_pointer_cast<sets::value>(value);
assert(svalue);
mut.cells.reserve(svalue->_elements.size());
for (auto&& e : svalue->_elements) {
kill(e);
}
auto ctype = static_pointer_cast<const collection_type_impl>(column.type);
m.set_cell(row_key, column,
@@ -301,4 +296,17 @@ sets::discarder::execute(mutation& m, const exploded_clustering_prefix& row_key,
ctype->serialize_mutation_form(mut)));
}
void sets::element_discarder::execute(mutation& m, const exploded_clustering_prefix& row_key, const update_parameters& params)
{
assert(column.type->is_multi_cell() && "Attempted to remove items from a frozen set");
auto elt = _t->bind(params._options);
if (!elt) {
throw exceptions::invalid_request_exception("Invalid null set element");
}
collection_type_impl::mutation mut;
mut.cells.emplace_back(*elt->get(params._options), params.make_dead_cell());
auto ctype = static_pointer_cast<const collection_type_impl>(column.type);
m.set_cell(row_key, column, ctype->serialize_mutation_form(mut));
}
}

View File

@@ -133,6 +133,13 @@ public:
}
virtual void execute(mutation& m, const exploded_clustering_prefix& row_key, const update_parameters& params) override;
};
class element_discarder : public operation {
public:
element_discarder(const column_definition& column, shared_ptr<term> t)
: operation(column, std::move(t)) { }
virtual void execute(mutation& m, const exploded_clustering_prefix& row_key, const update_parameters& params) override;
};
};
}

View File

@@ -45,6 +45,16 @@ namespace statements {
logging::logger batch_statement::_logger("BatchStatement");
bool batch_statement::depends_on_keyspace(const sstring& ks_name) const
{
return false;
}
bool batch_statement::depends_on_column_family(const sstring& cf_name) const
{
return false;
}
}
}

View File

@@ -96,6 +96,10 @@ public:
|| boost::algorithm::any_of(_statements, [&] (auto&& s) { return s->uses_function(ks_name, function_name); });
}
virtual bool depends_on_keyspace(const sstring& ks_name) const override;
virtual bool depends_on_column_family(const sstring& cf_name) const override;
virtual uint32_t get_bound_terms() override {
return _bound_terms;
}

View File

@@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2014-2015 ScyllaDB
*
* Modified by 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 "cql3/statements/cf_statement.hh"
namespace cql3 {
namespace statements {
cf_statement::cf_statement(::shared_ptr<cf_name> cf_name)
: _cf_name(std::move(cf_name))
{
}
void cf_statement::prepare_keyspace(const service::client_state& state)
{
if (!_cf_name->has_keyspace()) {
// XXX: We explicitely only want to call state.getKeyspace() in this case, as we don't want to throw
// if not logged in any keyspace but a keyspace is explicitely set on the statement. So don't move
// the call outside the 'if' or replace the method by 'prepareKeyspace(state.getKeyspace())'
_cf_name->set_keyspace(state.get_keyspace(), true);
}
}
void cf_statement::prepare_keyspace(sstring keyspace)
{
if (!_cf_name->has_keyspace()) {
_cf_name->set_keyspace(keyspace, true);
}
}
const sstring& cf_statement::keyspace() const
{
assert(_cf_name->has_keyspace()); // "The statement hasn't be prepared correctly";
return _cf_name->get_keyspace();
}
const sstring& cf_statement::column_family() const
{
return _cf_name->get_column_family();
}
}
}

View File

@@ -57,35 +57,16 @@ class cf_statement : public parsed_statement {
protected:
::shared_ptr<cf_name> _cf_name;
cf_statement(::shared_ptr<cf_name> cf_name)
: _cf_name(std::move(cf_name))
{ }
cf_statement(::shared_ptr<cf_name> cf_name);
public:
virtual void prepare_keyspace(const service::client_state& state) {
if (!_cf_name->has_keyspace()) {
// XXX: We explicitely only want to call state.getKeyspace() in this case, as we don't want to throw
// if not logged in any keyspace but a keyspace is explicitely set on the statement. So don't move
// the call outside the 'if' or replace the method by 'prepareKeyspace(state.getKeyspace())'
_cf_name->set_keyspace(state.get_keyspace(), true);
}
}
virtual void prepare_keyspace(const service::client_state& state);
// Only for internal calls, use the version with ClientState for user queries
virtual void prepare_keyspace(sstring keyspace) {
if (!_cf_name->has_keyspace()) {
_cf_name->set_keyspace(keyspace, true);
}
}
virtual void prepare_keyspace(sstring keyspace);
virtual const sstring& keyspace() const {
assert(_cf_name->has_keyspace()); // "The statement hasn't be prepared correctly";
return _cf_name->get_keyspace();
}
virtual const sstring& keyspace() const;
virtual const sstring& column_family() const {
return _cf_name->get_column_family();
}
virtual const sstring& column_family() const;
};
}

View File

@@ -0,0 +1,130 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2015 ScyllaDB
*
* Modified by 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 "cql3/statements/create_keyspace_statement.hh"
#include "service/migration_manager.hh"
#include <regex>
namespace cql3 {
namespace statements {
create_keyspace_statement::create_keyspace_statement(const sstring& name, shared_ptr<ks_prop_defs> attrs, bool if_not_exists)
: _name{name}
, _attrs{attrs}
, _if_not_exists{if_not_exists}
{
}
const sstring& create_keyspace_statement::keyspace() const
{
return _name;
}
void create_keyspace_statement::check_access(const service::client_state& state)
{
warn(unimplemented::cause::PERMISSIONS);
#if 0
state.hasAllKeyspacesAccess(Permission.CREATE);
#endif
}
void create_keyspace_statement::validate(distributed<service::storage_proxy>&, const service::client_state& state)
{
std::string name;
name.resize(_name.length());
std::transform(_name.begin(), _name.end(), name.begin(), ::tolower);
if (name == db::system_keyspace::NAME) {
throw exceptions::invalid_request_exception("system keyspace is not user-modifiable");
}
// keyspace name
std::regex name_regex("\\w+");
if (!std::regex_match(name, name_regex)) {
throw exceptions::invalid_request_exception(sprint("\"%s\" is not a valid keyspace name", _name.c_str()));
}
if (name.length() > schema::NAME_LENGTH) {
throw exceptions::invalid_request_exception(sprint("Keyspace names shouldn't be more than %d characters long (got \"%s\")", schema::NAME_LENGTH, _name.c_str()));
}
_attrs->validate();
if (!bool(_attrs->get_replication_strategy_class())) {
throw exceptions::configuration_exception("Missing mandatory replication strategy class");
}
#if 0
// The strategy is validated through KSMetaData.validate() in announceNewKeyspace below.
// However, for backward compatibility with thrift, this doesn't validate unexpected options yet,
// so doing proper validation here.
AbstractReplicationStrategy.validateReplicationStrategy(name,
AbstractReplicationStrategy.getClass(attrs.getReplicationStrategyClass()),
StorageService.instance.getTokenMetadata(),
DatabaseDescriptor.getEndpointSnitch(),
attrs.getReplicationOptions());
#endif
}
future<bool> create_keyspace_statement::announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only)
{
return make_ready_future<>().then([this, is_local_only] {
return service::get_local_migration_manager().announce_new_keyspace(_attrs->as_ks_metadata(_name), is_local_only);
}).then_wrapped([this] (auto&& f) {
try {
f.get();
return true;
} catch (const exceptions::already_exists_exception& e) {
if (_if_not_exists) {
return false;
}
throw e;
}
});
}
shared_ptr<transport::event::schema_change> create_keyspace_statement::change_event()
{
return make_shared<transport::event::schema_change>(transport::event::schema_change::change_type::CREATED, keyspace());
}
}
}

View File

@@ -41,11 +41,8 @@
#pragma once
#include <regex>
#include "cql3/statements/schema_altering_statement.hh"
#include "cql3/statements/ks_prop_defs.hh"
#include "service/migration_manager.hh"
#include "transport/event.hh"
#include "core/shared_ptr.hh"
@@ -69,22 +66,11 @@ public:
* @param name the name of the keyspace to create
* @param attrs map of the raw keyword arguments that followed the <code>WITH</code> keyword.
*/
create_keyspace_statement(const sstring& name, shared_ptr<ks_prop_defs> attrs, bool if_not_exists)
: _name{name}
, _attrs{attrs}
, _if_not_exists{if_not_exists}
{ }
create_keyspace_statement(const sstring& name, shared_ptr<ks_prop_defs> attrs, bool if_not_exists);
virtual const sstring& keyspace() const override {
return _name;
}
virtual const sstring& keyspace() const override;
virtual void check_access(const service::client_state& state) override {
warn(unimplemented::cause::PERMISSIONS);
#if 0
state.hasAllKeyspacesAccess(Permission.CREATE);
#endif
}
virtual void check_access(const service::client_state& state) override;
/**
* The <code>CqlParser</code> only goes as far as extracting the keyword arguments
@@ -93,58 +79,11 @@ public:
*
* @throws InvalidRequestException if arguments are missing or unacceptable
*/
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override {
std::string name;
name.resize(_name.length());
std::transform(_name.begin(), _name.end(), name.begin(), ::tolower);
if (name == db::system_keyspace::NAME) {
throw exceptions::invalid_request_exception("system keyspace is not user-modifiable");
}
// keyspace name
std::regex name_regex("\\w+");
if (!std::regex_match(name, name_regex)) {
throw exceptions::invalid_request_exception(sprint("\"%s\" is not a valid keyspace name", _name.c_str()));
}
if (name.length() > schema::NAME_LENGTH) {
throw exceptions::invalid_request_exception(sprint("Keyspace names shouldn't be more than %d characters long (got \"%s\")", schema::NAME_LENGTH, _name.c_str()));
}
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override;
_attrs->validate();
virtual future<bool> announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only) override;
if (!bool(_attrs->get_replication_strategy_class())) {
throw exceptions::configuration_exception("Missing mandatory replication strategy class");
}
#if 0
// The strategy is validated through KSMetaData.validate() in announceNewKeyspace below.
// However, for backward compatibility with thrift, this doesn't validate unexpected options yet,
// so doing proper validation here.
AbstractReplicationStrategy.validateReplicationStrategy(name,
AbstractReplicationStrategy.getClass(attrs.getReplicationStrategyClass()),
StorageService.instance.getTokenMetadata(),
DatabaseDescriptor.getEndpointSnitch(),
attrs.getReplicationOptions());
#endif
}
virtual future<bool> announce_migration(distributed<service::storage_proxy>& proxy, bool is_local_only) override {
return make_ready_future<>().then([this, is_local_only] {
return service::get_local_migration_manager().announce_new_keyspace(_attrs->as_ks_metadata(_name), is_local_only);
}).then_wrapped([this] (auto&& f) {
try {
f.get();
return true;
} catch (const exceptions::already_exists_exception& e) {
if (_if_not_exists) {
return false;
}
throw e;
}
});
}
virtual shared_ptr<transport::event::schema_change> change_event() override {
return make_shared<transport::event::schema_change>(transport::event::schema_change::change_type::CREATED, keyspace());
}
virtual shared_ptr<transport::event::schema_change> change_event() override;
};
}

View File

@@ -130,9 +130,9 @@ public:
const query::result_row_view& row) {
update_parameters::prefetch_data::row cells;
auto add_cell = [&cells] (column_id id, std::experimental::optional<collection_mutation::view>&& cell) {
auto add_cell = [&cells] (column_id id, std::experimental::optional<collection_mutation_view>&& cell) {
if (cell) {
cells.emplace(id, collection_mutation::one{to_bytes(cell->data)});
cells.emplace(id, collection_mutation{to_bytes(cell->data)});
}
};
@@ -541,6 +541,14 @@ modification_statement::validate(distributed<service::storage_proxy>&, const ser
}
}
bool modification_statement::depends_on_keyspace(const sstring& ks_name) const {
return keyspace() == ks_name;
}
bool modification_statement::depends_on_column_family(const sstring& cf_name) const {
return column_family() == cf_name;
}
}
}

View File

@@ -188,6 +188,10 @@ public:
void validate(distributed<service::storage_proxy>&, const service::client_state& state) override;
virtual bool depends_on_keyspace(const sstring& ks_name) const override;
virtual bool depends_on_column_family(const sstring& cf_name) const override;
void add_operation(::shared_ptr<operation> op) {
if (op->column.is_static()) {
_sets_static_columns = true;

View File

@@ -47,6 +47,50 @@ namespace cql3 {
namespace statements {
schema_altering_statement::schema_altering_statement()
: cf_statement{::shared_ptr<cf_name>{}}
, _is_column_family_level{false}
{
}
schema_altering_statement::schema_altering_statement(::shared_ptr<cf_name> name)
: cf_statement{std::move(name)}
, _is_column_family_level{true}
{
}
bool schema_altering_statement::uses_function(const sstring& ks_name, const sstring& function_name) const
{
return cf_statement::uses_function(ks_name, function_name);
}
bool schema_altering_statement::depends_on_keyspace(const sstring& ks_name) const
{
return false;
}
bool schema_altering_statement::depends_on_column_family(const sstring& cf_name) const
{
return false;
}
uint32_t schema_altering_statement::get_bound_terms()
{
return 0;
}
void schema_altering_statement::prepare_keyspace(const service::client_state& state)
{
if (_is_column_family_level) {
cf_statement::prepare_keyspace(state);
}
}
::shared_ptr<parsed_statement::prepared> schema_altering_statement::prepare(database& db)
{
return ::make_shared<parsed_statement::prepared>(this->shared_from_this());
}
future<::shared_ptr<messages::result_message>>
schema_altering_statement::execute0(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options, bool is_local_only) {
// If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change. To avoid doing

View File

@@ -41,16 +41,7 @@
#pragma once
namespace transport {
namespace messages {
class result_message;
}
}
#include "transport/messages_fwd.hh"
#include "transport/event.hh"
#include "cql3/statements/cf_statement.hh"
@@ -76,33 +67,21 @@ private:
future<::shared_ptr<messages::result_message>>
execute0(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options, bool);
protected:
schema_altering_statement()
: cf_statement{::shared_ptr<cf_name>{}}
, _is_column_family_level{false}
{ }
schema_altering_statement();
schema_altering_statement(::shared_ptr<cf_name> name)
: cf_statement{std::move(name)}
, _is_column_family_level{true}
{ }
schema_altering_statement(::shared_ptr<cf_name> name);
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override {
return cf_statement::uses_function(ks_name, function_name);
}
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override;
virtual uint32_t get_bound_terms() override {
return 0;
}
virtual bool depends_on_keyspace(const sstring& ks_name) const override;
virtual void prepare_keyspace(const service::client_state& state) override {
if (_is_column_family_level) {
cf_statement::prepare_keyspace(state);
}
}
virtual bool depends_on_column_family(const sstring& cf_name) const override;
virtual ::shared_ptr<prepared> prepare(database& db) override {
return ::make_shared<parsed_statement::prepared>(this->shared_from_this());
}
virtual uint32_t get_bound_terms() override;
virtual void prepare_keyspace(const service::client_state& state) override;
virtual ::shared_ptr<prepared> prepare(database& db) override;
virtual shared_ptr<transport::event::schema_change> change_event() = 0;

View File

@@ -46,6 +46,7 @@
#include "core/shared_ptr.hh"
#include "query-result-reader.hh"
#include "query_result_merger.hh"
#include "service/pager/query_pagers.hh"
namespace cql3 {
@@ -106,6 +107,14 @@ void select_statement::validate(distributed<service::storage_proxy>&, const serv
// Nothing to do, all validation has been done by raw_statemet::prepare()
}
bool select_statement::depends_on_keyspace(const sstring& ks_name) const {
return keyspace() == ks_name;
}
bool select_statement::depends_on_column_family(const sstring& cf_name) const {
return column_family() == cf_name;
}
query::partition_slice
select_statement::make_partition_slice(const query_options& options) {
std::vector<column_id> static_columns;
@@ -152,7 +161,7 @@ int32_t select_statement::get_limit(const query_options& options) const {
try {
int32_type->validate(*val);
auto l = boost::any_cast<int32_t>(int32_type->deserialize(*val));
auto l = value_cast<int32_t>(int32_type->deserialize(*val));
if (l <= 0) {
throw exceptions::invalid_request_exception("LIMIT must be strictly positive");
}
@@ -187,37 +196,51 @@ select_statement::execute(distributed<service::storage_proxy>& proxy, service::q
page_size = DEFAULT_COUNT_PAGE_SIZE;
}
warn(unimplemented::cause::PAGING);
return execute(proxy, command, _restrictions->get_partition_key_ranges(options), state, options, now);
auto key_ranges = _restrictions->get_partition_key_ranges(options);
#if 0
if (page_size <= 0 || !command || !query_pagers::may_need_paging(command, page_size)) {
return execute(proxy, command, state, options, now);
if (page_size <= 0
|| !service::pager::query_pagers::may_need_paging(page_size,
*command, key_ranges)) {
return execute(proxy, command, std::move(key_ranges), state, options,
now);
}
auto pager = query_pagers::pager(command, cl, state.get_client_state(), options.get_paging_state());
auto p = service::pager::query_pagers::pager(_schema, _selection,
state, options, command, std::move(key_ranges));
if (selection->isAggregate()) {
return page_aggregate_query(pager, options, page_size, now);
if (_selection->is_aggregate()) {
return do_with(
cql3::selection::result_set_builder(*_selection, now,
options.get_serialization_format()),
[p, page_size, now](auto& builder) {
return do_until([p] {return p->is_exhausted();},
[p, &builder, page_size, now] {
return p->fetch_page(builder, page_size, now);
}
).then([&builder] {
auto rs = builder.build();
auto msg = ::make_shared<transport::messages::result_message::rows>(std::move(rs));
return make_ready_future<shared_ptr<transport::messages::result_message>>(std::move(msg));
});
});
}
// We can't properly do post-query ordering if we page (see #6722)
if (needs_post_query_ordering()) {
throw exceptions::invalid_request_exception(
"Cannot page queries with both ORDER BY and a IN restriction on the partition key;"
" you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
"Cannot page queries with both ORDER BY and a IN restriction on the partition key;"
" you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
}
return pager->fetch_page(page_size).then([this, pager, &options, limit, now] (auto page) {
auto msg = process_results(page, options, limit, now);
return p->fetch_page(page_size, now).then(
[this, p, &options, limit, now](std::unique_ptr<cql3::result_set> rs) {
if (!pager->is_exhausted()) {
msg->result->metadata->set_has_more_pages(pager->state());
}
if (!p->is_exhausted()) {
rs->get_metadata().set_has_more_pages(p->state());
}
return msg;
});
#endif
auto msg = ::make_shared<transport::messages::result_message::rows>(std::move(rs));
return make_ready_future<shared_ptr<transport::messages::result_message>>(std::move(msg));
});
}
future<shared_ptr<transport::messages::result_message>>
@@ -273,114 +296,18 @@ select_statement::execute_internal(distributed<service::storage_proxy>& proxy, s
}
}
// Implements ResultVisitor concept from query.hh
class result_set_building_visitor {
cql3::selection::result_set_builder& builder;
select_statement& stmt;
uint32_t _row_count;
std::vector<bytes> _partition_key;
std::vector<bytes> _clustering_key;
public:
result_set_building_visitor(cql3::selection::result_set_builder& builder, select_statement& stmt)
: builder(builder)
, stmt(stmt)
, _row_count(0)
{ }
void add_value(const column_definition& def, query::result_row_view::iterator_type& i) {
if (def.type->is_multi_cell()) {
auto cell = i.next_collection_cell();
if (!cell) {
builder.add_empty();
return;
}
builder.add(def, *cell);
} else {
auto cell = i.next_atomic_cell();
if (!cell) {
builder.add_empty();
return;
}
builder.add(def, *cell);
}
};
void accept_new_partition(const partition_key& key, uint32_t row_count) {
_partition_key = key.explode(*stmt._schema);
_row_count = row_count;
}
void accept_new_partition(uint32_t row_count) {
_row_count = row_count;
}
void accept_new_row(const clustering_key& key, const query::result_row_view& static_row,
const query::result_row_view& row) {
_clustering_key = key.explode(*stmt._schema);
accept_new_row(static_row, row);
}
void accept_new_row(const query::result_row_view& static_row, const query::result_row_view& row) {
auto static_row_iterator = static_row.iterator();
auto row_iterator = row.iterator();
builder.new_row();
for (auto&& def : stmt._selection->get_columns()) {
switch (def->kind) {
case column_kind::partition_key:
builder.add(_partition_key[def->component_index()]);
break;
case column_kind::clustering_key:
builder.add(_clustering_key[def->component_index()]);
break;
case column_kind::regular_column:
add_value(*def, row_iterator);
break;
case column_kind::compact_column:
add_value(*def, row_iterator);
break;
case column_kind::static_column:
add_value(*def, static_row_iterator);
break;
default:
assert(0);
}
}
}
void accept_partition_end(const query::result_row_view& static_row) {
if (_row_count == 0) {
builder.new_row();
auto static_row_iterator = static_row.iterator();
for (auto&& def : stmt._selection->get_columns()) {
if (def->is_partition_key()) {
builder.add(_partition_key[def->component_index()]);
} else if (def->is_static()) {
add_value(*def, static_row_iterator);
} else {
builder.add_empty();
}
}
}
}
};
shared_ptr<transport::messages::result_message>
select_statement::process_results(foreign_ptr<lw_shared_ptr<query::result>> results, lw_shared_ptr<query::read_command> cmd,
const query_options& options, db_clock::time_point now) {
cql3::selection::result_set_builder builder(*_selection, now, options.get_serialization_format());
// FIXME: This special casing saves us the cost of copying an already
// linearized response. When we switch views to scattered_reader this will go away.
if (results->buf().is_linearized()) {
query::result_view view(results->buf().view());
view.consume(cmd->slice, result_set_building_visitor(builder, *this));
} else {
bytes_ostream w(results->buf());
query::result_view view(w.linearize());
view.consume(cmd->slice, result_set_building_visitor(builder, *this));
}
shared_ptr<transport::messages::result_message> select_statement::process_results(
foreign_ptr<lw_shared_ptr<query::result>> results,
lw_shared_ptr<query::read_command> cmd, const query_options& options,
db_clock::time_point now) {
cql3::selection::result_set_builder builder(*_selection, now,
options.get_serialization_format());
query::result_view::consume(results->buf(), cmd->slice,
cql3::selection::result_set_builder::visitor(builder, *_schema,
*_selection));
auto rs = builder.build();
if (needs_post_query_ordering()) {
rs->sort(_ordering_comparator);
if (_is_reversed) {

View File

@@ -63,7 +63,6 @@ namespace statements {
*
*/
class select_statement : public cql_statement {
friend class result_set_building_visitor;
public:
class parameters final {
public:
@@ -132,6 +131,8 @@ public:
virtual uint32_t get_bound_terms() override;
virtual void check_access(const service::client_state& state) override;
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override;
virtual bool depends_on_keyspace(const sstring& ks_name) const;
virtual bool depends_on_column_family(const sstring& cf_name) const;
virtual future<::shared_ptr<transport::messages::result_message>> execute(distributed<service::storage_proxy>& proxy,
service::query_state& state, const query_options& options) override;
@@ -192,18 +193,16 @@ public:
QueryOptions options = QueryOptions.DEFAULT;
return process(rows, options, getLimit(options), System.currentTimeMillis());
}
public String keyspace()
{
return _schema.ks_name;
}
public String columnFamily()
{
return _schema.cfName;
}
#endif
const sstring& keyspace() const {
return _schema->ks_name();
}
const sstring& column_family() const {
return _schema->cf_name();
}
query::partition_slice make_partition_slice(const query_options& options);
#if 0

View File

@@ -68,6 +68,16 @@ bool truncate_statement::uses_function(const sstring& ks_name, const sstring& fu
return parsed_statement::uses_function(ks_name, function_name);
}
bool truncate_statement::depends_on_keyspace(const sstring& ks_name) const
{
return false;
}
bool truncate_statement::depends_on_column_family(const sstring& cf_name) const
{
return false;
}
void truncate_statement::check_access(const service::client_state& state)
{
warn(unimplemented::cause::AUTH);

View File

@@ -60,6 +60,10 @@ public:
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override;
virtual bool depends_on_keyspace(const sstring& ks_name) const override;
virtual bool depends_on_column_family(const sstring& cf_name) const override;
virtual void check_access(const service::client_state& state) override;
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override;

View File

@@ -47,6 +47,45 @@ namespace cql3 {
namespace statements {
use_statement::use_statement(sstring keyspace)
: _keyspace(keyspace)
{
}
uint32_t use_statement::get_bound_terms()
{
return 0;
}
::shared_ptr<parsed_statement::prepared> use_statement::prepare(database& db)
{
return ::make_shared<parsed_statement::prepared>(this->shared_from_this());
}
bool use_statement::uses_function(const sstring& ks_name, const sstring& function_name) const
{
return parsed_statement::uses_function(ks_name, function_name);
}
bool use_statement::depends_on_keyspace(const sstring& ks_name) const
{
return false;
}
bool use_statement::depends_on_column_family(const sstring& cf_name) const
{
return false;
}
void use_statement::check_access(const service::client_state& state)
{
state.validate_login();
}
void use_statement::validate(distributed<service::storage_proxy>&, const service::client_state& state)
{
}
future<::shared_ptr<transport::messages::result_message>>
use_statement::execute(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) {
state.get_client_state().set_keyspace(proxy.local().get_db(), _keyspace);

View File

@@ -42,17 +42,9 @@
#pragma once
#include "cql3/statements/parsed_statement.hh"
#include "transport/messages_fwd.hh"
#include "cql3/cql_statement.hh"
namespace transport {
namespace messages {
class result_message;
}
}
namespace cql3 {
namespace statements {
@@ -62,49 +54,27 @@ private:
const sstring _keyspace;
public:
use_statement(sstring keyspace)
: _keyspace(keyspace)
{ }
use_statement(sstring keyspace);
virtual uint32_t get_bound_terms() override {
return 0;
}
virtual uint32_t get_bound_terms() override;
virtual ::shared_ptr<prepared> prepare(database& db) override {
return ::make_shared<parsed_statement::prepared>(this->shared_from_this());
}
virtual ::shared_ptr<prepared> prepare(database& db) override;
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override {
return parsed_statement::uses_function(ks_name, function_name);
}
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override;
virtual void check_access(const service::client_state& state) override {
state.validate_login();
}
virtual bool depends_on_keyspace(const sstring& ks_name) const override;
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override {
}
virtual bool depends_on_column_family(const sstring& cf_name) const override;
virtual void check_access(const service::client_state& state) override;
virtual void validate(distributed<service::storage_proxy>&, const service::client_state& state) override;
virtual future<::shared_ptr<transport::messages::result_message>>
execute(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) override;
virtual future<::shared_ptr<transport::messages::result_message>>
execute_internal(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) override;
#if 0
virtual future<::shared_ptr<transport::messages::result_message>>
execute(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) override {
state.get_client_state().set_keyspace(_keyspace);
auto result =::make_shared<transport::messages::result_message::set_keyspace>(_keyspace);
return make_ready_future<::shared_ptr<transport::messages::result_message>>(result);
}
virtual future<::shared_ptr<transport::messages::result_message>>
execute_internal(distributed<service::storage_proxy>& proxy, service::query_state& state, const query_options& options) override {
// Internal queries are exclusively on the system keyspace and 'use' is thus useless
throw std::runtime_error("unsupported operation");
}
#endif
};
}

View File

@@ -259,7 +259,7 @@ public:
try {
// Collections have this small hack that validate cannot be called on a serialized object,
// but the deserialization does the validation (so we're fine).
auto l = boost::any_cast<list_type_impl::native_type>(type->deserialize(value, options.get_serialization_format()));
auto l = value_cast<list_type_impl::native_type>(type->deserialize(value, options.get_serialization_format()));
auto ttype = dynamic_pointer_cast<const tuple_type_impl>(type->get_elements_type());
assert(ttype);

View File

@@ -66,7 +66,7 @@ public:
}
template<typename T>
T get_as(const sstring& name) const {
return boost::any_cast<T>(data_type_for<T>()->deserialize(get_blob(name)));
return value_cast<T>(data_type_for<T>()->deserialize(get_blob(name)));
}
// this could maybe be done as an overload of get_as (or something), but that just
// muddles things for no real gain. Let user (us) attempt to know what he is doing instead.
@@ -75,12 +75,12 @@ public:
data_type_for<K>(), data_type valtype =
data_type_for<V>()) const {
auto vec =
boost::any_cast<const map_type_impl::native_type&>(
value_cast<map_type_impl::native_type>(
map_type_impl::get_instance(keytype, valtype, false)->deserialize(
get_blob(name)));
std::transform(vec.begin(), vec.end(), out,
[](auto& p) {
return std::pair<K, V>(boost::any_cast<const K&>(p.first), boost::any_cast<const V&>(p.second));
return std::pair<K, V>(value_cast<K>(p.first), value_cast<V>(p.second));
});
}
template<typename K, typename V, typename ... Rest>

View File

@@ -43,7 +43,7 @@
namespace cql3 {
std::experimental::optional<collection_mutation::view>
std::experimental::optional<collection_mutation_view>
update_parameters::get_prefetched_list(
const partition_key& pkey,
const clustering_key& row_key,

View File

@@ -86,7 +86,7 @@ public:
return pk_eq(k1.first, k2.first) && ck_eq(k1.second, k2.second);
}
};
using row = std::unordered_map<column_id, collection_mutation::one>;
using row = std::unordered_map<column_id, collection_mutation>;
public:
std::unordered_map<key, row, key_hashing, key_equality> rows;
schema_ptr schema;
@@ -183,7 +183,7 @@ public:
return _timestamp;
}
std::experimental::optional<collection_mutation::view> get_prefetched_list(
std::experimental::optional<collection_mutation_view> get_prefetched_list(
const partition_key& pkey, const clustering_key& row_key, const column_definition& column) const;
};

View File

@@ -34,6 +34,7 @@
#include "cql3/column_identifier.hh"
#include "core/seastar.hh"
#include <seastar/core/sleep.hh>
#include <seastar/core/rwlock.hh>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include "sstables/sstables.hh"
@@ -53,20 +54,41 @@
#include "mutation_query.hh"
#include "sstable_mutation_readers.hh"
#include <core/fstream.hh>
#include <seastar/core/enum.hh>
#include "utils/latency.hh"
#include "utils/flush_queue.hh"
using namespace std::chrono_literals;
logging::logger dblog("database");
// Slight extension to the flush_queue type.
class column_family::memtable_flush_queue : public utils::flush_queue<db::replay_position> {
public:
template<typename Func, typename Post>
auto run_cf_flush(db::replay_position rp, Func&& func, Post&& post) {
// special case: empty rp, yet still data.
// We generate a few memtables with no valid, "high_rp", yet
// still containing data -> actual flush.
// And to make matters worse, we can initiate a flush of N such
// tables at the same time.
// Just queue them at the end of the queue and treat them as such.
if (rp == db::replay_position() && !empty()) {
rp = highest_key();
}
return run_with_ordered_post_op(rp, std::forward<Func>(func), std::forward<Post>(post));
}
};
column_family::column_family(schema_ptr schema, config config, db::commitlog& cl, compaction_manager& compaction_manager)
: _schema(std::move(schema))
, _config(std::move(config))
, _memtables(make_lw_shared(memtable_list{}))
, _sstables(make_lw_shared<sstable_list>())
, _cache(_schema, sstables_as_mutation_source(), global_cache_tracker())
, _cache(_schema, sstables_as_mutation_source(), sstables_as_key_source(), global_cache_tracker())
, _commitlog(&cl)
, _compaction_manager(compaction_manager)
, _flush_queue(std::make_unique<memtable_flush_queue>())
{
add_memtable();
if (!_config.enable_disk_writes) {
@@ -79,9 +101,10 @@ column_family::column_family(schema_ptr schema, config config, no_commitlog cl,
, _config(std::move(config))
, _memtables(make_lw_shared(memtable_list{}))
, _sstables(make_lw_shared<sstable_list>())
, _cache(_schema, sstables_as_mutation_source(), global_cache_tracker())
, _cache(_schema, sstables_as_mutation_source(), sstables_as_key_source(), global_cache_tracker())
, _commitlog(nullptr)
, _compaction_manager(compaction_manager)
, _flush_queue(std::make_unique<memtable_flush_queue>())
{
add_memtable();
if (!_config.enable_disk_writes) {
@@ -196,6 +219,24 @@ column_family::make_sstable_reader(const query::partition_range& pr) const {
}
}
key_source column_family::sstables_as_key_source() const {
return [this] (const query::partition_range& range) {
std::vector<key_reader> readers;
readers.reserve(_sstables->size());
std::transform(_sstables->begin(), _sstables->end(), std::back_inserter(readers), [&] (auto&& entry) {
auto& sst = entry.second;
auto rd = sstables::make_key_reader(_schema, sst, range);
if (sst->is_shared()) {
rd = make_filtering_reader(std::move(rd), [] (const dht::decorated_key& dk) {
return dht::shard_of(dk.token()) == engine().cpu_id();
});
}
return rd;
});
return make_combined_reader(_schema, std::move(readers));
};
}
// Exposed for testing, not performance critical.
future<column_family::const_mutation_partition_ptr>
column_family::find_partition(const dht::decorated_key& key) const {
@@ -259,8 +300,8 @@ column_family::make_reader(const query::partition_range& range) const {
// range queries in cache, so that scans can always be satisfied form
// memtable and cache only, as long as data is not evicted.
//
// https://github.com/cloudius-systems/urchin/issues/309
// https://github.com/cloudius-systems/urchin/issues/185
// https://github.com/scylladb/scylla/issues/309
// https://github.com/scylladb/scylla/issues/185
for (auto&& mt : *_memtables) {
readers.emplace_back(mt->make_reader(range));
@@ -315,14 +356,17 @@ column_family::for_all_partitions_slow(std::function<bool (const dht::decorated_
}
class lister {
public:
using dir_entry_types = std::unordered_set<directory_entry_type, enum_hash<directory_entry_type>>;
private:
file _f;
std::function<future<> (directory_entry de)> _walker;
directory_entry_type _expected_type;
dir_entry_types _expected_type;
subscription<directory_entry> _listing;
sstring _dirname;
public:
lister(file f, directory_entry_type type, std::function<future<> (directory_entry)> walker, sstring dirname)
lister(file f, dir_entry_types type, std::function<future<> (directory_entry)> walker, sstring dirname)
: _f(std::move(f))
, _walker(std::move(walker))
, _expected_type(type)
@@ -330,13 +374,13 @@ public:
, _dirname(dirname) {
}
static future<> scan_dir(sstring name, directory_entry_type type, std::function<future<> (directory_entry)> walker);
static future<> scan_dir(sstring name, dir_entry_types type, std::function<future<> (directory_entry)> walker);
protected:
future<> _visit(directory_entry de) {
return guarantee_type(std::move(de)).then([this] (directory_entry de) {
// Hide all synthetic directories and hidden files.
if ((de.type != _expected_type) || (de.name[0] == '.')) {
if ((!_expected_type.count(*(de.type))) || (de.name[0] == '.')) {
return make_ready_future<>();
}
return _walker(de);
@@ -359,8 +403,7 @@ private:
};
future<> lister::scan_dir(sstring name, directory_entry_type type, std::function<future<> (directory_entry)> walker) {
future<> lister::scan_dir(sstring name, lister::dir_entry_types type, std::function<future<> (directory_entry)> walker) {
return engine().open_directory(name).then([type, walker = std::move(walker), name] (file f) {
auto l = make_lw_shared<lister>(std::move(f), type, walker, name);
return l->done().then([l] { });
@@ -373,6 +416,23 @@ static std::vector<sstring> parse_fname(sstring filename) {
return comps;
}
static bool belongs_to_current_shard(const schema& s, const partition_key& first, const partition_key& last) {
auto key_shard = [&s] (const partition_key& pk) {
auto token = dht::global_partitioner().get_token(s, pk);
return dht::shard_of(token);
};
auto s1 = key_shard(first);
auto s2 = key_shard(last);
auto me = engine().cpu_id();
return (s1 <= me) && (me <= s2);
}
static bool belongs_to_current_shard(const schema& s, range<partition_key> r) {
assert(r.start());
assert(r.end());
return belongs_to_current_shard(s, r.start()->value(), r.end()->value());
}
future<sstables::entry_descriptor> column_family::probe_file(sstring sstdir, sstring fname) {
using namespace sstables;
@@ -386,16 +446,24 @@ future<sstables::entry_descriptor> column_family::probe_file(sstring sstdir, sst
return make_ready_future<entry_descriptor>(std::move(comps));
}
// Make sure new sstables don't overwrite this one.
_sstable_generation = std::max<uint64_t>(_sstable_generation, comps.generation / smp::count + 1);
update_sstables_known_generation(comps.generation);
assert(_sstables->count(comps.generation) == 0);
auto sst = std::make_unique<sstables::sstable>(_schema->ks_name(), _schema->cf_name(), sstdir, comps.generation, comps.version, comps.format);
auto fut = sst->load();
return std::move(fut).then([this, sst = std::move(sst)] () mutable {
add_sstable(std::move(*sst));
return make_ready_future<>();
}).then_wrapped([fname, comps = std::move(comps)] (future<> f) {
auto fut = sstable::get_sstable_key_range(*_schema, _schema->ks_name(), _schema->cf_name(), sstdir, comps.generation, comps.version, comps.format);
return std::move(fut).then([this, sstdir = std::move(sstdir), comps] (range<partition_key> r) {
// Checks whether or not sstable belongs to current shard.
if (!belongs_to_current_shard(*_schema, std::move(r))) {
sstable::mark_sstable_for_deletion(_schema->ks_name(), _schema->cf_name(), sstdir, comps.generation, comps.version, comps.format);
return make_ready_future<>();
}
auto sst = std::make_unique<sstables::sstable>(_schema->ks_name(), _schema->cf_name(), sstdir, comps.generation, comps.version, comps.format);
auto fut = sst->load();
return std::move(fut).then([this, sst = std::move(sst)] () mutable {
add_sstable(std::move(*sst));
return make_ready_future<>();
});
}).then_wrapped([fname, comps] (future<> f) {
try {
f.get();
} catch (malformed_sstable_exception& e) {
@@ -420,19 +488,6 @@ void column_family::add_sstable(sstables::sstable&& sstable) {
}
void column_family::add_sstable(lw_shared_ptr<sstables::sstable> sstable) {
auto key_shard = [this] (const partition_key& pk) {
auto token = dht::global_partitioner().get_token(*_schema, pk);
return dht::shard_of(token);
};
auto s1 = key_shard(sstable->get_first_partition_key(*_schema));
auto s2 = key_shard(sstable->get_last_partition_key(*_schema));
auto me = engine().cpu_id();
auto included = (s1 <= me) && (me <= s2);
if (!included) {
dblog.info("sstable {} not relevant for this shard, ignoring", sstable->get_filename());
sstable->mark_for_deletion();
return;
}
auto generation = sstable->generation();
// allow in-progress reads to continue using old list
_sstables = make_lw_shared<sstable_list>(*_sstables);
@@ -477,8 +532,17 @@ column_family::seal_active_memtable() {
);
_highest_flushed_rp = old->replay_position();
return seastar::with_gate(_in_flight_seals, [old, this] {
return flush_memtable_to_sstable(old);
return _flush_queue->run_cf_flush(old->replay_position(), [old, this] {
return repeat([this, old] {
return with_lock(_sstables_lock.for_read(), [this, old] {
_flush_queue->check_open_gate();
return try_flush_memtable_to_sstable(old);
});
});
}, [old, this] {
if (_commitlog) {
_commitlog->discard_completed_segments(_schema->id(), old->replay_position());
}
});
// FIXME: release commit log
// FIXME: provide back-pressure to upper layers
@@ -495,6 +559,10 @@ column_family::try_flush_memtable_to_sstable(lw_shared_ptr<memtable> old) {
sstables::sstable::version_types::ka,
sstables::sstable::format_types::big);
auto memtable_size = old->occupancy().total_space();
_config.cf_stats->pending_memtables_flushes_count++;
_config.cf_stats->pending_memtables_flushes_bytes += memtable_size;
newtab->set_unshared();
dblog.debug("Flushing to {}", newtab->get_filename());
return newtab->write_components(*old).then([this, newtab, old] {
@@ -518,38 +586,35 @@ column_family::try_flush_memtable_to_sstable(lw_shared_ptr<memtable> old) {
return newtab->create_links(dir);
});
});
}).then([this, old, newtab] {
}).then_wrapped([this, old, newtab, memtable_size] (future<> ret) {
_config.cf_stats->pending_memtables_flushes_count--;
_config.cf_stats->pending_memtables_flushes_bytes -= memtable_size;
dblog.debug("Flushing done");
// We must add sstable before we call update_cache(), because
// memtable's data after moving to cache can be evicted at any time.
auto old_sstables = _sstables;
add_sstable(newtab);
old->mark_flushed(newtab);
return update_cache(*old, std::move(old_sstables));
}).then_wrapped([this, old] (future<> ret) {
try {
ret.get();
// FIXME: until the surrounding function returns a future and
// caller ensures ordering (i.e. finish flushing one or more sequential tables before
// doing the discard), this below is _not_ correct, since the use of replay_position
// depends on us reporting the factual highest position we've actually flushed,
// _and_ all positions (for a given UUID) below having been dealt with.
//
// Note that the whole scheme is also dependent on memtables being "allocated" in order,
// i.e. we may not flush a younger memtable before and older, and we need to use the
// highest rp.
if (_commitlog) {
_commitlog->discard_completed_segments(_schema->id(), old->replay_position());
}
_memtables->erase(boost::range::find(*_memtables, old));
dblog.debug("Memtable replaced");
// We must add sstable before we call update_cache(), because
// memtable's data after moving to cache can be evicted at any time.
auto old_sstables = _sstables;
add_sstable(newtab);
old->mark_flushed(newtab);
trigger_compaction();
return make_ready_future<stop_iteration>(stop_iteration::yes);
} catch (std::exception& e) {
dblog.error("failed to write sstable: {}", e.what());
return update_cache(*old, std::move(old_sstables)).then_wrapped([this, old] (future<> f) {
try {
f.get();
} catch(...) {
dblog.error("failed to move memtable to cache: {}", std::current_exception());
}
_memtables->erase(boost::range::find(*_memtables, old));
dblog.debug("Memtable replaced");
return make_ready_future<stop_iteration>(stop_iteration::yes);
});
} catch (...) {
dblog.error("failed to write sstable: unknown error");
dblog.error("failed to write sstable: {}", std::current_exception());
}
return sleep(10s).then([] {
return make_ready_future<stop_iteration>(stop_iteration::no);
@@ -557,15 +622,6 @@ column_family::try_flush_memtable_to_sstable(lw_shared_ptr<memtable> old) {
});
}
future<>
column_family::flush_memtable_to_sstable(lw_shared_ptr<memtable> memt) {
return repeat([this, memt] {
return seastar::with_gate(_in_flight_seals, [memt, this] {
return try_flush_memtable_to_sstable(memt);
});
});
}
void
column_family::start() {
// FIXME: add option to disable automatic compaction.
@@ -575,70 +631,140 @@ column_family::start() {
future<>
column_family::stop() {
seal_active_memtable();
return _compaction_manager.remove(this).then([this] {
return _in_flight_seals.close().then([this] {
return make_ready_future<>();
return _flush_queue->close();
});
}
future<std::vector<sstables::entry_descriptor>>
column_family::reshuffle_sstables(int64_t start) {
struct work {
int64_t current_gen;
sstable_list sstables;
std::unordered_map<int64_t, sstables::entry_descriptor> descriptors;
std::vector<sstables::entry_descriptor> reshuffled;
work(int64_t start) : current_gen(start ? start : 1) {}
};
return do_with(work(start), [this] (work& work) {
return lister::scan_dir(_config.datadir, { directory_entry_type::regular }, [this, &work] (directory_entry de) {
auto comps = sstables::entry_descriptor::make_descriptor(de.name);
if (comps.component != sstables::sstable::component_type::TOC) {
return make_ready_future<>();
} else if (comps.generation < work.current_gen) {
return make_ready_future<>();
}
auto sst = make_lw_shared<sstables::sstable>(_schema->ks_name(), _schema->cf_name(),
_config.datadir, comps.generation,
comps.version, comps.format);
work.sstables.emplace(comps.generation, std::move(sst));
work.descriptors.emplace(comps.generation, std::move(comps));
// FIXME: This is the only place in which we actually issue disk activity aside from
// directory metadata operations.
//
// But without the TOC information, we don't know which files we should link.
// The alternative to that would be to change create link to try creating a
// link for all possible files and handling the failures gracefuly, but that's not
// exactly fast either.
//
// Those SSTables are not known by anyone in the system. So we don't have any kind of
// object describing them. There isn't too much of a choice.
return work.sstables[comps.generation]->read_toc();
}).then([&work] {
// Note: cannot be parallel because we will be shuffling things around at this stage. Can't race.
return do_for_each(work.sstables, [&work] (auto& pair) {
auto&& comps = std::move(work.descriptors.at(pair.first));
comps.generation = work.current_gen;
work.reshuffled.push_back(std::move(comps));
if (pair.first == work.current_gen) {
++work.current_gen;
return make_ready_future<>();
}
return pair.second->set_generation(work.current_gen++);
});
}).then([&work] {
return make_ready_future<std::vector<sstables::entry_descriptor>>(std::move(work.reshuffled));
});
});
}
future<>
column_family::compact_sstables(std::vector<sstables::shared_sstable> sstables) {
if (!sstables.size()) {
column_family::compact_sstables(sstables::compaction_descriptor descriptor) {
if (!descriptor.sstables.size()) {
// if there is nothing to compact, just return.
return make_ready_future<>();
}
auto sstables_to_compact = make_lw_shared<std::vector<sstables::shared_sstable>>(std::move(sstables));
return with_lock(_sstables_lock.for_read(), [this, descriptor = std::move(descriptor)] {
auto sstables_to_compact = make_lw_shared<std::vector<sstables::shared_sstable>>(std::move(descriptor.sstables));
auto new_tables = make_lw_shared<std::vector<
std::pair<unsigned, sstables::shared_sstable>>>();
auto create_sstable = [this, new_tables] {
// FIXME: this generation calculation should be in a function.
auto gen = _sstable_generation++ * smp::count + engine().cpu_id();
// FIXME: use "tmp" marker in names of incomplete sstable
auto sst = make_lw_shared<sstables::sstable>(_schema->ks_name(), _schema->cf_name(), _config.datadir, gen,
sstables::sstable::version_types::ka,
sstables::sstable::format_types::big);
sst->set_unshared();
new_tables->emplace_back(gen, sst);
return sst;
};
return sstables::compact_sstables(*sstables_to_compact, *this,
create_sstable).then([this, new_tables, sstables_to_compact] {
// Build a new list of _sstables: We remove from the existing list the
// tables we compacted (by now, there might be more sstables flushed
// later), and we add the new tables generated by the compaction.
// We create a new list rather than modifying it in-place, so that
// on-going reads can continue to use the old list.
auto current_sstables = _sstables;
_sstables = make_lw_shared<sstable_list>();
auto new_tables = make_lw_shared<std::vector<
std::pair<unsigned, sstables::shared_sstable>>>();
auto create_sstable = [this, new_tables] {
// FIXME: this generation calculation should be in a function.
auto gen = _sstable_generation++ * smp::count + engine().cpu_id();
// FIXME: use "tmp" marker in names of incomplete sstable
auto sst = make_lw_shared<sstables::sstable>(_schema->ks_name(), _schema->cf_name(), _config.datadir, gen,
sstables::sstable::version_types::ka,
sstables::sstable::format_types::big);
sst->set_unshared();
new_tables->emplace_back(gen, sst);
return sst;
};
return sstables::compact_sstables(*sstables_to_compact, *this,
create_sstable, descriptor.max_sstable_bytes, descriptor.level).then([this, new_tables, sstables_to_compact] {
// Build a new list of _sstables: We remove from the existing list the
// tables we compacted (by now, there might be more sstables flushed
// later), and we add the new tables generated by the compaction.
// We create a new list rather than modifying it in-place, so that
// on-going reads can continue to use the old list.
auto current_sstables = _sstables;
_sstables = make_lw_shared<sstable_list>();
// zeroing live_disk_space_used and live_sstable_count because the
// sstable list is re-created below.
_stats.live_disk_space_used = 0;
_stats.live_sstable_count = 0;
// zeroing live_disk_space_used and live_sstable_count because the
// sstable list is re-created below.
_stats.live_disk_space_used = 0;
_stats.live_sstable_count = 0;
std::unordered_set<sstables::shared_sstable> s(
sstables_to_compact->begin(), sstables_to_compact->end());
for (const auto& oldtab : *current_sstables) {
if (!s.count(oldtab.second)) {
update_stats_for_new_sstable(oldtab.second->data_size());
_sstables->emplace(oldtab.first, oldtab.second);
std::unordered_set<sstables::shared_sstable> s(
sstables_to_compact->begin(), sstables_to_compact->end());
for (const auto& oldtab : *current_sstables) {
if (!s.count(oldtab.second)) {
update_stats_for_new_sstable(oldtab.second->data_size());
_sstables->emplace(oldtab.first, oldtab.second);
}
for (const auto& newtab : *new_tables) {
// FIXME: rename the new sstable(s). Verify a rename doesn't cause
// problems for the sstable object.
update_stats_for_new_sstable(newtab.second->data_size());
_sstables->emplace(newtab.first, newtab.second);
}
for (const auto& oldtab : *sstables_to_compact) {
oldtab->mark_for_deletion();
}
}
}
});
});
}
for (const auto& newtab : *new_tables) {
// FIXME: rename the new sstable(s). Verify a rename doesn't cause
// problems for the sstable object.
update_stats_for_new_sstable(newtab.second->data_size());
_sstables->emplace(newtab.first, newtab.second);
}
for (const auto& oldtab : *sstables_to_compact) {
oldtab->mark_for_deletion();
}
future<>
column_family::load_new_sstables(std::vector<sstables::entry_descriptor> new_tables) {
return parallel_for_each(new_tables, [this] (auto comps) {
auto sst = make_lw_shared<sstables::sstable>(_schema->ks_name(), _schema->cf_name(), _config.datadir, comps.generation, comps.version, comps.format);
return sst->load().then([this, sst] {
return sst->mutate_sstable_level(0);
}).then([this, sst] {
auto first = sst->get_first_partition_key(*_schema);
auto last = sst->get_last_partition_key(*_schema);
if (belongs_to_current_shard(*_schema, first, last)) {
this->add_sstable(sst);
}
return make_ready_future<>();
});
});
}
@@ -653,7 +779,7 @@ column_family::compact_all_sstables() {
}
// FIXME: check if the lower bound min_compaction_threshold() from schema
// should be taken into account before proceeding with compaction.
return compact_sstables(std::move(sstables));
return compact_sstables(sstables::compaction_descriptor(std::move(sstables)));
}
void column_family::start_compaction() {
@@ -728,9 +854,10 @@ future<> column_family::populate(sstring sstdir) {
auto verifier = make_lw_shared<std::unordered_map<unsigned long, status>>();
auto descriptor = make_lw_shared<sstable_descriptor>();
return lister::scan_dir(sstdir, directory_entry_type::regular, [this, sstdir, verifier, descriptor] (directory_entry de) {
return do_with(std::vector<future<>>(), [this, sstdir, verifier, descriptor] (std::vector<future<>>& futures) {
return lister::scan_dir(sstdir, { directory_entry_type::regular }, [this, sstdir, verifier, descriptor, &futures] (directory_entry de) {
// FIXME: The secondary indexes are in this level, but with a directory type, (starting with ".")
return probe_file(sstdir, de.name).then([verifier, descriptor] (auto entry) {
auto f = probe_file(sstdir, de.name).then([verifier, descriptor] (auto entry) {
if (verifier->count(entry.generation)) {
if (verifier->at(entry.generation) == status::has_toc_file) {
if (entry.component == sstables::sstable::component_type::TOC) {
@@ -761,6 +888,23 @@ future<> column_family::populate(sstring sstdir) {
descriptor->format = entry.format;
}
});
// push future returned by probe_file into an array of futures,
// so that the supplied callback will not block scan_dir() from
// reading the next entry in the directory.
futures.push_back(std::move(f));
return make_ready_future<>();
}).then([&futures] {
return when_all(futures.begin(), futures.end()).then([] (std::vector<future<>> ret) {
try {
for (auto& f : ret) {
f.get();
}
} catch(...) {
throw;
}
});
}).then([verifier, sstdir, descriptor, this] {
return parallel_for_each(*verifier, [sstdir = std::move(sstdir), descriptor, this] (auto v) {
if (v.second == status::has_temporary_toc_file) {
@@ -782,6 +926,7 @@ future<> column_family::populate(sstring sstdir) {
return make_ready_future<>();
});
});
});
}
utils::UUID database::empty_version = utils::UUID_gen::get_name_UUID(bytes{});
@@ -815,6 +960,20 @@ database::setup_collectd() {
, scollectd::make_typed(scollectd::data_type::GAUGE, [this] {
return _dirty_memory_region_group.memory_used();
})));
_collectd.push_back(
scollectd::add_polled_metric(scollectd::type_instance_id("memtables"
, scollectd::per_cpu_plugin_instance
, "queue_length", "pending_flushes")
, scollectd::make_typed(scollectd::data_type::GAUGE, _cf_stats.pending_memtables_flushes_count)
));
_collectd.push_back(
scollectd::add_polled_metric(scollectd::type_instance_id("memtables"
, scollectd::per_cpu_plugin_instance
, "bytes", "pending_flushes")
, scollectd::make_typed(scollectd::data_type::GAUGE, _cf_stats.pending_memtables_flushes_bytes)
));
}
database::~database() {
@@ -835,7 +994,7 @@ future<> database::populate_keyspace(sstring datadir, sstring ks_name) {
dblog.warn("Skipping undefined keyspace: {}", ks_name);
} else {
dblog.info("Populating Keyspace {}", ks_name);
return lister::scan_dir(ksdir, directory_entry_type::directory, [this, ksdir, ks_name] (directory_entry de) {
return lister::scan_dir(ksdir, { directory_entry_type::directory }, [this, ksdir, ks_name] (directory_entry de) {
auto comps = parse_fname(de.name);
if (comps.size() < 2) {
dblog.error("Keyspace {}: Skipping malformed CF {} ", ksdir, de.name);
@@ -860,7 +1019,7 @@ future<> database::populate_keyspace(sstring datadir, sstring ks_name) {
}
future<> database::populate(sstring datadir) {
return lister::scan_dir(datadir, directory_entry_type::directory, [this, datadir] (directory_entry de) {
return lister::scan_dir(datadir, { directory_entry_type::directory }, [this, datadir] (directory_entry de) {
auto& ks_name = de.name;
if (ks_name == "system") {
return make_ready_future<>();
@@ -873,7 +1032,7 @@ template <typename Func>
static future<>
do_parse_system_tables(distributed<service::storage_proxy>& proxy, const sstring& _cf_name, Func&& func) {
using namespace db::schema_tables;
static_assert(std::is_same<future<>, std::result_of_t<Func(schema_result::value_type&)>>::value,
static_assert(std::is_same<future<>, std::result_of_t<Func(schema_result_value_type&)>>::value,
"bad Func signature");
@@ -908,11 +1067,11 @@ do_parse_system_tables(distributed<service::storage_proxy>& proxy, const sstring
future<> database::parse_system_tables(distributed<service::storage_proxy>& proxy) {
using namespace db::schema_tables;
return do_parse_system_tables(proxy, db::schema_tables::KEYSPACES, [this] (schema_result::value_type &v) {
return do_parse_system_tables(proxy, db::schema_tables::KEYSPACES, [this] (schema_result_value_type &v) {
auto ksm = create_keyspace_from_schema_partition(v);
return create_keyspace(ksm);
}).then([&proxy, this] {
return do_parse_system_tables(proxy, db::schema_tables::COLUMNFAMILIES, [this, &proxy] (schema_result::value_type &v) {
return do_parse_system_tables(proxy, db::schema_tables::COLUMNFAMILIES, [this, &proxy] (schema_result_value_type &v) {
return create_tables_from_tables_partition(proxy, v.second).then([this] (std::map<sstring, schema_ptr> tables) {
for (auto& t: tables) {
auto s = t.second;
@@ -1149,6 +1308,7 @@ keyspace::make_column_family_config(const schema& s) const {
cfg.enable_cache = _config.enable_cache;
cfg.max_memtable_size = _config.max_memtable_size;
cfg.dirty_memory_region_group = _config.dirty_memory_region_group;
cfg.cf_stats = _config.cf_stats;
cfg.enable_incremental_backups = _config.enable_incremental_backups;
return cfg;
@@ -1163,7 +1323,7 @@ keyspace::column_family_directory(const sstring& name, utils::UUID uuid) const {
future<>
keyspace::make_directory_for_column_family(const sstring& name, utils::UUID uuid) {
return make_directory(column_family_directory(name, uuid));
return touch_directory(column_family_directory(name, uuid));
}
no_such_keyspace::no_such_keyspace(const sstring& ks_name)
@@ -1321,7 +1481,7 @@ column_family::query(const query::read_command& cmd, const std::vector<query::pa
return do_until([&qs] { return !qs.limit || qs.range_empty; }, [this, &qs] {
return qs.reader().then([this, &qs](mutation_opt mo) {
if (mo) {
auto p_builder = qs.builder.add_partition(mo->key());
auto p_builder = qs.builder.add_partition(*mo->schema(), mo->key());
auto is_distinct = qs.cmd.slice.options.contains(query::partition_slice::option::distinct);
auto limit = !is_distinct ? qs.limit : 1;
mo->partition().query(p_builder, *_schema, qs.cmd.timestamp, limit);
@@ -1337,6 +1497,9 @@ column_family::query(const query::read_command& cmd, const std::vector<query::pa
});
}).finally([lc, this]() mutable {
_stats.reads.mark(lc);
if (lc.is_start()) {
_stats.estimated_read.add(lc.latency(), _stats.reads.count);
}
});
}
@@ -1349,28 +1512,51 @@ column_family::as_mutation_source() const {
future<lw_shared_ptr<query::result>>
database::query(const query::read_command& cmd, const std::vector<query::partition_range>& ranges) {
static auto make_empty = [] {
return make_ready_future<lw_shared_ptr<query::result>>(make_lw_shared(query::result()));
};
try {
column_family& cf = find_column_family(cmd.cf_id);
return cf.query(cmd, ranges);
} catch (const no_such_column_family&) {
// FIXME: load from sstables
return make_empty();
}
column_family& cf = find_column_family(cmd.cf_id);
return cf.query(cmd, ranges);
}
future<reconcilable_result>
database::query_mutations(const query::read_command& cmd, const query::partition_range& range) {
column_family& cf = find_column_family(cmd.cf_id);
return mutation_query(cf.as_mutation_source(), range, cmd.slice, cmd.row_limit, cmd.timestamp);
}
std::unordered_set<sstring> database::get_initial_tokens() {
std::unordered_set<sstring> tokens;
sstring tokens_string = get_config().initial_token();
try {
column_family& cf = find_column_family(cmd.cf_id);
return mutation_query(cf.as_mutation_source(), range, cmd.slice, cmd.row_limit, cmd.timestamp);
} catch (const no_such_column_family&) {
// FIXME: load from sstables
return make_ready_future<reconcilable_result>(reconcilable_result());
boost::split(tokens, tokens_string, boost::is_any_of(sstring(",")));
} catch (...) {
throw std::runtime_error(sprint("Unable to parse initial_token=%s", tokens_string));
}
tokens.erase("");
return tokens;
}
std::experimental::optional<gms::inet_address> database::get_replace_address() {
auto& cfg = get_config();
sstring replace_address = cfg.replace_address();
sstring replace_address_first_boot = cfg.replace_address_first_boot();
try {
if (!replace_address.empty()) {
return gms::inet_address(replace_address);
} else if (!replace_address_first_boot.empty()) {
return gms::inet_address(replace_address_first_boot);
}
return std::experimental::nullopt;
} catch (...) {
return std::experimental::nullopt;
}
}
bool database::is_replacing() {
sstring replace_address_first_boot = get_config().replace_address_first_boot();
if (!replace_address_first_boot.empty() && db::system_keyspace::bootstrap_complete()) {
dblog.info("Replace address on first boot requested; this node is already bootstrapped");
return false;
}
return bool(get_replace_address());
}
std::ostream& operator<<(std::ostream& out, const atomic_cell_or_collection& c) {
@@ -1402,8 +1588,7 @@ future<> database::apply_in_memory(const frozen_mutation& m, const db::replay_po
auto& cf = find_column_family(m.column_family_id());
cf.apply(m, rp);
} catch (no_such_column_family&) {
// TODO: log a warning
// FIXME: load keyspace meta-data from storage
dblog.error("Attempting to mutate non-existent table {}", m.column_family_id());
}
return make_ready_future<>();
}
@@ -1491,6 +1676,7 @@ database::make_keyspace_config(const keyspace_metadata& ksm) {
cfg.max_memtable_size = std::numeric_limits<size_t>::max();
}
cfg.dirty_memory_region_group = &_dirty_memory_region_group;
cfg.cf_stats = &_cf_stats;
cfg.enable_incremental_backups = _cfg->incremental_backups();
return cfg;
}
@@ -1547,9 +1733,7 @@ database::stop() {
return _compaction_manager.stop().then([this] {
// try to ensure that CL has done disk flushing
if (_commitlog != nullptr) {
return _commitlog->shutdown().then([this] {
return _commitlog->sync_all_segments();
});
return _commitlog->shutdown();
}
return make_ready_future<>();
}).then([this] {
@@ -1700,7 +1884,18 @@ future<> column_family::snapshot(sstring name) {
return parallel_for_each(tables, [name](sstables::shared_sstable sstable) {
auto dir = sstable->get_dir() + "/snapshots/" + name;
return recursive_touch_directory(dir).then([sstable, dir] {
return sstable->create_links(dir);
return sstable->create_links(dir).then_wrapped([] (future<> f) {
// If the SSTables are shared, one of the CPUs will fail here.
// That is completely fine, though. We only need one link.
try {
f.get();
} catch (std::system_error& e) {
if (e.code() != std::error_code(EEXIST, std::system_category())) {
throw;
}
}
return make_ready_future<>();
});
});
}).then([jsondir, &tables] {
// This is not just an optimization. If we have no files, jsondir may not have been created,
@@ -1710,7 +1905,7 @@ future<> column_family::snapshot(sstring name) {
} else {
return make_ready_future<>();
}
}).then([this, &tables, jsondir] {
}).finally([this, &tables, jsondir] {
auto shard = std::hash<sstring>()(jsondir) % smp::count;
std::unordered_set<sstring> table_names;
for (auto& sst : tables) {
@@ -1749,6 +1944,129 @@ future<> column_family::snapshot(sstring name) {
});
}
future<bool> column_family::snapshot_exists(sstring tag) {
sstring jsondir = _config.datadir + "/snapshots/";
return engine().open_directory(std::move(jsondir)).then_wrapped([] (future<file> f) {
try {
f.get0();
return make_ready_future<bool>(true);
} catch (std::system_error& e) {
if (e.code() != std::error_code(ENOENT, std::system_category())) {
throw;
}
return make_ready_future<bool>(false);
}
});
}
enum class missing { no, yes };
static missing
file_missing(future<> f) {
try {
f.get();
return missing::no;
} catch (std::system_error& e) {
if (e.code() != std::error_code(ENOENT, std::system_category())) {
throw;
}
return missing::yes;
}
}
future<> column_family::clear_snapshot(sstring tag) {
sstring jsondir = _config.datadir + "/snapshots/";
sstring parent = _config.datadir;
if (!tag.empty()) {
jsondir += tag;
parent += "/snapshots/";
}
lister::dir_entry_types dir_and_files = { directory_entry_type::regular, directory_entry_type::directory };
return lister::scan_dir(jsondir, dir_and_files, [this, curr_dir = jsondir, dir_and_files, tag] (directory_entry de) {
// FIXME: We really need a better directory walker. This should eventually be part of the seastar infrastructure.
// It's hard to write this in a fully recursive manner because we need to keep information about the parent directory,
// so we can remove the file. For now, we'll take advantage of the fact that we will at most visit 2 levels and keep
// it ugly but simple.
auto recurse = make_ready_future<>();
if (de.type == directory_entry_type::directory) {
// Should only recurse when tag is empty, meaning delete all snapshots
if (!tag.empty()) {
throw std::runtime_error(sprint("Unexpected directory %s found at %s! Aborting", de.name, curr_dir));
}
auto newdir = curr_dir + "/" + de.name;
recurse = lister::scan_dir(newdir, dir_and_files, [this, curr_dir = newdir] (directory_entry de) {
return remove_file(curr_dir + "/" + de.name);
});
}
return recurse.then([fname = curr_dir + "/" + de.name] {
return remove_file(fname);
});
}).then_wrapped([jsondir] (future<> f) {
// Fine if directory does not exist. If it did, we delete it
if (file_missing(std::move(f)) == missing::no) {
return remove_file(jsondir);
}
return make_ready_future<>();
}).then([parent] {
return sync_directory(parent).then_wrapped([] (future<> f) {
// Should always exist for empty tags, but may not exist for a single tag if we never took
// snapshots. We will check this here just to mask out the exception, without silencing
// unexpected ones.
file_missing(std::move(f));
return make_ready_future<>();
});
});
}
future<std::unordered_map<sstring, column_family::snapshot_details>> column_family::get_snapshot_details() {
std::unordered_map<sstring, snapshot_details> all_snapshots;
return do_with(std::move(all_snapshots), [this] (auto& all_snapshots) {
return engine().file_exists(_config.datadir + "/snapshots").then([this, &all_snapshots](bool file_exists) {
if (!file_exists) {
return make_ready_future<>();
}
return lister::scan_dir(_config.datadir + "/snapshots", { directory_entry_type::directory }, [this, &all_snapshots] (directory_entry de) {
auto snapshot_name = de.name;
auto snapshot = _config.datadir + "/snapshots/" + snapshot_name;
all_snapshots.emplace(snapshot_name, snapshot_details());
return lister::scan_dir(snapshot, { directory_entry_type::regular }, [this, &all_snapshots, snapshot, snapshot_name] (directory_entry de) {
return file_size(snapshot + "/" + de.name).then([this, &all_snapshots, snapshot_name, name = de.name] (auto size) {
// The manifest is the only file expected to be in this directory not belonging to the SSTable.
// For it, we account the total size, but zero it for the true size calculation.
//
// All the others should just generate an exception: there is something wrong, so don't blindly
// add it to the size.
if (name != "manifest.json") {
sstables::entry_descriptor::make_descriptor(name);
all_snapshots.at(snapshot_name).total += size;
} else {
size = 0;
}
return make_ready_future<uint64_t>(size);
}).then([this, &all_snapshots, snapshot_name, name = de.name] (auto size) {
// FIXME: When we support multiple data directories, the file may not necessarily
// live in this same location. May have to test others as well.
return file_size(_config.datadir + "/" + name).then_wrapped([&all_snapshots, snapshot_name, size] (auto fut) {
try {
// File exists in the main SSTable directory. Snapshots are not contributing to size
fut.get0();
} catch (std::system_error& e) {
if (e.code() != std::error_code(ENOENT, std::system_category())) {
throw;
}
all_snapshots.at(snapshot_name).live += size;
}
return make_ready_future<>();
});
});
});
});
}).then([&all_snapshots] {
return std::move(all_snapshots);
});
});
}
future<> column_family::flush() {
// FIXME: this will synchronously wait for this write to finish, but doesn't guarantee
// anything about previous writes.
@@ -1789,26 +2107,27 @@ void column_family::clear() {
future<db::replay_position> column_family::discard_sstables(db_clock::time_point truncated_at) {
assert(_stats.pending_compactions == 0);
db::replay_position rp;
auto gc_trunc = to_gc_clock(truncated_at);
return with_lock(_sstables_lock.for_read(), [this, truncated_at] {
db::replay_position rp;
auto gc_trunc = to_gc_clock(truncated_at);
auto pruned = make_lw_shared<sstable_list>();
auto pruned = make_lw_shared<sstable_list>();
for (auto&p : *_sstables) {
if (p.second->max_data_age() <= gc_trunc) {
rp = std::max(p.second->get_stats_metadata().position, rp);
p.second->mark_for_deletion();
continue;
for (auto&p : *_sstables) {
if (p.second->max_data_age() <= gc_trunc) {
rp = std::max(p.second->get_stats_metadata().position, rp);
p.second->mark_for_deletion();
continue;
}
pruned->emplace(p.first, p.second);
}
pruned->emplace(p.first, p.second);
}
_sstables = std::move(pruned);
_sstables = std::move(pruned);
dblog.debug("cleaning out row cache");
_cache.clear();
return make_ready_future<db::replay_position>(rp);
dblog.debug("cleaning out row cache");
_cache.clear();
return make_ready_future<db::replay_position>(rp);
});
}

View File

@@ -32,6 +32,7 @@
#include "utils/hash.hh"
#include "db_clock.hh"
#include "gc_clock.hh"
#include <chrono>
#include "core/distributed.hh"
#include <functional>
#include <cstdint>
@@ -67,6 +68,9 @@
#include "utils/exponential_backoff_retry.hh"
#include "utils/histogram.hh"
#include "sstables/estimated_histogram.hh"
#include "sstables/compaction.hh"
#include "key_reader.hh"
#include <seastar/core/rwlock.hh>
class frozen_mutation;
class reconcilable_result;
@@ -98,6 +102,16 @@ class replay_position_reordered_exception : public std::exception {};
using memtable_list = std::vector<lw_shared_ptr<memtable>>;
using sstable_list = sstables::sstable_list;
// The CF has a "stats" structure. But we don't want all fields here,
// since some of them are fairly complex for exporting to collectd. Also,
// that structure matches what we export via the API, so better leave it
// untouched. And we need more fields. We will summarize it in here what
// we need.
struct cf_stats {
int64_t pending_memtables_flushes_count = 0;
int64_t pending_memtables_flushes_bytes = 0;
};
class column_family {
public:
struct config {
@@ -109,6 +123,7 @@ public:
bool enable_incremental_backups = false;
size_t max_memtable_size = 5'000'000;
logalloc::region_group* dirty_memory_region_group = nullptr;
::cf_stats* cf_stats = nullptr;
};
struct no_commitlog {};
struct stats {
@@ -125,8 +140,15 @@ public:
utils::ihistogram writes{256};
sstables::estimated_histogram estimated_read;
sstables::estimated_histogram estimated_write;
sstables::estimated_histogram estimated_sstable_per_read;
utils::ihistogram tombstone_scanned;
utils::ihistogram live_scanned;
};
struct snapshot_details {
int64_t total;
int64_t live;
};
private:
schema_ptr _schema;
config _config;
@@ -134,8 +156,11 @@ private:
lw_shared_ptr<memtable_list> _memtables;
// generation -> sstable. Ordered by key so we can easily get the most recent.
lw_shared_ptr<sstable_list> _sstables;
// There are situations in which we need to stop writing sstables. Flushers will take
// the read lock, and the ones that wish to stop that process will take the write lock.
rwlock _sstables_lock;
mutable row_cache _cache; // Cache covers only sstables.
unsigned _sstable_generation = 1;
int64_t _sstable_generation = 1;
unsigned _mutation_count = 0;
db::replay_position _highest_flushed_rp;
// Provided by the database that owns this commitlog
@@ -145,15 +170,21 @@ private:
// Whether or not a cf is queued by its compaction manager.
bool _compaction_manager_queued = false;
int _compaction_disabled = 0;
class memtable_flush_queue;
std::unique_ptr<memtable_flush_queue> _flush_queue;
private:
void update_stats_for_new_sstable(uint64_t new_sstable_data_size);
void add_sstable(sstables::sstable&& sstable);
void add_sstable(lw_shared_ptr<sstables::sstable> sstable);
void add_memtable();
future<> flush_memtable_to_sstable(lw_shared_ptr<memtable> memt);
future<stop_iteration> try_flush_memtable_to_sstable(lw_shared_ptr<memtable> memt);
future<> update_cache(memtable&, lw_shared_ptr<sstable_list> old_sstables);
struct merge_comparator;
// update the sstable generation, making sure that new new sstables don't overwrite this one.
void update_sstables_known_generation(unsigned generation) {
_sstable_generation = std::max<uint64_t>(_sstable_generation, generation / smp::count + 1);
}
private:
// Creates a mutation reader which covers sstables.
// Caller needs to ensure that column_family remains live (FIXME: relax this).
@@ -161,7 +192,10 @@ private:
mutation_reader make_sstable_reader(const query::partition_range& range) const;
mutation_source sstables_as_mutation_source();
key_source sstables_as_key_source() const;
partition_presence_checker make_partition_presence_checker(lw_shared_ptr<sstable_list> old_sstables);
// We will use highres because hopefully it won't take more than a few usecs
std::chrono::high_resolution_clock::time_point _sstable_writes_disabled_at;
public:
// Creates a mutation reader which covers all data sources for this column family.
// Caller needs to ensure that column_family remains live (FIXME: relax this).
@@ -208,15 +242,52 @@ public:
void clear(); // discards memtable(s) without flushing them to disk.
future<db::replay_position> discard_sstables(db_clock::time_point);
// Important warning: disabling writes will only have an effect in the current shard.
// The other shards will keep writing tables at will. Therefore, you very likely need
// to call this separately in all shards first, to guarantee that none of them are writing
// new data before you can safely assume that the whole node is disabled.
future<int64_t> disable_sstable_write() {
_sstable_writes_disabled_at = std::chrono::high_resolution_clock::now();
return _sstables_lock.write_lock().then([this] {
return make_ready_future<int64_t>((*_sstables->end()).first);
});
}
// SSTable writes are now allowed again, and generation is updated to new_generation
// returns the amount of microseconds elapsed since we disabled writes.
std::chrono::high_resolution_clock::duration enable_sstable_write(int64_t new_generation) {
update_sstables_known_generation(new_generation);
_sstables_lock.write_unlock();
return std::chrono::high_resolution_clock::now() - _sstable_writes_disabled_at;
}
// Make sure the generation numbers are sequential, starting from "start".
// Generations before "start" are left untouched.
//
// Return the highest generation number seen so far
//
// Word of warning: although this function will reshuffle anything over "start", it is
// very dangerous to do that with live SSTables. This is meant to be used with SSTables
// that are not yet managed by the system.
//
// An example usage would query all shards asking what is the highest SSTable number known
// to them, and then pass that + 1 as "start".
future<std::vector<sstables::entry_descriptor>> reshuffle_sstables(int64_t start);
// FIXME: this is just an example, should be changed to something more
// general. compact_all_sstables() starts a compaction of all sstables.
// It doesn't flush the current memtable first. It's just a ad-hoc method,
// not a real compaction policy.
future<> compact_all_sstables();
// Compact all sstables provided in the vector.
future<> compact_sstables(std::vector<lw_shared_ptr<sstables::sstable>> sstables);
future<> compact_sstables(sstables::compaction_descriptor descriptor);
future<bool> snapshot_exists(sstring name);
future<> load_new_sstables(std::vector<sstables::entry_descriptor> new_tables);
future<> snapshot(sstring name);
future<> clear_snapshot(sstring name);
future<std::unordered_map<sstring, snapshot_details>> get_snapshot_details();
const bool incremental_backups_enabled() const {
return _config.enable_incremental_backups;
@@ -385,6 +456,7 @@ public:
bool enable_incremental_backups = false;
size_t max_memtable_size = 5'000'000;
logalloc::region_group* dirty_memory_region_group = nullptr;
::cf_stats* cf_stats = nullptr;
};
private:
std::unique_ptr<locator::abstract_replication_strategy> _replication_strategy;
@@ -443,6 +515,7 @@ public:
// use shard_of() for data
class database {
::cf_stats _cf_stats;
logalloc::region_group _dirty_memory_region_group;
std::unordered_map<sstring, keyspace> _keyspaces;
std::unordered_map<utils::UUID, lw_shared_ptr<column_family>> _column_families;
@@ -573,6 +646,10 @@ public:
const logalloc::region_group& dirty_memory_region_group() const {
return _dirty_memory_region_group;
}
std::unordered_set<sstring> get_initial_tokens();
std::experimental::optional<gms::inet_address> get_replace_address();
bool is_replacing();
};
// FIXME: stub
@@ -586,6 +663,9 @@ column_family::apply(const mutation& m, const db::replay_position& rp) {
active_memtable().apply(m, rp);
seal_on_overflow();
_stats.writes.mark(lc);
if (lc.is_start()) {
_stats.estimated_write.add(lc.latency(), _stats.writes.count);
}
}
inline
@@ -617,6 +697,9 @@ column_family::apply(const frozen_mutation& m, const db::replay_position& rp) {
active_memtable().apply(m, rp);
seal_on_overflow();
_stats.writes.mark(lc);
if (lc.is_start()) {
_stats.estimated_write.add(lc.latency(), _stats.writes.count);
}
}
future<> update_schema_version_and_announce(distributed<service::storage_proxy>& proxy);

View File

@@ -132,7 +132,7 @@ mutation db::batchlog_manager::get_batch_log_mutation_for(const std::vector<muta
mutation m(key, schema);
m.set_cell({}, to_bytes("version"), version, timestamp);
m.set_cell({}, to_bytes("written_at"), now, timestamp);
m.set_cell({}, to_bytes("data"), std::move(data), timestamp);
m.set_cell({}, to_bytes("data"), data_value(std::move(data)), timestamp);
return m;
}

View File

@@ -55,6 +55,7 @@
#include <core/rwlock.hh>
#include <core/gate.hh>
#include <core/fstream.hh>
#include <seastar/core/memory.hh>
#include <net/byteorder.hh>
#include "commitlog.hh"
@@ -89,7 +90,7 @@ public:
db::commitlog::config::config(const db::config& cfg)
: commit_log_location(cfg.commitlog_directory())
, commitlog_total_space_in_mb(cfg.commitlog_total_space_in_mb())
, commitlog_total_space_in_mb(cfg.commitlog_total_space_in_mb() >= 0 ? cfg.commitlog_total_space_in_mb() : memory::stats().total_memory() >> 20)
, commitlog_segment_size_in_mb(cfg.commitlog_segment_size_in_mb())
, commitlog_sync_period_in_ms(cfg.commitlog_sync_batch_window_in_ms())
, mode(cfg.commitlog_sync() == "batch" ? sync_mode::BATCH : sync_mode::PERIODIC)
@@ -177,6 +178,15 @@ public:
stats totals;
void begin_op() {
_gate.enter();
++totals.pending_operations;
}
void end_op() {
--totals.pending_operations;
_gate.leave();
}
segment_manager(config c)
: cfg(c), max_size(
std::min<size_t>(std::numeric_limits<position_type>::max(),
@@ -192,10 +202,14 @@ public:
if (cfg.commit_log_location.empty()) {
cfg.commit_log_location = "/var/lib/scylla/commitlog";
}
logger.trace("Commitlog maximum disk size: {} MB / cpu ({} cpus)",
max_disk_size / (1024*1024), smp::count);
logger.trace("Commitlog {} maximum disk size: {} MB / cpu ({} cpus)",
cfg.commit_log_location, max_disk_size / (1024 * 1024),
smp::count);
_regs = create_counters();
}
~segment_manager() {
logger.trace("Commitlog {} disposed", cfg.commit_log_location);
}
uint64_t next_id() {
return ++_ids;
@@ -218,7 +232,9 @@ public:
void on_timer();
void sync();
void arm(uint32_t extra = 0) {
_timer.arm(std::chrono::milliseconds(cfg.commitlog_sync_period_in_ms + extra));
if (!_shutdown) {
_timer.arm(std::chrono::milliseconds(cfg.commitlog_sync_period_in_ms + extra));
}
}
std::vector<sstring> get_active_names() const;
@@ -300,7 +316,8 @@ public:
// The commit log entry overhead in bytes (int: length + int: head checksum + int: tail checksum)
static constexpr size_t entry_overhead_size = 3 * sizeof(uint32_t);
static constexpr size_t segment_overhead_size = 2 * sizeof(uint32_t);
static constexpr size_t descriptor_header_size = 4 * sizeof(uint32_t);
static constexpr size_t descriptor_header_size = 5 * sizeof(uint32_t);
static constexpr uint32_t segment_magic = ('S'<<24) |('C'<< 16) | ('L' << 8) | 'C';
// The commit log (chained) sync marker/header size in bytes (int: length + int: checksum [segmentId, position])
static constexpr size_t sync_marker_size = 2 * sizeof(uint32_t);
@@ -371,6 +388,7 @@ public:
}
future<sseg_ptr> flush(uint64_t pos = 0) {
auto me = shared_from_this();
assert(!me.owned());
if (pos == 0) {
pos = _file_pos;
}
@@ -378,38 +396,35 @@ public:
logger.trace("{} already synced! ({} < {})", *this, pos, _flush_pos);
return make_ready_future<sseg_ptr>(std::move(me));
}
logger.trace("Syncing {} -> {}", _flush_pos, pos);
logger.trace("Syncing {} {} -> {}", *this, _flush_pos, pos);
// Make sure all disk writes are done.
// This is not 100% neccesary, we really only need the ones below our flush pos,
// but since we pretty much assume that task ordering will make this the case anyway...
return _dwrite.write_lock().then(
[this, me = std::move(me), pos]() mutable {
[this, me, pos]() mutable {
_dwrite.write_unlock(); // release it already.
pos = std::max(pos, _file_pos);
if (pos <= _flush_pos) {
logger.trace("{} already synced! ({} < {})", *this, pos, _flush_pos);
return make_ready_future<sseg_ptr>(std::move(me));
}
++_segment_manager->totals.pending_operations;
return _file.flush().handle_exception([](auto ex) {
_segment_manager->begin_op();
return _file.flush().then_wrapped([this, pos, me](auto f) {
try {
std::rethrow_exception(ex);
f.get();
// TODO: retry/ignore/fail/stop - optional behaviour in origin.
// we fast-fail the whole commit.
} catch (std::exception& e) {
logger.error("Failed to flush commits to disk: {}", e.what());
throw;
_flush_pos = std::max(pos, _flush_pos);
++_segment_manager->totals.flush_count;
logger.trace("{} synced to {}", *this, _flush_pos);
return make_ready_future<sseg_ptr>(std::move(me));
} catch (...) {
logger.error("Failed to flush commits to disk.");
logger.error("Failed to flush commits to disk: {}", std::current_exception());
throw;
}
}).then([this, pos, me = std::move(me)]() {
_flush_pos = std::max(pos, _flush_pos);
++_segment_manager->totals.flush_count;
logger.trace("{} synced to {}", *this, _flush_pos);
return make_ready_future<sseg_ptr>(std::move(me));
}).finally([this] {
--_segment_manager->totals.pending_operations;
}).finally([this, me] {
_segment_manager->end_op();
});
});
}
@@ -455,6 +470,8 @@ public:
_segment_manager->totals.total_size += k;
}
auto me = shared_from_this();
assert(!me.owned());
if (size == 0) {
return make_ready_future<sseg_ptr>(std::move(me));
}
@@ -468,6 +485,7 @@ public:
if (off == 0) {
// first block. write file header.
out.write(segment_magic);
out.write(_desc.ver);
out.write(_desc.id);
crc32_nbo crc;
@@ -489,9 +507,9 @@ public:
// acquire read lock
return _dwrite.read_lock().then([this, size, off, buf = std::move(buf), me]() mutable {
++_segment_manager->totals.pending_operations;
auto written = make_lw_shared<size_t>(0);
auto p = buf.get();
_segment_manager->begin_op();
return repeat([this, size, off, written, p]() mutable {
return _file.dma_write(off + *written, p + *written, size - *written).then_wrapped([this, size, written](auto&& f) {
try {
@@ -517,11 +535,11 @@ public:
});
}).finally([this, buf = std::move(buf)]() mutable {
_segment_manager->release_buffer(std::move(buf));
_segment_manager->end_op();
});
}).then([me] {
return make_ready_future<sseg_ptr>(std::move(me));
}).finally([me, this]() {
--_segment_manager->totals.pending_operations;
_dwrite.read_unlock(); // release
});
}
@@ -540,18 +558,22 @@ public:
+ std::to_string(_segment_manager->max_mutation_size)));
}
// would we make the file too big?
if (position() + s > _segment_manager->max_size) {
// do this in next segment instead.
return finish_and_get_new().then(
[id, size, func = std::move(func)](auto new_seg) {
return new_seg->allocate(id, size, func);
});
}
// enough data?
if (s > (_buffer.size() - _buf_pos)) {
// TODO: iff we have to many writes running, maybe we should
// wait for this?
cycle(s);
for (;;) {
if (position() + s > _segment_manager->max_size) {
// do this in next segment instead.
return finish_and_get_new().then(
[id, size, func = std::move(func)](auto new_seg) {
return new_seg->allocate(id, size, func);
});
}
// enough data?
if (s > (_buffer.size() - _buf_pos)) {
// TODO: iff we have to many writes running, maybe we should
// wait for this?
cycle(s);
continue; // re-check file size overflow
}
break;
}
_gate.enter(); // this might throw. I guess we accept this?
@@ -629,13 +651,19 @@ public:
bool is_still_allocating() const {
return !_closed && position() < _segment_manager->max_size;
}
bool is_clean() {
bool is_clean() const {
return _cf_dirty.empty();
}
bool is_unused() {
bool is_unused() const {
return !is_still_allocating() && is_clean();
}
bool contains(const replay_position& pos) {
bool is_flushed() const {
return position() <= _flush_pos;
}
bool can_delete() const {
return is_unused() && is_flushed();
}
bool contains(const replay_position& pos) const {
return pos.id == _desc.id;
}
sstring get_segment_name() const {
@@ -820,8 +848,11 @@ void db::commitlog::segment_manager::flush_segments(bool force) {
future<db::commitlog::segment_manager::sseg_ptr> db::commitlog::segment_manager::allocate_segment(bool active) {
descriptor d(next_id());
return engine().open_file_dma(cfg.commit_log_location + "/" + d.filename(), open_flags::wo | open_flags::create).then([this, d, active](file f) {
auto s = make_lw_shared<segment>(this, d, std::move(f), active);
return make_ready_future<sseg_ptr>(s);
// xfs doesn't like files extended betond eof, so enlarge the file
return f.truncate(max_size).then([this, d, active, f] () mutable {
auto s = make_lw_shared<segment>(this, d, std::move(f), active);
return make_ready_future<sseg_ptr>(s);
});
});
}
@@ -890,15 +921,19 @@ std::ostream& db::operator<<(std::ostream& out, const db::replay_position& p) {
}
void db::commitlog::segment_manager::discard_unused_segments() {
auto i = std::remove_if(_segments.begin(), _segments.end(), [=](auto& s) {
if (s->is_unused()) {
logger.trace("Checking for unused segments ({} active)", _segments.size());
auto i = std::remove_if(_segments.begin(), _segments.end(), [=](auto s) {
if (s->can_delete()) {
logger.debug("Segment {} is unused", *s);
return true;
}
if (s->is_still_allocating()) {
logger.debug("Not safe to delete segment {}; still allocating.", s);
} else {
} else if (!s->is_clean()) {
logger.debug("Not safe to delete segment {}; dirty is {}", s, segment::cf_mark {*s});
} else {
logger.debug("Not safe to delete segment {}; disk ops pending", s);
}
return false;
});
@@ -918,12 +953,12 @@ future<> db::commitlog::segment_manager::sync_all_segments() {
future<> db::commitlog::segment_manager::shutdown() {
if (!_shutdown) {
_shutdown = true;
_timer.cancel();
return _gate.close().then([this] {
return parallel_for_each(_segments, [this](sseg_ptr s) {
return s->shutdown();
});
_shutdown = true; // no re-arm, no create new segments.
_timer.cancel(); // no more timer calls
return parallel_for_each(_segments, [this](sseg_ptr s) {
return s->shutdown(); // close each segment (no more alloc)
}).then(std::bind(&segment_manager::sync_all_segments, this)).then([this] { // flush all
return _gate.close(); // wait for any pending ops
});
}
return make_ready_future<>();
@@ -936,11 +971,9 @@ future<> db::commitlog::segment_manager::shutdown() {
* Only use from tests.
*/
future<> db::commitlog::segment_manager::clear() {
logger.debug("Clearing all segments");
_shutdown = true;
_timer.cancel();
flush_segments(true);
return sync_all_segments().then([this] {
logger.debug("Clearing commitlog");
return shutdown().then([this] {
logger.debug("Clearing all segments");
for (auto& s : _segments) {
s->mark_clean();
}
@@ -951,30 +984,30 @@ future<> db::commitlog::segment_manager::clear() {
* Called by timer in periodic mode.
*/
void db::commitlog::segment_manager::sync() {
for (auto& s : _segments) {
for (auto s : _segments) {
s->sync(); // we do not care about waiting...
}
}
void db::commitlog::segment_manager::on_timer() {
if (cfg.mode != sync_mode::BATCH) {
sync();
}
// IFF a new segment was put in use since last we checked, and we're
// above threshold, request flush.
if (_new_counter > 0) {
auto max = max_disk_size;
auto cur = totals.total_size_on_disk;
if (max != 0 && cur >= max) {
_new_counter = 0;
logger.debug("Size on disk {} MB exceeds local maximum {} MB", cur / (1024 * 1024), max / (1024 * 1024));
flush_segments();
}
}
// Gate, because we are starting potentially blocking ops
// without waiting for them, so segement_manager could be shut down
// while they are running.
seastar::with_gate(_gate, [this] {
if (cfg.mode != sync_mode::BATCH) {
sync();
}
// IFF a new segment was put in use since last we checked, and we're
// above threshold, request flush.
if (_new_counter > 0) {
auto max = max_disk_size;
auto cur = totals.total_size_on_disk;
if (max != 0 && cur >= max) {
_new_counter = 0;
logger.debug("Size on disk {} MB exceeds local maximum {} MB", cur / (1024 * 1024), max / (1024 * 1024));
flush_segments();
}
}
// take outstanding allocations into regard. This is paranoid,
// but if for some reason the file::open takes longer than timer period,
// we could flood the reserve list with new segments
@@ -1064,7 +1097,7 @@ db::commitlog::commitlog(config cfg)
: _segment_manager(new segment_manager(std::move(cfg))) {
}
db::commitlog::commitlog(commitlog&& v)
db::commitlog::commitlog(commitlog&& v) noexcept
: _segment_manager(std::move(v._segment_manager)) {
}
@@ -1140,10 +1173,11 @@ const db::commitlog::config& db::commitlog::active_config() const {
return _segment_manager->cfg;
}
future<subscription<temporary_buffer<char>, db::replay_position>>
future<std::unique_ptr<subscription<temporary_buffer<char>, db::replay_position>>>
db::commitlog::read_log_file(const sstring& filename, commit_load_reader_func next, position_type off) {
return engine().open_file_dma(filename, open_flags::ro).then([next = std::move(next), off](file f) {
return read_log_file(std::move(f), std::move(next), off);
return std::make_unique<subscription<temporary_buffer<char>, replay_position>>(
read_log_file(std::move(f), std::move(next), off));
});
}
@@ -1159,6 +1193,8 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
size_t next = 0;
size_t start_off = 0;
size_t skip_to = 0;
size_t file_size = 0;
size_t corrupt_size = 0;
bool eof = false;
bool header = true;
@@ -1190,6 +1226,10 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
});
});
}
future<> stop() {
eof = true;
return make_ready_future<>();
}
future<> read_header() {
return fin.read_exactly(segment::descriptor_header_size).then([this](temporary_buffer<char> buf) {
if (!advance(buf)) {
@@ -1198,10 +1238,20 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
}
// Will throw if we got eof
data_input in(buf);
auto magic = in.read<uint32_t>();
auto ver = in.read<uint32_t>();
auto id = in.read<uint64_t>();
auto checksum = in.read<uint32_t>();
if (magic == 0 && ver == 0 && id == 0 && checksum == 0) {
// let's assume this was an empty (pre-allocated)
// file. just skip it.
return stop();
}
if (magic != segment::segment_magic) {
throw std::invalid_argument("Not a scylla format commitlog file");
}
crc32_nbo crc;
crc.process(ver);
crc.process<int32_t>(id & 0xffffffff);
@@ -1230,6 +1280,11 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
auto next = in.read<uint32_t>();
auto checksum = in.read<uint32_t>();
if (next == 0 && checksum == 0) {
// in a pre-allocating world, this means eof
return stop();
}
crc32_nbo crc;
crc.process<int32_t>(id & 0xffffffff);
crc.process<int32_t>(id >> 32);
@@ -1237,7 +1292,11 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
auto cs = crc.checksum();
if (cs != checksum) {
throw std::runtime_error("Checksum error in chunk header");
// if a chunk header checksum is broken, we shall just assume that all
// remaining is as well. We cannot trust the "next" pointer, so...
logger.debug("Checksum error in segment chunk at {}.", pos);
corrupt_size += (file_size - pos);
return stop();
}
this->next = next;
@@ -1263,21 +1322,24 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
auto size = in.read<uint32_t>();
auto checksum = in.read<uint32_t>();
if (size == 0) {
// special urchin case: zero padding due to dma blocks
auto slack = next - pos;
return skip(slack);
}
crc32_nbo crc;
crc.process(size);
if (size < 3 * sizeof(uint32_t)) {
throw std::runtime_error("Invalid entry size");
if (size < 3 * sizeof(uint32_t) || checksum != crc.checksum()) {
auto slack = next - pos;
if (size != 0) {
logger.debug("Segment entry at {} has broken header. Skipping to next chunk ({} bytes)", rp, slack);
corrupt_size += slack;
}
// size == 0 -> special scylla case: zero padding due to dma blocks
return skip(slack);
}
if (start_off > pos) {
return skip(size - entry_header_size);
}
return fin.read_exactly(size - entry_header_size).then([this, size, checksum, rp](temporary_buffer<char> buf) {
return fin.read_exactly(size - entry_header_size).then([this, size, crc = std::move(crc), rp](temporary_buffer<char> buf) mutable {
advance(buf);
data_input in(buf);
@@ -1286,12 +1348,15 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
in.skip(data_size);
auto checksum = in.read<uint32_t>();
crc32_nbo crc;
crc.process(size);
crc.process_bytes(buf.get(), data_size);
if (crc.checksum() != checksum) {
throw std::runtime_error("Checksum error in data entry");
// If we're getting a checksum error here, most likely the rest of
// the file will be corrupt as well. But it does not hurt to retry.
// Just go to the next entry (since "size" in header seemed ok).
logger.debug("Segment entry at {} checksum error. Skipping {} bytes", rp, size);
corrupt_size += size;
return make_ready_future<>();
}
return s.produce(buf.share(0, data_size), rp);
@@ -1299,10 +1364,18 @@ db::commitlog::read_log_file(file f, commit_load_reader_func next, position_type
});
}
future<> read_file() {
return read_header().then(
[this] {
return do_until(std::bind(&work::end_of_file, this), std::bind(&work::read_chunk, this));
});
return f.size().then([this](uint64_t size) {
file_size = size;
}).then([this] {
return read_header().then(
[this] {
return do_until(std::bind(&work::end_of_file, this), std::bind(&work::read_chunk, this));
}).then([this] {
if (corrupt_size > 0) {
throw segment_data_corruption_error("Data corruption", corrupt_size);
}
});
});
}
};
@@ -1330,6 +1403,10 @@ uint64_t db::commitlog::get_completed_tasks() const {
return _segment_manager->totals.allocation_count;
}
uint64_t db::commitlog::get_flush_count() const {
return _segment_manager->totals.flush_count;
}
uint64_t db::commitlog::get_pending_tasks() const {
return _segment_manager->totals.pending_operations;
}

View File

@@ -139,7 +139,7 @@ public:
const uint32_t ver;
};
commitlog(commitlog&&);
commitlog(commitlog&&) noexcept;
~commitlog();
/**
@@ -231,6 +231,7 @@ public:
uint64_t get_total_size() const;
uint64_t get_completed_tasks() const;
uint64_t get_flush_count() const;
uint64_t get_pending_tasks() const;
uint64_t get_num_segments_created() const;
uint64_t get_num_segments_destroyed() const;
@@ -265,8 +266,21 @@ public:
typedef std::function<future<>(temporary_buffer<char>, replay_position)> commit_load_reader_func;
class segment_data_corruption_error: public std::runtime_error {
public:
segment_data_corruption_error(std::string msg, uint64_t s)
: std::runtime_error(msg), _bytes(s) {
}
uint64_t bytes() const {
return _bytes;
}
private:
uint64_t _bytes;
};
static subscription<temporary_buffer<char>, replay_position> read_log_file(file, commit_load_reader_func, position_type = 0);
static future<subscription<temporary_buffer<char>, replay_position>> read_log_file(const sstring&, commit_load_reader_func, position_type = 0);
static future<std::unique_ptr<subscription<temporary_buffer<char>, replay_position>>> read_log_file(
const sstring&, commit_load_reader_func, position_type = 0);
private:
commitlog(config);
};

View File

@@ -69,6 +69,7 @@ public:
uint64_t invalid_mutations = 0;
uint64_t skipped_mutations = 0;
uint64_t applied_mutations = 0;
uint64_t corrupt_bytes = 0;
};
future<> process(stats*, temporary_buffer<char> buf, replay_position rp);
@@ -166,9 +167,16 @@ db::commitlog_replayer::impl::recover(sstring file) {
return db::commitlog::read_log_file(file,
std::bind(&impl::process, this, s.get(), std::placeholders::_1,
std::placeholders::_2), p).then([](auto s) {
auto f = s.done();
auto f = s->done();
return f.finally([s = std::move(s)] {});
}).then([s] {
}).then_wrapped([s](future<> f) {
try {
f.get();
} catch (commitlog::segment_data_corruption_error& e) {
s->corrupt_bytes += e.bytes();
} catch (...) {
throw;
}
return make_ready_future<stats>(*s);
});
}
@@ -233,7 +241,7 @@ db::commitlog_replayer::commitlog_replayer(seastar::sharded<cql3::query_processo
: _impl(std::make_unique<impl>(qp))
{}
db::commitlog_replayer::commitlog_replayer(commitlog_replayer&& r)
db::commitlog_replayer::commitlog_replayer(commitlog_replayer&& r) noexcept
: _impl(std::move(r._impl))
{}
@@ -250,24 +258,32 @@ future<db::commitlog_replayer> db::commitlog_replayer::create_replayer(seastar::
}
future<> db::commitlog_replayer::recover(std::vector<sstring> files) {
logger.info("Replaying {}", files);
return parallel_for_each(files, [this](auto f) {
return this->recover(f).handle_exception([f](auto ep) {
logger.error("Error recovering {}: {}", f, ep);
std::rethrow_exception(ep);
});
return this->recover(f);
});
}
future<> db::commitlog_replayer::recover(sstring file) {
return _impl->recover(file).then([file](impl::stats stats) {
future<> db::commitlog_replayer::recover(sstring f) {
return _impl->recover(f).then([f](impl::stats stats) {
if (stats.corrupt_bytes != 0) {
logger.warn("Corrupted file: {}. {} bytes skipped.", f, stats.corrupt_bytes);
}
logger.info("Log replay of {} complete, {} replayed mutations ({} invalid, {} skipped)"
, file
, f
, stats.applied_mutations
, stats.invalid_mutations
, stats.skipped_mutations
);
});
}).handle_exception([f](auto ep) {
logger.error("Error recovering {}: {}", f, ep);
try {
std::rethrow_exception(ep);
} catch (std::invalid_argument&) {
logger.error("Scylla cannot process {}. Make sure to fully flush all Cassandra commit log files to sstable before migrating.");
throw;
} catch (...) {
throw;
}
});;
}

View File

@@ -57,7 +57,7 @@ class commitlog;
class commitlog_replayer {
public:
commitlog_replayer(commitlog_replayer&&);
commitlog_replayer(commitlog_replayer&&) noexcept;
~commitlog_replayer();
static future<commitlog_replayer> create_replayer(seastar::sharded<cql3::query_processor>&);

View File

@@ -31,6 +31,7 @@
#include "core/fstream.hh"
#include "core/do_with.hh"
#include "log.hh"
#include <boost/any.hpp>
static logging::logger logger("config");

View File

@@ -23,6 +23,7 @@
#pragma once
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <unordered_map>
#include "core/sstring.hh"
#include "core/future.hh"
@@ -112,6 +113,32 @@ public:
future<> read_from_file(const sstring&);
future<> read_from_file(file);
/**
* Scans the environment variables for configuration files directory
* definition. It's either $SCYLLA_CONF, $SCYLLA_HOME/conf or "conf" if none
* of SCYLLA_CONF and SCYLLA_HOME is defined.
*
* @return path of the directory where configuration files are located
* according the environment variables definitions.
*/
static boost::filesystem::path get_conf_dir() {
using namespace boost::filesystem;
path confdir;
auto* cd = std::getenv("SCYLLA_CONF");
if (cd != nullptr) {
confdir = path(cd);
} else {
auto* p = std::getenv("SCYLLA_HOME");
if (p != nullptr) {
confdir = path(p);
}
confdir /= "conf";
}
return confdir;
}
typedef std::unordered_map<sstring, sstring> string_map;
typedef std::vector<sstring> string_list;
using seed_provider_type = db::seed_provider_type;
@@ -132,7 +159,7 @@ public:
* type: is the value type (bool, uint32_t etc)
* status: is the current _usage_ of the opt. I.e. if you actually use the value, set it to "Used".
* Most values are set to "Unused", as in "will probably have an effect eventually".
* Values set to "Invalid" have no meaning/usage in urchin, and should (and will currently)
* Values set to "Invalid" have no meaning/usage in scylla, and should (and will currently)
* be signaled to a user providing a config with them, that these settings are pointless.
* desc: documentation.
* value...: enumerated valid values if any. Not currently used, but why not...
@@ -263,7 +290,7 @@ public:
"Related information: Configuring compaction" \
) \
/* Common fault detection setting */ \
val(phi_convict_threshold, uint32_t, 8, Unused, \
val(phi_convict_threshold, uint32_t, 8, Used, \
"Adjusts the sensitivity of the failure detector on an exponential scale. Generally this setting never needs adjusting.\n" \
"Related information: Failure detection and recovery" \
) \
@@ -289,7 +316,7 @@ public:
val(commitlog_sync_batch_window_in_ms, uint32_t, 10000, Used, \
"Controls how long the system waits for other writes before performing a sync in \"batch\" mode." \
) \
val(commitlog_total_space_in_mb, uint32_t, 8192, Used, \
val(commitlog_total_space_in_mb, int64_t, -1, Used, \
"Total space used for commitlogs. If the used space goes above this value, Cassandra rounds up to the next nearest segment multiple and flushes memtables to disk for the oldest commitlog segments, removing those log segments. This reduces the amount of data to replay on startup, and prevents infrequently-updated tables from indefinitely keeping commitlog segments. A small total commitlog space tends to cause more flush activity on less-active tables.\n" \
"Related information: Configuring memtable throughput" \
) \
@@ -375,11 +402,11 @@ public:
val(batch_size_warn_threshold_in_kb, uint32_t, 5, Unused, \
"Log WARN on any batch size exceeding this value in kilobytes. Caution should be taken on increasing the size of this threshold as it can lead to node instability." \
) \
val(broadcast_address, sstring, /* listen_address */, Unused, \
val(broadcast_address, sstring, /* listen_address */, Used, \
"The IP address a node tells other nodes in the cluster to contact it by. It allows public and private address to be different. For example, use the broadcast_address parameter in topologies where not all nodes have access to other nodes by their private IP addresses.\n" \
"If your Cassandra cluster is deployed across multiple Amazon EC2 regions and you use the EC2MultiRegionSnitch , set the broadcast_address to public IP address of the node and the listen_address to the private IP." \
) \
val(initial_token, sstring, /* N/A */, Unused, \
val(initial_token, sstring, /* N/A */, Used, \
"Used in the single-node-per-token architecture, where a node owns exactly one contiguous range in the ring space. Setting this property overrides num_tokens.\n" \
"If you not using vnodes or have num_tokens set it to 1 or unspecified (#num_tokens), you should always specify this parameter when setting up a production cluster for the first time and when adding capacity. For more information, see this parameter in the Cassandra 1.1 Node and Cluster Configuration documentation.\n" \
"This parameter can be used with num_tokens (vnodes ) in special cases such as Restoring from a snapshot." \
@@ -403,7 +430,7 @@ public:
, "org.apache.cassandra.dht.ByteOrderedPartitioner" \
, "org.apache.cassandra.dht.OrderPreservingPartitioner" \
) \
val(storage_port, uint16_t, 7000, Unused, \
val(storage_port, uint16_t, 7000, Used, \
"The port for inter-node communication." \
) \
/* Advanced automatic backup setting */ \
@@ -533,7 +560,7 @@ public:
) \
/* RPC (remote procedure call) settings */ \
/* Settings for configuring and tuning client connections. */ \
val(broadcast_rpc_address, sstring, /* unset */, Unused, \
val(broadcast_rpc_address, sstring, /* unset */, Used, \
"RPC address to broadcast to drivers and other Cassandra nodes. This cannot be set to 0.0.0.0. If blank, it is set to the value of the rpc_address or rpc_interface. If rpc_address or rpc_interfaceis set to 0.0.0.0, this property must be set.\n" \
) \
val(rpc_port, uint16_t, 9160, Used, \
@@ -715,6 +742,14 @@ public:
val(api_address, sstring, "", Used, "Http Rest API address") \
val(api_ui_dir, sstring, "swagger-ui/dist/", Used, "The directory location of the API GUI") \
val(api_doc_dir, sstring, "api/api-doc/", Used, "The API definition file directory") \
val(load_balance, sstring, "none", Used, "CQL request load balancing: 'none' or round-robin'") \
val(consistent_rangemovement, bool, true, Used, "When set to true, range movements will be consistent. It means: 1) it will refuse to bootstrapp a new node if other bootstrapping/leaving/moving nodes detected. 2) data will be streamed to a new node only from the node which is no longer responsible for the token range. Same as -Dcassandra.consistent.rangemovement in cassandra") \
val(join_ring, bool, true, Used, "When set to true, a node will join the token ring. When set to false, a node will not join the token ring. User can use nodetool join to initiate ring joinging later. Same as -Dcassandra.join_ring in cassandra.") \
val(load_ring_state, bool, true, Used, "When set to true, load tokens and host_ids previously saved. Same as -Dcassandra.load_ring_state in cassandra.") \
val(replace_node, sstring, "", Used, "The UUID of the node to replace. Same as -Dcassandra.replace_node in cssandra.") \
val(replace_token, sstring, "", Used, "The tokens of the node to replace. Same as -Dcassandra.replace_token in cassandra.") \
val(replace_address, sstring, "", Used, "The listen_address or broadcast_address of the dead node to replace. Same as -Dcassandra.replace_address.") \
val(replace_address_first_boot, sstring, "", Used, "Like replace_address option, but if the node has been bootstrapped sucessfully it will be ignored. Same as -Dcassandra.replace_address_first_boot.") \
/* done! */
#define _make_value_member(name, type, deflt, status, desc, ...) \

View File

@@ -42,7 +42,7 @@ struct query_context {
future<::shared_ptr<cql3::untyped_result_set>> execute_cql(sstring text, sstring cf, Args&&... args) {
// FIXME: Would be better not to use sprint here.
sstring req = sprint(text, cf);
return this->_qp.local().execute_internal(req, { boost::any(std::forward<Args>(args))... });
return this->_qp.local().execute_internal(req, { data_value(std::forward<Args>(args))... });
}
database& db() {
return _db.local();
@@ -67,9 +67,8 @@ extern std::unique_ptr<query_context> qctx;
// we executed the query, and return an empty result
template <typename... Args>
static future<::shared_ptr<cql3::untyped_result_set>> execute_cql(sstring text, Args&&... args) {
if (qctx) {
return qctx->execute_cql(text, std::forward<Args>(args)...);
}
return make_ready_future<shared_ptr<cql3::untyped_result_set>>(::make_shared<cql3::untyped_result_set>(cql3::untyped_result_set::make_empty()));
assert(qctx);
return qctx->execute_cql(text, std::forward<Args>(args)...);
}
}

View File

@@ -52,6 +52,7 @@
#include "core/do_with.hh"
#include "core/thread.hh"
#include "json.hh"
#include "log.hh"
#include "db/marshal/type_parser.hh"
#include "db/config.hh"
@@ -67,6 +68,8 @@ using namespace db::system_keyspace;
namespace db {
namespace schema_tables {
logging::logger logger("schema_tables");
std::vector<const char*> ALL { KEYSPACES, COLUMNFAMILIES, COLUMNS, TRIGGERS, USERTYPES, /* not present in 2.1.8: FUNCTIONS, AGGREGATES */ };
using days = std::chrono::duration<int, std::ratio<24 * 3600>>;
@@ -326,7 +329,7 @@ future<utils::UUID> calculate_schema_digest(distributed<service::storage_proxy>&
std::vector<query::result> results;
for (auto&& p : rs->partitions()) {
auto mut = p.mut().unfreeze(s);
auto partition_key = boost::any_cast<sstring>(utf8_type->deserialize(mut.key().get_component(*s, 0)));
auto partition_key = value_cast<sstring>(utf8_type->deserialize(mut.key().get_component(*s, 0)));
if (partition_key == system_keyspace::NAME) {
continue;
}
@@ -365,7 +368,7 @@ future<std::vector<frozen_mutation>> convert_schema_to_mutations(distributed<ser
std::vector<frozen_mutation> results;
for (auto&& p : rs->partitions()) {
auto mut = p.mut().unfreeze(s);
auto partition_key = boost::any_cast<sstring>(utf8_type->deserialize(mut.key().get_component(*s, 0)));
auto partition_key = value_cast<sstring>(utf8_type->deserialize(mut.key().get_component(*s, 0)));
if (partition_key == system_keyspace::NAME) {
continue;
}
@@ -395,18 +398,18 @@ read_schema_for_keyspaces(distributed<service::storage_proxy>& proxy, const sstr
return map_reduce(keyspace_names.begin(), keyspace_names.end(), map, schema_result{}, insert);
}
future<schema_result::value_type>
future<schema_result_value_type>
read_schema_partition_for_keyspace(distributed<service::storage_proxy>& proxy, const sstring& schema_table_name, const sstring& keyspace_name)
{
auto schema = proxy.local().get_db().local().find_schema(system_keyspace::NAME, schema_table_name);
auto keyspace_key = dht::global_partitioner().decorate_key(*schema,
partition_key::from_singular(*schema, keyspace_name));
return db::system_keyspace::query(proxy, schema_table_name, keyspace_key).then([keyspace_name] (auto&& rs) {
return schema_result::value_type{keyspace_name, std::move(rs)};
return schema_result_value_type{keyspace_name, std::move(rs)};
});
}
future<schema_result::value_type>
future<schema_result_value_type>
read_schema_partition_for_table(distributed<service::storage_proxy>& proxy, const sstring& schema_table_name, const sstring& keyspace_name, const sstring& table_name)
{
auto schema = proxy.local().get_db().local().find_schema(system_keyspace::NAME, schema_table_name);
@@ -414,7 +417,7 @@ read_schema_partition_for_table(distributed<service::storage_proxy>& proxy, cons
partition_key::from_singular(*schema, keyspace_name));
auto clustering_range = query::clustering_range(clustering_key_prefix::from_clustering_prefix(*schema, exploded_clustering_prefix({utf8_type->decompose(table_name)})));
return db::system_keyspace::query(proxy, schema_table_name, keyspace_key, clustering_range).then([keyspace_name] (auto&& rs) {
return schema_result::value_type{keyspace_name, std::move(rs)};
return schema_result_value_type{keyspace_name, std::move(rs)};
});
}
@@ -465,7 +468,7 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
std::set<sstring> keyspaces;
std::set<utils::UUID> column_families;
for (auto&& mutation : mutations) {
keyspaces.emplace(boost::any_cast<sstring>(utf8_type->deserialize(mutation.key().get_component(*s, 0))));
keyspaces.emplace(value_cast<sstring>(utf8_type->deserialize(mutation.key().get_component(*s, 0))));
column_families.emplace(mutation.column_family_id());
}
@@ -525,7 +528,7 @@ future<> do_merge_schema(distributed<service::storage_proxy>& proxy, std::vector
future<std::set<sstring>> merge_keyspaces(distributed<service::storage_proxy>& proxy, schema_result&& before, schema_result&& after)
{
std::vector<schema_result::value_type> created;
std::vector<schema_result_value_type> created;
std::vector<sstring> altered;
std::set<sstring> dropped;
@@ -549,7 +552,7 @@ future<std::set<sstring>> merge_keyspaces(distributed<service::storage_proxy>& p
for (auto&& key : diff.entries_only_on_right) {
auto&& value = after[key];
if (!value->empty()) {
created.emplace_back(schema_result::value_type{key, std::move(value)});
created.emplace_back(schema_result_value_type{key, std::move(value)});
}
}
for (auto&& key : diff.entries_differing) {
@@ -563,7 +566,7 @@ future<std::set<sstring>> merge_keyspaces(distributed<service::storage_proxy>& p
} else if (!pre->empty()) {
dropped.emplace(keyspace_name);
} else if (!post->empty()) { // a (re)created keyspace
created.emplace_back(schema_result::value_type{key, std::move(post)});
created.emplace_back(schema_result_value_type{key, std::move(post)});
}
}
return do_with(std::move(created), [&proxy, altered = std::move(altered)] (auto& created) {
@@ -670,6 +673,8 @@ future<> merge_tables(distributed<service::storage_proxy>& proxy, schema_result&
if (engine().cpu_id() == 0) {
for (auto&& cfm : created) {
service::migration_manager::notify_create_column_family(cfm).get0();
auto& ks = db.find_keyspace(cfm->ks_name());
ks.make_directory_for_column_family(cfm->cf_name(), cfm->id());
}
for (auto&& cfm : dropped) {
service::migration_manager::notify_drop_column_family(cfm).get0();
@@ -894,7 +899,7 @@ std::vector<mutation> make_drop_keyspace_mutations(lw_shared_ptr<keyspace_metada
*
* @param partition Keyspace attributes in serialized form
*/
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result::value_type& result)
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result_value_type& result)
{
auto&& rs = result.second;
if (rs->empty()) {
@@ -1305,10 +1310,10 @@ void create_table_from_table_row_and_column_rows(schema_builder& builder, const
builder.set_max_compaction_threshold(table_row.get_nonnull<int>("max_compaction_threshold"));
}
#if 0
if (result.has("comment"))
cfm.comment(result.getString("comment"));
#endif
if (table_row.has("comment")) {
builder.set_comment(table_row.get_nonnull<sstring>("comment"));
}
if (table_row.has("memtable_flush_period_in_ms")) {
builder.set_memtable_flush_period(table_row.get_nonnull<int32_t>("memtable_flush_period_in_ms"));
}
@@ -1325,9 +1330,15 @@ void create_table_from_table_row_and_column_rows(schema_builder& builder, const
builder.set_speculative_retry(table_row.get_nonnull<sstring>("speculative_retry"));
}
if (table_row.has("compaction_strategy")) {
auto strategy = table_row.get_nonnull<sstring>("compression_strategy_class");
builder.set_compaction_strategy(sstables::compaction_strategy::type(strategy));
if (table_row.has("compaction_strategy_class")) {
auto strategy = table_row.get_nonnull<sstring>("compaction_strategy_class");
try {
builder.set_compaction_strategy(sstables::compaction_strategy::type(strategy));
} catch (const exceptions::configuration_exception& e) {
// If compaction strategy class isn't supported, fallback to size tiered.
logger.warn("Falling back to size-tiered compaction strategy after the problem: {}", e.what());
builder.set_compaction_strategy(sstables::compaction_strategy_type::size_tiered);
}
}
if (table_row.has("compaction_strategy_options")) {

View File

@@ -55,6 +55,7 @@ namespace db {
namespace schema_tables {
using schema_result = std::map<sstring, lw_shared_ptr<query::result_set>>;
using schema_result_value_type = std::pair<sstring, lw_shared_ptr<query::result_set>>;
static constexpr auto KEYSPACES = "schema_keyspaces";
static constexpr auto COLUMNFAMILIES = "schema_columnfamilies";
@@ -74,7 +75,7 @@ future<utils::UUID> calculate_schema_digest(distributed<service::storage_proxy>&
future<std::vector<frozen_mutation>> convert_schema_to_mutations(distributed<service::storage_proxy>& proxy);
future<schema_result::value_type>
future<schema_result_value_type>
read_schema_partition_for_keyspace(distributed<service::storage_proxy>& proxy, const sstring& schema_table_name, const sstring& keyspace_name);
future<> merge_schema(distributed<service::storage_proxy>& proxy, std::vector<mutation> mutations);
@@ -89,11 +90,11 @@ std::vector<mutation> make_create_keyspace_mutations(lw_shared_ptr<keyspace_meta
std::vector<mutation> make_drop_keyspace_mutations(lw_shared_ptr<keyspace_metadata> keyspace, api::timestamp_type timestamp);
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result::value_type& partition);
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result_value_type& partition);
future<> merge_tables(distributed<service::storage_proxy>& proxy, schema_result&& before, schema_result&& after);
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result::value_type& partition);
lw_shared_ptr<keyspace_metadata> create_keyspace_from_schema_partition(const schema_result_value_type& partition);
mutation make_create_keyspace_mutation(lw_shared_ptr<keyspace_metadata> keyspace, api::timestamp_type timestamp, bool with_tables_and_types_and_functions = true);

View File

@@ -143,18 +143,18 @@ atomic_cell_view db::serializer<atomic_cell_view>::read(input& in) {
}
template<>
db::serializer<collection_mutation::view>::serializer(const collection_mutation::view& c)
db::serializer<collection_mutation_view>::serializer(const collection_mutation_view& c)
: _item(c), _size(bytes_view_serializer(c.serialize()).size()) {
}
template<>
void db::serializer<collection_mutation::view>::write(output& out, const collection_mutation::view& t) {
void db::serializer<collection_mutation_view>::write(output& out, const collection_mutation_view& t) {
bytes_view_serializer::write(out, t.serialize());
}
template<>
void db::serializer<collection_mutation::view>::read(collection_mutation::view& c, input& in) {
c = collection_mutation::view::from_bytes(bytes_view_serializer::read(in));
void db::serializer<collection_mutation_view>::read(collection_mutation_view& c, input& in) {
c = collection_mutation_view::from_bytes(bytes_view_serializer::read(in));
}
template<>
@@ -278,7 +278,7 @@ template class db::serializer<bytes> ;
template class db::serializer<bytes_view> ;
template class db::serializer<sstring> ;
template class db::serializer<atomic_cell_view> ;
template class db::serializer<collection_mutation::view> ;
template class db::serializer<collection_mutation_view> ;
template class db::serializer<utils::UUID> ;
template class db::serializer<partition_key_view> ;
template class db::serializer<clustering_key_view> ;

View File

@@ -26,7 +26,6 @@
#include "utils/data_output.hh"
#include "bytes_ostream.hh"
#include "bytes.hh"
#include "mutation.hh"
#include "keys.hh"
#include "database_fwd.hh"
#include "frozen_mutation.hh"
@@ -109,9 +108,9 @@ template<> void serializer<atomic_cell_view>::write(output&, const type&);
template<> void serializer<atomic_cell_view>::read(atomic_cell_view&, input&);
template<> atomic_cell_view serializer<atomic_cell_view>::read(input&);
template<> serializer<collection_mutation::view>::serializer(const collection_mutation::view &);
template<> void serializer<collection_mutation::view>::write(output&, const type&);
template<> void serializer<collection_mutation::view>::read(collection_mutation::view&, input&);
template<> serializer<collection_mutation_view>::serializer(const collection_mutation_view &);
template<> void serializer<collection_mutation_view>::write(output&, const type&);
template<> void serializer<collection_mutation_view>::read(collection_mutation_view&, input&);
template<> serializer<frozen_mutation>::serializer(const frozen_mutation &);
template<> void serializer<frozen_mutation>::write(output&, const type&);
@@ -160,7 +159,7 @@ typedef serializer<bytes> bytes_serializer; // Compatible with bytes_view_serial
typedef serializer<bytes_view> bytes_view_serializer; // Compatible with bytes_serializer
typedef serializer<sstring> sstring_serializer;
typedef serializer<atomic_cell_view> atomic_cell_view_serializer;
typedef serializer<collection_mutation::view> collection_mutation_view_serializer;
typedef serializer<collection_mutation_view> collection_mutation_view_serializer;
typedef serializer<utils::UUID> uuid_serializer;
typedef serializer<partition_key_view> partition_key_view_serializer;
typedef serializer<clustering_key_view> clustering_key_view_serializer;

View File

@@ -486,9 +486,7 @@ future<> init_local_cache() {
}
void minimal_setup(distributed<database>& db, distributed<cql3::query_processor>& qp) {
auto new_ctx = std::make_unique<query_context>(db, qp);
qctx.swap(new_ctx);
assert(!new_ctx);
qctx = std::make_unique<query_context>(db, qp);
}
future<> setup(distributed<database>& db, distributed<cql3::query_processor>& qp) {
@@ -505,6 +503,10 @@ future<> setup(distributed<database>& db, distributed<cql3::query_processor>& qp
return check_health();
}).then([] {
return db::schema_tables::save_system_keyspace_schema();
}).then([] {
return net::get_messaging_service().invoke_on_all([] (auto& ms){
return ms.init_local_preferred_ip_cache();
});
});
return make_ready_future<>();
}
@@ -536,10 +538,11 @@ future<> save_truncation_records(const column_family& cf, db_clock::time_point t
out.write<db_clock::rep>(truncated_at.time_since_epoch().count());
map_type_impl::native_type tmp;
tmp.emplace_back(boost::any{ cf.schema()->id() }, boost::any{ buf });
tmp.emplace_back(cf.schema()->id(), data_value(buf));
auto map_type = map_type_impl::get_instance(uuid_type, bytes_type, true);
sstring req = sprint("UPDATE system.%s SET truncated_at = truncated_at + ? WHERE key = '%s'", LOCAL, LOCAL);
return qctx->qp().execute_internal(req, {tmp}).then([](auto rs) {
return qctx->qp().execute_internal(req, {make_map_value(map_type, tmp)}).then([](auto rs) {
truncation_records = {};
return force_blocking_flush(LOCAL);
});
@@ -629,7 +632,7 @@ future<db_clock::time_point> get_truncated_at(utils::UUID cf_id) {
set_type_impl::native_type prepare_tokens(std::unordered_set<dht::token>& tokens) {
set_type_impl::native_type tset;
for (auto& t: tokens) {
tset.push_back(boost::any(dht::global_partitioner().to_sstring(t)));
tset.push_back(dht::global_partitioner().to_sstring(t));
}
return tset;
}
@@ -637,7 +640,7 @@ set_type_impl::native_type prepare_tokens(std::unordered_set<dht::token>& tokens
std::unordered_set<dht::token> decode_tokens(set_type_impl::native_type& tokens) {
std::unordered_set<dht::token> tset;
for (auto& t: tokens) {
auto str = boost::any_cast<sstring>(t);
auto str = value_cast<sstring>(t);
assert(str == dht::global_partitioner().to_sstring(dht::global_partitioner().from_sstring(str)));
tset.insert(dht::global_partitioner().from_sstring(str));
}
@@ -654,7 +657,8 @@ future<> update_tokens(gms::inet_address ep, std::unordered_set<dht::token> toke
}
sstring req = "INSERT INTO system.%s (peer, tokens) VALUES (?, ?)";
return execute_cql(req, PEERS, ep.addr(), prepare_tokens(tokens)).discard_result().then([] {
auto set_type = set_type_impl::get_instance(utf8_type, true);
return execute_cql(req, PEERS, ep.addr(), make_set_value(set_type, prepare_tokens(tokens))).discard_result().then([] {
return force_blocking_flush(PEERS);
});
}
@@ -685,7 +689,7 @@ future<std::unordered_map<gms::inet_address, std::unordered_set<dht::token>>> lo
auto blob = row.get_blob("tokens");
auto cdef = peers()->get_column_definition("tokens");
auto deserialized = cdef->type->deserialize(blob);
auto tokens = boost::any_cast<set_type_impl::native_type>(deserialized);
auto tokens = value_cast<set_type_impl::native_type>(deserialized);
ret->emplace(peer, decode_tokens(tokens));
}
@@ -714,11 +718,28 @@ future<std::unordered_map<gms::inet_address, utils::UUID>> load_host_ids() {
future<> update_preferred_ip(gms::inet_address ep, gms::inet_address preferred_ip) {
sstring req = "INSERT INTO system.%s (peer, preferred_ip) VALUES (?, ?)";
return execute_cql(req, PEERS, ep.addr(), preferred_ip).discard_result().then([] {
return execute_cql(req, PEERS, ep.addr(), preferred_ip.addr()).discard_result().then([] {
return force_blocking_flush(PEERS);
});
}
future<std::unordered_map<gms::inet_address, gms::inet_address>> get_preferred_ips() {
sstring req = "SELECT peer, preferred_ip FROM system.%s";
return execute_cql(req, PEERS).then([] (::shared_ptr<cql3::untyped_result_set> cql_res_set) {
std::unordered_map<gms::inet_address, gms::inet_address> res;
for (auto& r : *cql_res_set) {
if (r.has("preferred_ip")) {
res.emplace(gms::inet_address(r.get_as<net::ipv4_address>("peer")),
gms::inet_address(r.get_as<net::ipv4_address>("preferred_ip")));
}
}
return res;
});
}
template <typename Value>
static future<> update_cached_values(gms::inet_address ep, sstring column_name, Value value) {
return make_ready_future<>();
@@ -787,16 +808,14 @@ future<> update_tokens(std::unordered_set<dht::token> tokens) {
}
sstring req = "INSERT INTO system.%s (key, tokens) VALUES (?, ?)";
return execute_cql(req, LOCAL, sstring(LOCAL), prepare_tokens(tokens)).discard_result().then([] {
auto set_type = set_type_impl::get_instance(utf8_type, true);
return execute_cql(req, LOCAL, sstring(LOCAL), make_set_value(set_type, prepare_tokens(tokens))).discard_result().then([] {
return force_blocking_flush(LOCAL);
});
}
future<> force_blocking_flush(sstring cfname) {
if (!qctx) {
return make_ready_future<>();
}
assert(qctx);
return qctx->_db.invoke_on_all([cfname = std::move(cfname)](database& db) {
// if (!Boolean.getBoolean("cassandra.unsafesystem"))
column_family& cf = db.find_column_family(NAME, cfname);
@@ -841,7 +860,7 @@ future<std::unordered_set<dht::token>> get_saved_tokens() {
auto blob = msg->one().get_blob("tokens");
auto cdef = local()->get_column_definition("tokens");
auto deserialized = cdef->type->deserialize(blob);
auto tokens = boost::any_cast<set_type_impl::native_type>(deserialized);
auto tokens = value_cast<set_type_impl::native_type>(deserialized);
return make_ready_future<std::unordered_set<dht::token>>(decode_tokens(tokens));
});

View File

@@ -94,6 +94,7 @@ future<> update_tokens(std::unordered_set<dht::token> tokens);
future<> update_tokens(gms::inet_address ep, std::unordered_set<dht::token> tokens);
future<> update_preferred_ip(gms::inet_address ep, gms::inet_address preferred_ip);
future<std::unordered_map<gms::inet_address, gms::inet_address>> get_preferred_ips();
template <typename Value>
future<> update_peer_info(gms::inet_address ep, sstring column_name, Value value);

View File

@@ -38,69 +38,67 @@
#include "dht/boot_strapper.hh"
#include "service/storage_service.hh"
#include "dht/range_streamer.hh"
#include "gms/failure_detector.hh"
#include "log.hh"
static logging::logger logger("boot_strapper");
namespace dht {
future<> boot_strapper::bootstrap() {
// FIXME: Stream data from other nodes
service::get_local_storage_service().finish_bootstrapping();
return make_ready_future<>();
#if 0
if (logger.isDebugEnabled())
logger.debug("Beginning bootstrap process");
logger.debug("Beginning bootstrap process: sorted_tokens={}", _token_metadata.sorted_tokens());
RangeStreamer streamer = new RangeStreamer(tokenMetadata, tokens, address, "Bootstrap");
streamer.addSourceFilter(new RangeStreamer.FailureDetectorSourceFilter(FailureDetector.instance));
for (String keyspaceName : Schema.instance.getNonSystemKeyspaces())
{
AbstractReplicationStrategy strategy = Keyspace.open(keyspaceName).getReplicationStrategy();
streamer.addRanges(keyspaceName, strategy.getPendingAddressRanges(tokenMetadata, tokens, address));
auto streamer = make_lw_shared<range_streamer>(_db, _token_metadata, _tokens, _address, "Bootstrap");
streamer->add_source_filter(std::make_unique<range_streamer::failure_detector_source_filter>(gms::get_local_failure_detector()));
for (const auto& keyspace_name : _db.local().get_non_system_keyspaces()) {
auto& ks = _db.local().find_keyspace(keyspace_name);
auto& strategy = ks.get_replication_strategy();
std::vector<range<token>> ranges = strategy.get_pending_address_ranges(_token_metadata, _tokens, _address);
logger.debug("Will stream keyspace={}, ranges={}", keyspace_name, ranges);
streamer->add_ranges(keyspace_name, ranges);
}
try
{
streamer.fetchAsync().get();
StorageService.instance.finishBootstrapping();
}
catch (InterruptedException e)
{
throw new RuntimeException("Interrupted while waiting on boostrap to complete. Bootstrap will have to be restarted.");
}
catch (ExecutionException e)
{
throw new RuntimeException("Error during boostrap: " + e.getCause().getMessage(), e.getCause());
}
#endif
return streamer->fetch_async().then_wrapped([streamer] (auto&& f) {
try {
auto state = f.get0();
} catch (...) {
throw std::runtime_error(sprint("Error during boostrap: %s", std::current_exception()));
}
service::get_local_storage_service().finish_bootstrapping();
return make_ready_future<>();
});
}
std::unordered_set<token> boot_strapper::get_bootstrap_tokens(token_metadata metadata, database& db) {
#if 0
Collection<String> initialTokens = DatabaseDescriptor.getInitialTokens();
auto initial_tokens = db.get_initial_tokens();
// if user specified tokens, use those
if (initialTokens.size() > 0)
{
logger.debug("tokens manually specified as {}", initialTokens);
List<Token> tokens = new ArrayList<Token>(initialTokens.size());
for (String tokenString : initialTokens)
{
Token token = StorageService.getPartitioner().getTokenFactory().fromString(tokenString);
if (metadata.getEndpoint(token) != null)
throw new ConfigurationException("Bootstrapping to existing token " + tokenString + " is not allowed (decommission/removenode the old node first).");
tokens.add(token);
if (initial_tokens.size() > 0) {
logger.debug("tokens manually specified as {}", initial_tokens);
std::unordered_set<token> tokens;
for (auto& token_string : initial_tokens) {
auto token = dht::global_partitioner().from_sstring(token_string);
if (metadata.get_endpoint(token)) {
throw std::runtime_error(sprint("Bootstrapping to existing token %s is not allowed (decommission/removenode the old node first).", token_string));
}
tokens.insert(token);
}
logger.debug("Get manually specified bootstrap_tokens={}", tokens);
return tokens;
}
#endif
size_t num_tokens = db.get_config().num_tokens();
if (num_tokens < 1) {
throw std::runtime_error("num_tokens must be >= 1");
}
// if (numTokens == 1)
// logger.warn("Picking random token for a single vnode. You should probably add more vnodes; failing that, you should probably specify the token manually");
if (num_tokens == 1) {
logger.warn("Picking random token for a single vnode. You should probably add more vnodes; failing that, you should probably specify the token manually");
}
return get_random_tokens(metadata, num_tokens);
auto tokens = get_random_tokens(metadata, num_tokens);
logger.debug("Get random bootstrap_tokens={}", tokens);
return tokens;
}
std::unordered_set<token> boot_strapper::get_random_tokens(token_metadata metadata, size_t num_tokens) {

View File

@@ -49,14 +49,16 @@ class boot_strapper {
using inet_address = gms::inet_address;
using token_metadata = locator::token_metadata;
using token = dht::token;
distributed<database>& _db;
/* endpoint that needs to be bootstrapped */
inet_address _address;
/* token of the node being bootstrapped. */
std::unordered_set<token> _tokens;
token_metadata _token_metadata;
public:
boot_strapper(inet_address addr, std::unordered_set<token> tokens, token_metadata tmd)
: _address(addr)
boot_strapper(distributed<database>& db, inet_address addr, std::unordered_set<token> tokens, token_metadata tmd)
: _db(db)
, _address(addr)
, _tokens(tokens)
, _token_metadata(tmd) {
}

View File

@@ -44,11 +44,19 @@ token byte_ordered_partitioner::midpoint(const token& t1, const token& t2) const
unsigned
byte_ordered_partitioner::shard_of(const token& t) const {
if (t._data.empty()) {
return 0;
switch (t._kind) {
case token::kind::before_all_keys:
return 0;
case token::kind::after_all_keys:
return smp::count - 1;
case token::kind::key:
if (t._data.empty()) {
return 0;
}
// treat first byte as a fraction in the range [0, 1) and divide it evenly:
return (uint8_t(t._data[0]) * smp::count) >> 8;
}
// treat first byte as a fraction in the range [0, 1) and divide it evenly:
return (uint8_t(t._data[0]) * smp::count) >> 8;
assert(0);
}
using registry = class_registrator<i_partitioner, byte_ordered_partitioner>;

View File

@@ -161,12 +161,7 @@ std::ostream& operator<<(std::ostream& out, const token& t) {
} else if (t._kind == token::kind::before_all_keys) {
out << "minimum token";
} else {
auto flags = out.flags();
for (auto c : t._data) {
unsigned char x = c;
out << std::hex << std::setw(2) << std::setfill('0') << +x << " ";
}
out.flags(flags);
out << global_partitioner().to_sstring(t);
}
return out;
}
@@ -297,6 +292,10 @@ int ring_position_comparator::operator()(const ring_position& lh, const ring_pos
return lh.tri_compare(s, rh);
}
int token_comparator::operator()(const token& t1, const token& t2) const {
return tri_compare(t1, t2);
}
void token::serialize(bytes::iterator& out) const {
uint8_t kind = _kind == dht::token::kind::before_all_keys ? 0 :
_kind == dht::token::kind::key ? 1 : 2;

View File

@@ -159,6 +159,8 @@ public:
}
};
using decorated_key_opt = std::experimental::optional<decorated_key>;
class i_partitioner {
public:
virtual ~i_partitioner() {}
@@ -390,6 +392,11 @@ struct ring_position_comparator {
int operator()(const ring_position& lh, const ring_position& rh) const;
};
struct token_comparator {
// Return values are those of a trichotomic comparison.
int operator()(const token& t1, const token& t2) const;
};
std::ostream& operator<<(std::ostream& out, const token& t);
std::ostream& operator<<(std::ostream& out, const decorated_key& t);

View File

@@ -75,6 +75,9 @@ token murmur3_partitioner::get_random_token() {
}
inline int64_t long_token(const token& t) {
if (t.is_minimum()) {
return std::numeric_limits<long>::min();
}
if (t._data.size() != sizeof(int64_t)) {
throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(int64_t), t._data.size()));
@@ -178,11 +181,19 @@ murmur3_partitioner::get_token_validator() {
unsigned
murmur3_partitioner::shard_of(const token& t) const {
int64_t l = long_token(t);
// treat l as a fraction between 0 and 1 and use 128-bit arithmetic to
// divide that range evenly among shards:
uint64_t adjusted = uint64_t(l) + uint64_t(std::numeric_limits<int64_t>::min());
return (__int128(adjusted) * smp::count) >> 64;
switch (t._kind) {
case token::kind::before_all_keys:
return 0;
case token::kind::after_all_keys:
return smp::count - 1;
case token::kind::key:
int64_t l = long_token(t);
// treat l as a fraction between 0 and 1 and use 128-bit arithmetic to
// divide that range evenly among shards:
uint64_t adjusted = uint64_t(l) + uint64_t(std::numeric_limits<int64_t>::min());
return (__int128(adjusted) * smp::count) >> 64;
}
assert(0);
}
using registry = class_registrator<i_partitioner, murmur3_partitioner>;

269
dht/range_streamer.cc Normal file
View File

@@ -0,0 +1,269 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modified by Cloudius Systems
* Copyright 2015 Cloudius Systems
*/
/*
* 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 "dht/range_streamer.hh"
#include "utils/fb_utilities.hh"
#include "locator/snitch_base.hh"
#include "database.hh"
#include "gms/gossiper.hh"
#include "gms/failure_detector.hh"
#include "log.hh"
#include "streaming/stream_plan.hh"
#include "streaming/stream_state.hh"
#include "service/storage_service.hh"
namespace dht {
logging::logger logger("range_streamer");
using inet_address = gms::inet_address;
static std::unordered_map<range<token>, std::unordered_set<inet_address>>
unordered_multimap_to_unordered_map(const std::unordered_multimap<range<token>, inet_address>& multimap) {
std::unordered_map<range<token>, std::unordered_set<inet_address>> ret;
for (auto x : multimap) {
ret[x.first].emplace(x.second);
}
return ret;
}
std::unordered_multimap<inet_address, range<token>>
range_streamer::get_range_fetch_map(const std::unordered_multimap<range<token>, inet_address>& ranges_with_sources,
const std::unordered_set<std::unique_ptr<i_source_filter>>& source_filters,
const sstring& keyspace) {
std::unordered_multimap<inet_address, range<token>> range_fetch_map_map;
for (auto x : unordered_multimap_to_unordered_map(ranges_with_sources)) {
const range<token>& range_ = x.first;
const std::unordered_set<inet_address>& addresses = x.second;
bool found_source = false;
for (auto address : addresses) {
if (address == utils::fb_utilities::get_broadcast_address()) {
// If localhost is a source, we have found one, but we don't add it to the map to avoid streaming locally
found_source = true;
continue;
}
auto filtered = false;
for (const auto& filter : source_filters) {
if (!filter->should_include(address)) {
filtered = true;
break;
}
}
if (filtered) {
continue;
}
range_fetch_map_map.emplace(address, range_);
found_source = true;
break; // ensure we only stream from one other node for each range
}
if (!found_source) {
throw std::runtime_error(sprint("unable to find sufficient sources for streaming range %s in keyspace %s", range_, keyspace));
}
}
return range_fetch_map_map;
}
std::unordered_multimap<range<token>, inet_address>
range_streamer::get_all_ranges_with_sources_for(const sstring& keyspace_name, std::vector<range<token>> desired_ranges) {
logger.debug("{} ks={}", __func__, keyspace_name);
auto& ks = _db.local().find_keyspace(keyspace_name);
auto& strat = ks.get_replication_strategy();
auto tm = _metadata.clone_only_token_map();
auto range_addresses = unordered_multimap_to_unordered_map(strat.get_range_addresses(tm));
std::unordered_multimap<range<token>, inet_address> range_sources;
auto& snitch = locator::i_endpoint_snitch::get_local_snitch_ptr();
for (auto& desired_range : desired_ranges) {
auto found = false;
for (auto& x : range_addresses) {
const range<token>& src_range = x.first;
if (src_range.contains(desired_range, dht::tri_compare)) {
std::unordered_set<inet_address>& addresses = x.second;
auto preferred = snitch->get_sorted_list_by_proximity(_address, addresses);
for (inet_address& p : preferred) {
range_sources.emplace(desired_range, p);
}
found = true;
}
}
if (!found) {
throw std::runtime_error(sprint("No sources found for %s", desired_range));
}
}
return range_sources;
}
std::unordered_multimap<range<token>, inet_address>
range_streamer::get_all_ranges_with_strict_sources_for(const sstring& keyspace_name, std::vector<range<token>> desired_ranges) {
logger.debug("{} ks={}", __func__, keyspace_name);
assert (_tokens.empty() == false);
auto& ks = _db.local().find_keyspace(keyspace_name);
auto& strat = ks.get_replication_strategy();
//Active ranges
auto metadata_clone = _metadata.clone_only_token_map();
auto range_addresses = unordered_multimap_to_unordered_map(strat.get_range_addresses(metadata_clone));
//Pending ranges
metadata_clone.update_normal_tokens(_tokens, _address);
auto pending_range_addresses = unordered_multimap_to_unordered_map(strat.get_range_addresses(metadata_clone));
//Collects the source that will have its range moved to the new node
std::unordered_multimap<range<token>, inet_address> range_sources;
for (auto& desired_range : desired_ranges) {
for (auto& x : range_addresses) {
const range<token>& src_range = x.first;
if (src_range.contains(desired_range, dht::tri_compare)) {
std::vector<inet_address> old_endpoints(x.second.begin(), x.second.end());
auto it = pending_range_addresses.find(desired_range);
if (it == pending_range_addresses.end()) {
throw std::runtime_error(sprint("Can not find desired_range = {} in pending_range_addresses", desired_range));
}
std::unordered_set<inet_address> new_endpoints = it->second;
//Due to CASSANDRA-5953 we can have a higher RF then we have endpoints.
//So we need to be careful to only be strict when endpoints == RF
if (old_endpoints.size() == strat.get_replication_factor()) {
auto it = std::remove_if(old_endpoints.begin(), old_endpoints.end(),
[&new_endpoints] (inet_address ep) { return new_endpoints.count(ep); });
old_endpoints.erase(it, old_endpoints.end());
if (old_endpoints.size() != 1) {
throw std::runtime_error(sprint("Expected 1 endpoint but found %d", old_endpoints.size()));
}
}
range_sources.emplace(desired_range, old_endpoints.front());
}
}
//Validate
auto nr = range_sources.count(desired_range);
if (nr < 1) {
throw std::runtime_error(sprint("No sources found for %s", desired_range));
}
if (nr > 1) {
throw std::runtime_error(sprint("Multiple endpoints found for %s", desired_range));
}
inet_address source_ip = range_sources.find(desired_range)->second;
auto& gossiper = gms::get_local_gossiper();
auto source_state = gossiper.get_endpoint_state_for_endpoint(source_ip);
if (gossiper.is_enabled() && source_state && !source_state->is_alive()) {
throw std::runtime_error(sprint("A node required to move the data consistently is down (%s). If you wish to move the data from a potentially inconsistent replica, restart the node with -Dcassandra.consistent.rangemovement=false", source_ip));
}
}
return range_sources;
}
bool range_streamer::use_strict_sources_for_ranges(const sstring& keyspace_name) {
auto& ks = _db.local().find_keyspace(keyspace_name);
auto& strat = ks.get_replication_strategy();
return !_db.local().is_replacing()
&& use_strict_consistency()
&& !_tokens.empty()
&& _metadata.get_all_endpoints().size() != strat.get_replication_factor();
}
void range_streamer::add_ranges(const sstring& keyspace_name, std::vector<range<token>> ranges) {
auto ranges_for_keyspace = use_strict_sources_for_ranges(keyspace_name)
? get_all_ranges_with_strict_sources_for(keyspace_name, ranges)
: get_all_ranges_with_sources_for(keyspace_name, ranges);
if (logger.is_enabled(logging::log_level::debug)) {
for (auto& x : ranges_for_keyspace) {
logger.debug("{} : range {} exists on {}", _description, x.first, x.second);
}
}
std::unordered_map<inet_address, std::vector<range<token>>> range_fetch_map;
for (auto& x : get_range_fetch_map(ranges_for_keyspace, _source_filters, keyspace_name)) {
range_fetch_map[x.first].emplace_back(x.second);
}
if (logger.is_enabled(logging::log_level::debug)) {
for (auto& x : range_fetch_map) {
logger.debug("{} : range {} from source {} for keyspace {}", _description, x.second, x.first, keyspace_name);
}
}
_to_fetch.emplace(keyspace_name, std::move(range_fetch_map));
}
future<streaming::stream_state> range_streamer::fetch_async() {
for (auto& fetch : _to_fetch) {
const auto& keyspace = fetch.first;
for (auto& x : fetch.second) {
auto& source = x.first;
auto& ranges = x.second;
auto preferred = net::get_local_messaging_service().get_preferred_ip(source);
/* Send messages to respective folks to stream data over to me */
if (logger.is_enabled(logging::log_level::debug)) {
logger.debug("{}ing from {} ranges {}", _description, source, ranges);
}
_stream_plan.request_ranges(source, preferred, keyspace, ranges);
}
}
return _stream_plan.execute();
}
std::unordered_multimap<inet_address, range<token>>
range_streamer::get_work_map(const std::unordered_multimap<range<token>, inet_address>& ranges_with_source_target,
const sstring& keyspace) {
auto filter = std::make_unique<dht::range_streamer::failure_detector_source_filter>(gms::get_local_failure_detector());
std::unordered_set<std::unique_ptr<i_source_filter>> source_filters;
source_filters.emplace(std::move(filter));
return get_range_fetch_map(ranges_with_source_target, source_filters, keyspace);
}
bool range_streamer::use_strict_consistency() {
return service::get_local_storage_service().db().local().get_config().consistent_rangemovement();
}
} // dht

174
dht/range_streamer.hh Normal file
View File

@@ -0,0 +1,174 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modified by Cloudius Systems
* Copyright 2015 Cloudius Systems
*/
/*
* 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 "locator/token_metadata.hh"
#include "locator/snitch_base.hh"
#include "streaming/stream_plan.hh"
#include "streaming/stream_state.hh"
#include "gms/inet_address.hh"
#include "gms/i_failure_detector.hh"
#include "range.hh"
#include <seastar/core/distributed.hh>
#include <unordered_map>
#include <memory>
class database;
namespace dht {
/**
* Assists in streaming ranges to a node.
*/
class range_streamer {
public:
using inet_address = gms::inet_address;
using token_metadata = locator::token_metadata;
using stream_plan = streaming::stream_plan;
using stream_state = streaming::stream_state;
using i_failure_detector = gms::i_failure_detector;
static bool use_strict_consistency();
public:
/**
* A filter applied to sources to stream from when constructing a fetch map.
*/
class i_source_filter {
public:
virtual bool should_include(inet_address endpoint) = 0;
virtual ~i_source_filter() {}
};
/**
* Source filter which excludes any endpoints that are not alive according to a
* failure detector.
*/
class failure_detector_source_filter : public i_source_filter {
private:
gms::i_failure_detector& _fd;
public:
failure_detector_source_filter(i_failure_detector& fd) : _fd(fd) { }
virtual bool should_include(inet_address endpoint) override { return _fd.is_alive(endpoint); }
};
/**
* Source filter which excludes any endpoints that are not in a specific data center.
*/
class single_datacenter_filter : public i_source_filter {
private:
sstring _source_dc;
public:
single_datacenter_filter(const sstring& source_dc)
: _source_dc(source_dc) {
}
virtual bool should_include(inet_address endpoint) override {
auto& snitch_ptr = locator::i_endpoint_snitch::get_local_snitch_ptr();
return snitch_ptr->get_datacenter(endpoint) == _source_dc;
}
};
range_streamer(distributed<database>& db, token_metadata& tm, std::unordered_set<token> tokens, inet_address address, sstring description)
: _db(db)
, _metadata(tm)
, _tokens(std::move(tokens))
, _address(address)
, _description(std::move(description))
, _stream_plan(_description, true) {
}
range_streamer(distributed<database>& db, token_metadata& tm, inet_address address, sstring description)
: range_streamer(db, tm, std::unordered_set<token>(), address, description) {
}
void add_source_filter(std::unique_ptr<i_source_filter> filter) {
_source_filters.emplace(std::move(filter));
}
void add_ranges(const sstring& keyspace_name, std::vector<range<token>> ranges);
private:
bool use_strict_sources_for_ranges(const sstring& keyspace_name);
/**
* Get a map of all ranges and their respective sources that are candidates for streaming the given ranges
* to us. For each range, the list of sources is sorted by proximity relative to the given destAddress.
*/
std::unordered_multimap<range<token>, inet_address>
get_all_ranges_with_sources_for(const sstring& keyspace_name, std::vector<range<token>> desired_ranges);
/**
* Get a map of all ranges and the source that will be cleaned up once this bootstrapped node is added for the given ranges.
* For each range, the list should only contain a single source. This allows us to consistently migrate data without violating
* consistency.
*/
std::unordered_multimap<range<token>, inet_address>
get_all_ranges_with_strict_sources_for(const sstring& keyspace_name, std::vector<range<token>> desired_ranges);
private:
/**
* @param rangesWithSources The ranges we want to fetch (key) and their potential sources (value)
* @param sourceFilters A (possibly empty) collection of source filters to apply. In addition to any filters given
* here, we always exclude ourselves.
* @return
*/
static std::unordered_multimap<inet_address, range<token>>
get_range_fetch_map(const std::unordered_multimap<range<token>, inet_address>& ranges_with_sources,
const std::unordered_set<std::unique_ptr<i_source_filter>>& source_filters,
const sstring& keyspace);
public:
static std::unordered_multimap<inet_address, range<token>>
get_work_map(const std::unordered_multimap<range<token>, inet_address>& ranges_with_source_target,
const sstring& keyspace);
#if 0
// For testing purposes
Multimap<String, Map.Entry<InetAddress, Collection<Range<Token>>>> toFetch()
{
return toFetch;
}
#endif
public:
future<streaming::stream_state> fetch_async();
private:
distributed<database>& _db;
token_metadata& _metadata;
std::unordered_set<token> _tokens;
inet_address _address;
sstring _description;
std::unordered_multimap<sstring, std::unordered_map<inet_address, std::vector<range<token>>>> _to_fetch;
std::unordered_set<std::unique_ptr<i_source_filter>> _source_filters;
stream_plan _stream_plan;
};
} // dht

39
dht/token_range.hh Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 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 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 License for more details.
*
* You should have received a copy of the GNU General License
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
namespace dht {
struct endpoint_details {
sstring _host;
sstring _datacenter;
sstring _rack;
};
struct token_range {
sstring _start_token;
sstring _end_token;
std::vector<sstring> _endpoints;
std::vector<sstring> _rpc_endpoints;
std::vector<endpoint_details> _endpoint_details;
};
}

37
dist/ami/build_ami.sh vendored
View File

@@ -1,9 +1,7 @@
#!/bin/sh -e
if [ ! -e dist/ami/build_ami.sh ] || [ ! -e ../scylla-jmx/dist/redhat/build_rpm.sh ] || [ ! -e ../cassandra/dist/redhat/build_rpm.sh ]; then
if [ ! -e dist/ami/build_ami.sh ]; then
echo "run build_ami.sh in top of scylla dir"
echo "please make sure scylla-jmx is checked out under the same directory as scylla"
echo "please make sure cassandra with scylla tools branch checked out under the same directory as scylla"
exit 1
fi
@@ -14,39 +12,6 @@ if [ ! -f variables.json ]; then
exit 1
fi
if [ ! -f files/scylla-server.rpm ] || [ ! -f files/scylla-server-debuginfo.rpm ]; then
cd ../../
dist/redhat/build_rpm.sh
SCYLLA_VERSION=$(cat build/SCYLLA-VERSION-FILE)
SCYLLA_RELEASE=$(cat build/SCYLLA-RELEASE-FILE)
RPM=`ls build/rpms/scylla-server-$SCYLLA_VERSION-$SCYLLA_RELEASE*.x86_64.rpm|grep -v debuginfo`
cp $RPM dist/ami/files/scylla-server.rpm
cp build/rpms/scylla-server-debuginfo-$SCYLLA_VERSION-$SCYLLA_RELEASE*.x86_64.rpm dist/ami/files/scylla-server-debuginfo.rpm
cd -
fi
if [ ! -f files/scylla-jmx.rpm ]; then
CWD=`pwd`
cd ../../../scylla-jmx
dist/redhat/build_rpm.sh
SCYLLA_VERSION=$(cat build/SCYLLA-VERSION-FILE)
SCYLLA_RELEASE=$(cat build/SCYLLA-RELEASE-FILE)
RPM=`ls build/rpms/scylla-jmx-$SCYLLA_VERSION-$SCYLLA_RELEASE*.noarch.rpm`
cp $RPM $CWD/files/scylla-jmx.rpm
cd -
fi
if [ ! -f files/scylla-tools.rpm ]; then
CWD=`pwd`
cd ../../../cassandra
dist/redhat/build_rpm.sh
SCYLLA_VERSION=$(cat build/SCYLLA-VERSION-FILE)
SCYLLA_RELEASE=$(cat build/SCYLLA-RELEASE-FILE)
RPM=`ls build/rpms/scylla-tools-$SCYLLA_VERSION-$SCYLLA_RELEASE*.noarch.rpm`
cp $RPM $CWD/files/scylla-tools.rpm
cd -
fi
if [ ! -d packer ]; then
wget https://dl.bintray.com/mitchellh/packer/packer_0.8.6_linux_amd64.zip
mkdir packer

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