Commit Graph

606 Commits

Author SHA1 Message Date
Pavel Emelyanov
dbaca825ec storage_service: Remove _initialized and is_initialized()
This bit is hairy. First, it indicates that the storage service
entered the init_server() method. But, once the node is up and
running it also indicates whether the gossiper is enabled or not
via the APi call.

To rely on the operation mode, first, the NONE mode is introduced
at which the server starts. Then in init_server() is switches to
STARTING.

Second change is to stop using the bit in enable/disable gossiper
API call, instead -- check the gossiper.is_enabled() itself.

To keep the is_initialized API call compatible, when the operation
mode is NORMAL it would return true/false according to the status
of the gossiper. This change is simple because storage service API
handlers already have the gossiper instance hanging around.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2022-03-07 13:29:47 +03:00
Pavel Emelyanov
ffbfa3b542 storage_service: Remove _joined and is_joined()
The is_joined() status can be get with get_operation_mode(). Since
it indicates that the operation mode is JOINING, NORMAL or anything
above, the operation mode the enum class should be shuffled to get
the simple >= comparison.

Another needed change is to set mode few steps earlier than it
happens now to cover the non-bootstrap startup case.

And the third change is to partially revert the d49aa7ab that made
the .is_joined() method be future-less. Nowadays the is_joined() is
called only from the API which is happy with being future-full in
all other storage service state checks.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2022-03-07 13:29:47 +03:00
Pavel Emelyanov
ca03fd3145 storage_service: Replace is_starting() with get_operation_mode()
This is trivial change, since the only user is in API and the
get_operation_mode + mode values are at hand.

One thing to pay attention to -- the new method checks the mode to
be <= STARTING, not for equality. Now this is equivalent change,
but next patch will introduce NONE mode that should be reported
as is_starting() too.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2022-03-07 13:29:47 +03:00
Pavel Emelyanov
c385fe7d79 storage_service: Make get_operation_mode() return mode itself
Now it reports back formatted mode. For future convenience it's
needed to return the raw value, all the more so the mode enum class
is already public.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2022-03-07 13:29:47 +03:00
Nadav Har'El
eec39e1258 Merge 'api: keyspace_scrub: validate params' from Benny Halevy
Refs #10087

Add validation of all params for the keyspace_scrub api.
The validation method is generic and should be used by all apis eventually,
but I'm leaving that as follow-up work.

While at it, fixed the exception types thrown on invalid `scrub_mode` or `quarantine_mode` values from `std::runtime_error` to `httpd::bad_param_exception` so to generate the `bad_request` http status.

And added unit tests to verify that, and the handling of an unknown parameter.

Test: unit(dev)
DTest: nodetool_additional_test.py::TestNodetool::{test_scrub_with_one_node_expect_data_loss,test_scrub_with_multi_nodes_expect_data_rebuild,test_scrub_sstable_with_invalid_fragment,test_scrub_ks_sstable_with_invalid_fragment,test_scrub_segregate_sstable_with_invalid_fragment,test_scrub_segregate_ks_sstable_with_invalid_fragment}

Closes #10090

* github.com:scylladb/scylla:
  api: storage_service: scrub: validate parameters
  api: storage_service: refactor parse_tables
  api: storage_service: refactor validate_keyspace
  test: rest_api: add test_storage_service_keyspace_scrub tests
  api: storage_service: scrub: throw httpd::bad_param_exception for invalid param values
2022-02-22 20:58:25 +03:00
Michael Livshin
c96708d262 add support for the ME sstable format
The ME format has been introduced in Cassandra 3.11.11:

11952fae77/src/java/org/apache/cassandra/io/sstable/format/big/BigFormat.java (L123)
d84c6e9810

It adds originating host id to sstable metadata in support of fixing
loss of commit log data when moving sstables between nodes:

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

In Scylla:

* The supported way to ingest sstables is via upload/, where stored
  commit log replay position should be disregarded (but see
  https://github.com/scylladb/scylla/issues/10080).

* A later commit in this series implements originating host id
  validation for native ME sstables.

Signed-off-by: Michael Livshin <michael.livshin@scylladb.com>
2022-02-16 18:21:24 +02:00
Benny Halevy
5a63026932 api: storage_service: scrub: validate parameters
Validate all parameters, rejecting unsupported parameters.

Refs #10087

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-02-16 17:01:46 +02:00
Benny Halevy
16afde46e7 api: storage_service: refactor parse_tables
Prepare for string-based parsing and validation.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-02-16 16:53:18 +02:00
Benny Halevy
cce6810615 api: storage_service: refactor validate_keyspace
Prepare for string-based validation.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-02-16 16:53:18 +02:00
Benny Halevy
fc2e9abeba api: storage_service: scrub: throw httpd::bad_param_exception for invalid param values
Throwing std::runtime_error results in
http status 500 (internal_server_error), but the problem
is with the request parameters, nt with the server.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-02-16 15:39:17 +02:00
Benny Halevy
f6431824a7 api: add keyspace_offstrategy_compaction
Perform offstrategy compaction via the REST API with
a new `keyspace_offstrategy_compaction` option.

This is useful for performing offstrategy compaction
post repair, after repairing all token ranges.

Otherwise, offstrategy compaction will only be
auto-triggered after a 5 minutes idle timeout.

Like major compaction, the api call returns the offstrategy
compaction task future, so it's waited on.
The `long` result counts the number of tables that required
offstrategy compaction.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-01-30 20:40:39 +02:00
Avi Kivity
fcb8d040e8 treewide: use Software Package Data Exchange (SPDX) license identifiers
Instead of lengthy blurbs, switch to single-line, machine-readable
standardized (https://spdx.dev) license identifiers. The Linux kernel
switched long ago, so there is strong precedent.

Three cases are handled: AGPL-only, Apache-only, and dual licensed.
For the latter case, I chose (AGPL-3.0-or-later and Apache-2.0),
reasoning that our changes are extensive enough to apply our license.

The changes we applied mechanically with a script, except to
licenses/README.md.

Closes #9937
2022-01-18 12:15:18 +01:00
Benny Halevy
4db57267a6 repair: move tracker-dependent free functions to repair_service
These functions are called from the api layer.
Continue to hide the repair tracker from the caller
but use the repair_service already available
at the api layer to invoke the respective high-level
methods without requiring `the_repair_tracker()`.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2022-01-10 11:40:09 +02:00
Avi Kivity
bbad8f4677 replica: move ::database, ::keyspace, and ::table to replica namespace
Move replica-oriented classes to the replica namespace. The main
classes moved are ::database, ::keyspace, and ::table, but a few
ancillary classes are also moved. There are certainly classes that
should be moved but aren't (like distributed_loader) but we have
to start somewhere.

References are adjusted treewide. In many cases, it is obvious that
a call site should not access the replica (but the data_dictionary
instead), but that is left for separate work.

scylla-gdb.py is adjusted to look for both the new and old names.
2022-01-07 12:04:38 +02:00
Avi Kivity
ae3a360725 database: Move database, keyspace, table classes to replica/ directory
The database, keyspace, and table classes represent the replica-only
part of the objects after which they are named. Reading from a table
doesn't give you the full data, just the replica's view, and it is not
consistent since reconciliation is applied on the coordinator.

As a first step in acknowledging this, move the related files to
a replica/ subdirectory.
2022-01-06 17:07:30 +02:00
Benny Halevy
85f10138f0 api: storage_service: validate_keyspace: improve exception error message
Generate the error message using the
no_such_keyspace(ks_name) exception.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-09 14:40:21 +02:00
Benny Halevy
6805ce5bd9 api: compaction_manager: add stop_keyspace_compaction
Allow stopping compaction by type on a given keyspace
and list of tables.

Add respective rest_api test.

Fixes #9700

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-09 14:40:13 +02:00
Benny Halevy
522a32f19f api: storage_service: expose validate_keyspace and parse_tables
To be used by the compaction_manager api in a following patch.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-09 14:25:53 +02:00
Benny Halevy
71c95faeee api: compaction_manager: stop_compaction: fix type description
List only the compaction types we support stopping.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-09 14:17:38 +02:00
Benny Halevy
ff63ad9f6e api: storage_service: add parse_tables
Splits and validate the cf parameter, containing an optional
comma-separated list of table names.

If any table is not found and a no_such_column_family
exception is thrown, wrap it in a `bad_param_exception`
so it will translate to `reply::status_type::bad_request`
rather than `reply::status_type::internal_server_error`.

With that, hide the split_cf function from api/api.hh
since it was used only from api/storage_service
and new use sites should use validate_tables instead.

Fixes #9754

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-08 16:42:40 +02:00
Benny Halevy
8cbecb1c21 database: find_uuid: throw no_such_column_family exception if ks/cf were not found
Rather than masquerading all errors as std::out_of_range("")
convert only the std::out_of_range error from _ks_cf_to_uuid.at()
to no_such_column_family(ks, cf).  That relieves all callers of
fund_uuid from doing that conversion themselves.

For example, get_uuid in api/column_family now only deals with converting
no_such_column_family to bad_param_exception, as it needs to do
at the api level, rather than generating a similar error from scratch.

Other call sites required no intervention.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-08 16:35:38 +02:00
Benny Halevy
cc122984d6 compaction: scrub: add quarantine_mode option
Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-05 18:29:04 +02:00
Benny Halevy
60ff28932c compaction_manager: perform_sstable_scrub: get the whole compaction_type_options::scrub
So we can pass additional options on top of the scrub mode.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-12-05 18:21:37 +02:00
Avi Kivity
03755b362a Merge 'compaction_manager api: stop ongoing compactions' from Benny Halevy
This series extends `compaction_manager::stop_ongoing_compaction` so it can be used from the api layer for:
- table::disable_auto_compaction
- compaction_manager::stop_compaction

Fixes #9313
Fixes #9695

Test: unit(dev)

Closes #9699

* github.com:scylladb/scylla:
  compaction_manager: stop_compaction: wait for ongoing compactions to stop
  compaction_manager: stop_ongoing_compactions: log Stopping 0 tasks at debug level
  compaction_manager: unify stop_ongoing_compactions implementations
  compaction_manager: stop_ongoing_compactions: add compaction_type option
  compaction_manager: get_compactions: get a table* parameter
  table: disable_auto_compaction: stop ongoing compactions
  compaction_manager: make stop_ongoing_compactions public
  table: futurize disable_auto_compactions
2021-11-30 19:08:14 +02:00
Raphael S. Carvalho
0d5ac845e1 compaction: Make cleanup withstand better disk pressure scenario
It's not uncommong for cleanup to be issued against an entire keyspace,
which may be composed of tons of tables. To increase chances of success
if low on space, cleanup will now start from smaller tables first, such
that bigger tables will have more space available, once they're reached,
to satisfy their space requirement.

parallel_for_each() is dropped and wasn't needed given that manager
performs per-shard serialization of cleanup jobs.

Refs #9504.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20211130133712.64517-1-raphaelsc@scylladb.com>
2021-11-30 16:15:24 +02:00
Benny Halevy
957003e73f compaction_manager: stop_compaction: wait for ongoing compactions to stop
Similar to #9313, stop_compaction should also reuse the
stop_ongoing_comapctions() infrastructure and wait on ongoing
compactions of the given type to stop.

Fixes #9695

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-11-30 16:09:11 +02:00
Benny Halevy
b60d697084 table: futurize disable_auto_compactions
So it can stop ongoing compaction and wait
for them to complete.

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
2021-11-30 08:33:04 +02:00
Pavel Emelyanov
5166a98ce4 streaming, api: Use captured manager in handlers
Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-11-24 12:17:37 +03:00
Pavel Emelyanov
fd920e2420 streaming, api: Standardize the API start/stop
Todays idea of API reg/unreg is to carry the target service via
lambda captures down to the route handlers and unregister those
handers before the target is about to stop.

This patch makes it so for the streaming API.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-11-24 12:17:37 +03:00
Botond Dénes
a51529dd15 protocol_servers: strengthen guarantees of listen_addresses()
In early versions of the series which proposed protocol servers, the
interface had two methods answering pretty much the same question of
whether the server is running or not:
* listen_addresses(): empty list -> server not running
* is_server_running()

To reduce redundancy and to avoid possible inconsistencies between the
two methods, `is_server_running()` was scrapped, but re-added by a
follow-up patch because `listen_addresses()` proved to be unreliable as
a source for whether the server is running or not.
This patch restores the previous state of having only
`listen_addresses()` with two additional changes:
* rephrase the comment on `listen_addresses()` to make it clear that
  implementations must return empty list when the server is not running;
* those implementations that have a reliable source of whether the
  server is running or not, use it to force-return an empty list when
  the server is not running

Tests: dtest(nodetool_additional_test.py)
Signed-off-by: Botond Dénes <bdenes@scylladb.com>
Message-Id: <20211117062539.16932-1-bdenes@scylladb.com>
2021-11-19 11:09:09 +03:00
Benny Halevy
9d4262e264 protocol_server: add per-protocol is_server_running method
Change b0a2a9771f broke
the generic api implementation of
is_native_transport_running that relied on
the addresses list being empty agter the server is stopped.

To fix that, this change introduces a pure virtual method:
protocol_server::is_server_running that can be implemented
by each derived class.

Test: unit(dev)
DTest: nodetool_additional_test.py:TestNodetool.binary_test

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
Message-Id: <20211114135248.588798-1-bhalevy@scylladb.com>
2021-11-14 16:01:31 +02:00
Botond Dénes
b58403fb63 Merge "Flatten database drain" from Pavel E
"
Draining the database is now scattered across the do_drain()
method of the storage_service. Also it tells shutdown drain
from API drain.

This set packs this logic into the database::drain() method.

tests: unit(dev), start-stop-drain(dev)
"

* 'br-database-drain' of https://github.com/xemul/scylla:
  database, storage_service: Pack database::drain() method
  storage_service: Shuffle drain sequence
  storage_service, database: Move flush-on-drain code
  storage_service: Remove bool from do_drain
2021-11-11 08:19:35 +02:00
Pavel Emelyanov
82509c9e74 storage_service, database: Move flush-on-drain code
Flushing all CFs on shutdown is now fully managed in storage service
and it looks weird. Some better place for it seems to be the database
itself.

Moving the flushing code also imples moving the drain_progress thing
and patching the relevant API call.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-11-09 19:11:49 +03:00
Raphael S. Carvalho
e2f6a47999 compaction: switch to table_state in estimated_pending_compactions()
Last method in compaction_strategy using table. From now on,
compaction strategy no longer works directly with table.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
2021-11-09 11:25:28 -03:00
Botond Dénes
134fa98ff4 transport: controller: implement the protocol_server interface 2021-11-05 15:42:41 +02:00
Botond Dénes
bda0d0ccba thrift: controller: implement the protocol_server interface 2021-11-05 15:42:41 +02:00
Asias He
f5f5714aa6 repair: Return HTTP 400 when repiar id is not found
There are two APIs for checking the repair status and they behave
differently in case the id is not found.

```
{"host": "192.168.100.11:10001", "method": "GET", "uri":
"/storage_service/repair_async/system_auth?id=999", "duration": "1ms",
"status": 400, "bytes": 49, "dump": "HTTP/1.1 400 Bad
Request\r\nContent-Length: 49\r\nContent-Type: application/json\r\nDate:
Wed, 03 Nov 2021 10:49:33 GMT\r\nServer: Seastar
httpd\r\n\r\n{\"message\": \"unknown repair id 999\", \"code\": 400}"}

{"host": "192.168.100.11:10001", "method": "GET", "uri":
"/storage_service/repair_status?id=999&timeout=1", "duration": "0ms",
"status": 500, "bytes": 49, "dump": "HTTP/1.1 500 Internal Server
Error\r\nContent-Length: 49\r\nContent-Type: application/json\r\nDate:
Wed, 03 Nov 2021 10:49:33 GMT\r\nServer: Seastar
httpd\r\n\r\n{\"message\": \"unknown repair id 999\", \"code\": 500}"}
```

The correct status code is 400 as this is a parameter error and should
not be retried.

Returning status code 500 makes smarter http clients retry the request
in hopes of server recovering.

After this patch:

curl -X PGET
'http://127.0.0.1:10000/storage_service/repair_async/system_auth?id=9999'
{"message": "unknown repair id 9999", "code": 400}

curl -X GET
'http://127.0.0.1:10000/storage_service/repair_status?id=9999'
{"message": "unknown repair id 9999", "code": 400}

Fixes #9576

Closes #9578
2021-11-03 17:15:40 +02:00
Benny Halevy
a2fc3345bd storage_service: futurize storage_service::describe_ring
Convert storage_service::describe_ring to a coroutine
to prevent reactor stalls as seen in #9280.

Fixes #9280
Closes #9282

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>

Closes #9282
2021-10-28 16:51:57 +03:00
Alejo Sanchez
0a63e72fa4 api: (minor) fix typo bool instead of boolean
In definition for /column_family/major_compaction/{name} there is an
incorrect use of "bool" instead of "boolean".

Signed-off-by: Alejo Sanchez <alejo.sanchez@scylladb.com>

Closes #9516
2021-10-27 12:25:59 +02:00
Pavel Emelyanov
f0b5ab1c61 storage_service, api: Move set-tables-autocompaction back into API
The global autocompaction toggle is no longer tied to the storage
service. It naturally belongs to the database, but is small and
tidy enough not to pollute database methods and can be placed into
the api/ dir itself.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:13:59 +03:00
Pavel Emelyanov
fece1a2f9f api: Fix indentation after previous patch
Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:13:56 +03:00
Pavel Emelyanov
c5128eea67 api, database, storage_service: Unify auto-compaction toggle
There are two knobs here -- global and per-table one. Both were added
without any synchronisation, but the former one was later fixed to
become serialized and not to be available "too early".

This patch unifies both toggles to be serialized with each-other and
not be enabled too early.

The justification for this change is to move the global toggle from out
of the storage service, as it really belongs to the database, not the
storage service. Respectively, the current synchronization, that depends
on storage service internals, should be replaced with something else.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:12:39 +03:00
Pavel Emelyanov
c53c74258a api: Remove storage service from new APIs
The APIs that had been recently switched to using relevant services no
longer need the storage service reference capture, so remove it.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:11:52 +03:00
Pavel Emelyanov
c504361c15 view_builder: Accept view_build_statuses
The code itself is already in relevant .cc file, not move it to the
relevant class.

The only significant change is where to get token metadata from.
In its old location tokens were provided by the storage service
itself, now when it's in the view builder there's no "native" place
to get them from, however the rest of the view building code gets
tokens from global storage proxy, so do the same here.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:11:40 +03:00
Pavel Emelyanov
540c6fa5ae api, storage_service: Keep view builder API handlers separate
There's the 'storage_service/view_build_statuses' endpoint. It's
handler code sits in the storage_service, but the functionality
belongs purely to view_builder. Same as with sstables loader,
detach the enpoint's API set/unset code, next patches will fix
the handler to use view_builder.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:09:07 +03:00
Pavel Emelyanov
68ecec0197 sstables_loader: Accept the sstables loading code
The code was moved in the relevant .cc file by previous patch, now
make it sit in the relevant class. One "significant" change is that
the messaging service is available by local reference already, not
by the sharded one. Other dependencies are already satisfied by the
patch that introduced the sstables_loader class.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:08:21 +03:00
Pavel Emelyanov
7e49359720 storage_service, api: Keep sstables loading API handlers separate
Right now the handlers sit in one boat with the rest of the storage
service APIs. Next patches will switch this particular endpoint to
use previously introduced sstables_loader, before doing so here's
the respective API set/unset stubs.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>
2021-10-11 11:05:45 +03:00
Raphael S. Carvalho
342bfbd65a compaction: Make major compaction on keyspace resilient if low on space
Let's major compact the smallest tables first, increasing chances of
success if low on disk space.

parallel_for_each() didn't have any effect on space requirement as
compaction_manager serializes major compaction in a shard.
As parallel_for_each() is no longer used, find_column_family() is now
used before each compact_all_sstables() to avoid a race with table drop.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <20211005135257.31931-1-raphaelsc@scylladb.com>
2021-10-05 17:04:34 +03:00
Avi Kivity
148a12f3da Merge "Keep storage_service less aware of cdc internals" from Pavel E
"
The storage_service is involved in the cdc_generation_service guts
more than needed.

 - the bool _for_testing bit is cdc-only
 - there's API-only cdc_generation_service getter
 - cdc_g._s. startup code partially sits in s._s. one

This patch cleans most of the above leaving only the startup
_cdc_gen_id on board.

tests: unit(dev)
refs: #2795

"

* 'br-storage-service-vs-cdc-2' of https://github.com/xemul/scylla:
  api: Use local sharded<cdc::generation_service> reference
  main: Push cdc::generation_service via API
  storage_service: Ditch for_testing boolean
  cdc: Replace db::config with generation_service::config
  cdc: Drop db::config from description_generator
  cdc: Remove all arguments from maybe_rewrite_streams_descriptions
  cdc: Move maybe_rewrite_streams_descriptions into after_join
  cdc: Squash two methods into one
  cdc: Turn make_new_cdc_generation a service method
  cdc: Remove ring-delay arg from make_new_cdc_generation
  cdc: Keep database reference on generation_service
2021-10-04 14:56:05 +03:00
Avi Kivity
1bac93e075 Merge "simplifications and layer violation fix for compaction manager" from Raphael
"This series removes layer violation in compaction, and also
simplifies compaction manager and how it interacts with compaction
procedure."

* 'compaction_manager_layer_violation_fix/v4' of github.com:raphaelsc/scylla:
  compaction: split compaction info and data for control
  compaction_manager: use task when stopping a given compaction type
  compaction: remove start_size and end_size from compaction_info
  compaction_manager: introduce helpers for task
  compaction_manager: introduce explicit ctor for task
  compaction: kill sstables field in compaction_info
  compaction: kill table pointer in compaction_info
  compaction: simplify procedure to stop ongoing compactions
  compaction: move management of compaction_info to compaction_manager
  compaction: move output run id from compaction_info into task
2021-10-04 13:09:31 +03:00