From 27fe34cd414cb73eb31591c5f98eaff833019147 Mon Sep 17 00:00:00 2001 From: Igor Gaponenko Date: Mon, 30 Sep 2024 23:00:11 -0700 Subject: [PATCH] Added the Ingest Workflow Developer's Guide --- doc/_static/ingest-transaction-fsm.png | Bin 0 -> 72474 bytes doc/_static/ingest-transaction-fsm.pptx | Bin 0 -> 46083 bytes doc/_static/ingest-transactions-aborted.png | Bin 0 -> 53776 bytes doc/_static/ingest-transactions-aborted.pptx | Bin 0 -> 42974 bytes doc/_static/ingest-transactions-failed.png | Bin 0 -> 77490 bytes doc/_static/ingest-transactions-failed.pptx | Bin 0 -> 45976 bytes doc/_static/ingest-transactions-resolved.png | Bin 0 -> 65354 bytes doc/_static/ingest-transactions-resolved.pptx | Bin 0 -> 46021 bytes doc/admin/data-table-indexes.rst | 608 ++++++++++++ doc/admin/index.rst | 6 +- doc/admin/row-counters.rst | 176 ++++ doc/conf.py | 1 + doc/ingest/api/advanced/index.rst | 131 +++ doc/ingest/api/appendix/index.rst | 6 + doc/ingest/api/concepts/contributions.rst | 67 ++ doc/ingest/api/concepts/families.rst | 11 + doc/ingest/api/concepts/index.rst | 35 + doc/ingest/api/concepts/overview.rst | 155 +++ doc/ingest/api/concepts/publishing.rst | 12 + doc/ingest/api/concepts/table-types.rst | 34 + doc/ingest/api/concepts/transactions.rst | 257 +++++ doc/ingest/api/index.rst | 32 +- doc/ingest/api/introduction.rst | 91 ++ doc/ingest/api/post-ingest/index.rst | 11 + doc/ingest/api/reference/index.rst | 12 + .../api/reference/rest/controller/config.rst | 426 +++++++++ .../rest/controller/db-table-management.rst | 559 +++++++++++ .../rest/controller/director-index.rst | 139 +++ .../api/reference/rest/controller/index.rst | 14 + .../api/reference/rest/controller/info.rst | 137 +++ .../rest/controller/row-counters.rst | 193 ++++ .../rest/controller/table-location.rst | 243 +++++ .../rest/controller/trans-management.rst | 794 +++++++++++++++ doc/ingest/api/reference/rest/general.rst | 314 ++++++ doc/ingest/api/reference/rest/index.rst | 10 + .../api/reference/rest/worker/index.rst | 900 ++++++++++++++++++ doc/ingest/api/reference/tools.rst | 17 + doc/ingest/api/simple/index.rst | 6 + doc/ingest/data/index.rst | 291 ++++++ doc/ingest/index.rst | 48 +- doc/ingest/intro.rst | 37 + doc/user/http-frontend-ingest.rst | 41 +- doc/user/http-frontend-query.rst | 21 +- 43 files changed, 5717 insertions(+), 118 deletions(-) create mode 100755 doc/_static/ingest-transaction-fsm.png create mode 100644 doc/_static/ingest-transaction-fsm.pptx create mode 100755 doc/_static/ingest-transactions-aborted.png create mode 100644 doc/_static/ingest-transactions-aborted.pptx create mode 100755 doc/_static/ingest-transactions-failed.png create mode 100644 doc/_static/ingest-transactions-failed.pptx create mode 100755 doc/_static/ingest-transactions-resolved.png create mode 100644 doc/_static/ingest-transactions-resolved.pptx create mode 100644 doc/admin/data-table-indexes.rst create mode 100644 doc/admin/row-counters.rst create mode 100644 doc/ingest/api/advanced/index.rst create mode 100644 doc/ingest/api/appendix/index.rst create mode 100644 doc/ingest/api/concepts/contributions.rst create mode 100644 doc/ingest/api/concepts/families.rst create mode 100644 doc/ingest/api/concepts/index.rst create mode 100644 doc/ingest/api/concepts/overview.rst create mode 100644 doc/ingest/api/concepts/publishing.rst create mode 100644 doc/ingest/api/concepts/table-types.rst create mode 100644 doc/ingest/api/concepts/transactions.rst create mode 100644 doc/ingest/api/introduction.rst create mode 100644 doc/ingest/api/post-ingest/index.rst create mode 100644 doc/ingest/api/reference/index.rst create mode 100644 doc/ingest/api/reference/rest/controller/config.rst create mode 100644 doc/ingest/api/reference/rest/controller/db-table-management.rst create mode 100644 doc/ingest/api/reference/rest/controller/director-index.rst create mode 100644 doc/ingest/api/reference/rest/controller/index.rst create mode 100644 doc/ingest/api/reference/rest/controller/info.rst create mode 100644 doc/ingest/api/reference/rest/controller/row-counters.rst create mode 100644 doc/ingest/api/reference/rest/controller/table-location.rst create mode 100644 doc/ingest/api/reference/rest/controller/trans-management.rst create mode 100644 doc/ingest/api/reference/rest/general.rst create mode 100644 doc/ingest/api/reference/rest/index.rst create mode 100644 doc/ingest/api/reference/rest/worker/index.rst create mode 100644 doc/ingest/api/reference/tools.rst create mode 100644 doc/ingest/api/simple/index.rst create mode 100644 doc/ingest/data/index.rst create mode 100644 doc/ingest/intro.rst diff --git a/doc/_static/ingest-transaction-fsm.png b/doc/_static/ingest-transaction-fsm.png new file mode 100755 index 0000000000000000000000000000000000000000..29d4a076b52c6b715be617ccc19f64a8d0009e15 GIT binary patch literal 72474 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 literal 0 HcmV?d00001 diff --git a/doc/_static/ingest-transaction-fsm.pptx b/doc/_static/ingest-transaction-fsm.pptx new file mode 100644 index 0000000000000000000000000000000000000000..7f2c2bbf0c133df23e3843ca57397892254b1351 GIT binary patch literal 46083 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
    n_xTU1m-GvgDfAw;)E`p32hoeBI;{*~xOIwN3ke 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�T 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 literal 0 HcmV?d00001 diff --git a/doc/_static/ingest-transactions-failed.png b/doc/_static/ingest-transactions-failed.png new file mode 100755 index 0000000000000000000000000000000000000000..d2a0d60d5fc9dcdf2013e247432f30a0c52a68c2 GIT binary patch literal 77490 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 literal 0 HcmV?d00001 diff --git a/doc/_static/ingest-transactions-resolved.pptx b/doc/_static/ingest-transactions-resolved.pptx new file mode 100644 index 0000000000000000000000000000000000000000..932f344e0a7fe2759f915fc6ef22a939a43315bf GIT binary patch literal 46021 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

    y$ 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 F^* ... + CREATE ... INDEX ON ... + DROP INDEX ON
    ... + +However, unlike the single table operations listed above, the services allow managing groups of related tables distributed +across Qserv worker nodes. Hence, each request for any service refers to a single such group. In particular: + +- if a request refers to the *regular* (fully replicated) table then all instances of the table will be affected by the request. +- otherwise (in the case of the *partitioned* tables) each replica of every chunk of the table will be included in an operation. + Note that the index management services differentiate between the *chunk* tables themselves and the corresponding *full overlap* + tables. When submitting a request, a user will have to choose which of those tables will be included in the operation. + +The latter would also be reflected in the result and error reports made by the services. The JSON objects returned by +the services would return the names of the *final* tables affected by the operations, not the names of the corresponding +*base* name of a table specified in service requests. This is done to facilitate investigating problems with Qserv should +they occur. See more on the *base* and *final* table names in the section: + +- :ref:`ingest-general-base-table-names` (REST) + +Things to consider before creating indexes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The recommendations mentioned in this section are not complete. Please, get yourself familiarized with +the MySQL documentation on indexes before attempting the operation. Read the following instructions on +the index creation command: + +- https://dev.mysql.com/doc/refman/8.4/en/create-index.html + +Always keep in mind that there is the MySQL (or alike) machinery behind Qserv and that the data tables +in Qserv are presently based on the MyISAM storage engine: + +- https://dev.mysql.com/doc/refman/8.4/en/myisam-storage-engine.html + +These are a few points to consider. + +General: + +- Indexes are created on tables, and not on views. +- Indexes are created in the scope of the table, and not databases. +- In the case of the *partitioned* tables, the *chunk* and *full* overlap may not need to have the same set of indexes. + In some cases, it may not be even possible, for instance, due to different ``UNIQUE`` constraints requirements. +- Please, provide a reasonable comment for an index, even though, comments aren't mandatory. Your comments could be useful + for bookkeeping purposes to know why and what the index was created for. +- Be aware that indexes take additional space on the Qserv workers' filesystems where the database tables are residing. + Potentially, if too many indexes were created, MySQL may run out of disk space and stop working. The rule of thumb for + estimating the amount of space to be taken by an index is based on the sizes of columns mentioned in an index + specification (explained in the next section) multiplied by the total number of rows in a table (on which the index + is being created). There are other factors here, such as the type of a table (regular or partitioned) as well as + the number of replicas for the partitioned tables. The index management service which is used for creating indexes + will also make the best attempt to prevent creating indexes if it will detect that the amount of available disk space + is falling too low. In this case, the service will refuse to create an index and an error will be reported back. + +When choosing a name for an index: + +- The name should be unique (don't confuse this with the UNIQUE keyword used in the index specifications) in the scope + of the table. It means it should not be already taken by some other index. Always check which indexes already exist + in a table before creating a new one. +- Generally, the name must adhere to the MySQL requirements for identifiers as explained + in: + + - https://dev.mysql.com/doc/refman/8.4/en/identifier-qualifiers.html + +- Keep in mind that names of identifiers (including indexes) in Qserv are case-insensitive. This is not the general + requirement in MySQL, where the case sensitivity of identifiers is configurable one way or another. It's because + of a design decision the original Qserv developers made to configure the underlying MySQL machinery. +- To make things simple, restrain from using special characters (all but the underscore one ``_``). +- The length of the name should not exceed 64 characters: + + - https://dev.mysql.com/doc/refman/8.4/en/identifier-length.html + +Error reporting +^^^^^^^^^^^^^^^^ + +All services mentioned in the document are the Replication system's services, and they adhere to the same error reporting +schema. The schema is explained in the document: + +- :ref:`ingest-general-error-reporting` (REST) + +In addition, the index managemnt services may return the service-specific error conditions in the ``error_ext`` attribute: + +.. code-block: + + "error_ext" : { + "job_state" : , + "workers" : { + : { +
    : { + "request_status" : , + "request_error" : + }, + ... + }, + ... + } + } + +Where: + +``job_state`` : *string* + The completion status (state) of the corresponding C++ job classes: + + - ``lsst::qserv::replica::SqlGetIndexesJob`` + - ``lsst::qserv::replica::SqlCreateIndexesJob`` + - ``lsst::qserv::replica::SqlDropIndexesJob`` + + The status will be serialized into a string. The explanation of the possible values could be found in + the following C++ header: + + - https://github.com/lsst/qserv/blob/master/src/replica/jobs/Job.h + + Look for this enum type: + + .. code-block:: + + enum ExtendedState { + NONE, ///< No extended state exists at this time. + SUCCESS, ///< The job has been fully implemented. + CONFIG_ERROR, ///< Problems with job configuration found. + FAILED, ///< The job has failed. + ... + } + + Also look for worker/table-specific errors in a JSON object explained below. + +``workers`` : *object* + The JSON object which has unique identifiers of workers (attribute ``worker``) as the keys, where the corresponding + value for the worker is another JSON object which has names of worker-side tables as the next-level keys for + descriptions of problems with managing indexes for the corresponding tables. + + .. note: + + Only the problematic tables (if any) would be mentioned in the report. If no problems were seen during + the index management operations then a collection of workers and tables will be empty. + +``request_status`` : *string* + The completion status (state) of the index creation C++ request classes: + + - ``SqlGetIndexesRequest`` + - ``SqlCreateIndexesRequest`` + - ``SqlDropIndexesRequest`` + + The status will be serialized into a string. More information on possible values could be found in the + following C++ header: + + - https://github.com/lsst/qserv/blob/main/src/replica/requests/Request.h + + Look for this enum type: + + .. code-block:: + + enum ExtendedState { + NONE, /// No extended state exists at this time + SUCCESS, /// The request has been fully implemented + CLIENT_ERROR, /// The request could not be implemented due to + /// an unrecoverable client-side error. + SERVER_BAD, /// Server reports that the request can not be implemented + /// due to incorrect parameters, etc. + SERVER_ERROR, /// The request could not be implemented due to + /// an unrecoverable server-side error. + ... + }; + +``request_error`` : *string* + This string provides an expanded explanation of an error reported by the Replication system's worker (in case if the + request failed on the worker's side and is reported to the service). + +.. note:: + + **Reporting partial successes or failures** + + Since the index management requests may (will) involve multiple tables, the corresponding operations may be potentially + partially successful and partially not successful. All failures for specific indexes which couldn't be managed (created, + queried, or deleted) would be reported as explained in the previous section. For example, that would be a case if a request + was made to drop a known to-exist index, and if no such index existed for some final tables. There may be various reasons + why this might happen. An explanation of the reasons is beyond a scope of this document. The best way a user should treat + this situation is to expect that the service would do the "best effort" of removing the index. It's also allowed to run + the index removal request multiple times. This won't make any harm. All subsequent requests will report failures for all + final tables in the specified group of tables. + +.. _admin-data-table-index-create: + +Creating +-------- + +To create a new index, a user must submit a request to the service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/replication/sql/index`` + +Where the request object has the following schema: + +.. code-block:: + + { "database" : , + "table" : , + "overlap" : , + "index" : , + "spec" : , + "comment" : , + "columns" : [ + { "column" : , + "length " :, + "ascending" : + }, + .. + ], + "auth_key" : + } + +Where: + +``database`` : *string* + The required name of the database where the table resides. + +``table`` : *string* + The required *base* name of the table where the index will be created. + +``overlap`` : *number* := ``0`` + The optional *overlap* flagg indicating a sub-type of the *chunk* table. The value should be one of the following: + + - ``1`` : *full overlap* + - ``0`` : *chunk* + +``index`` : *string* + The required name of the index to be created. + +``spec`` : *string* + The required index specification. The specification should adhere to the MySQL requirements for the index creation command: + + - https://dev.mysql.com/doc/refman/8.4/en/create-index.html + + Where a value of the parameter should be one of the following keywords: ``DEFAULT``, ``UNIQUE``, ``FULLTEXT``, or ``SPATIAL``. + All but the first one (``DEFAULT``) are mentioned in the MySQL documentation. The keywords map to the indfex + creation command: + + .. code-block:: sql + + CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name ... + + The REST service expects ``DEFAULT`` in those cases when none of the other three specifications are provided. + Any other value or a lack of ant will be considered as an error. + +``comment`` : *string* := ``""`` + The optional comment for the index. The value will be passed via the ``COMMENT`` parameter of the MySQL index + creation command: + + .. code-block:: sql + + CREATE ... INDEX ... COMMENT 'string' ... + +``columns`` : *array* + The required non-empty array of JSON objects keys mentioned in the key_part of the index creation statements: + + .. code-block:: sql + + CREATE ... INDEX index_name ON tbl_name (key_part,...) ... + + .. note:: + + The current implementation of the service doesn't support the extended-expression syntax of key_part introduced + in MySQL version 8. + + These are the mandatory attributes of each key-specific object: + + ``column`` : *string* + The required name of a column. + ``length`` : *number* + The required length of a substring used for the index. It only has a meaning for columns of + types: ``TEXT``, ``CHAR(N)``, ``VARCHAR(N)``, ``BLOB`` , etc. And it must be always 0 for other column + types (numeric, etc.). Otherwise, an index creation request will fail. + + ``ascending`` : *number* + The required sorting order of the column in the index. It translates into ``ASC`` or ``DESC`` optiona + in the key definition in ``key_part``. A value of ``0`` will be interpreted as ``DESC``. Any other positive number + will be imterpreted as to ``ASC``. + +``auth_key`` : *string* + The required zauthorization key. + +Here is an example of the index creation request. Let's supposed we have the *regular* (fully replicated) +table that has the following schema: + +.. code-block:: sql + + CREATE TABLE `sdss_stripe82_01`.`Science_Ccd_Exposure_NoFile` ( + `scienceCcdExposureId` BIGINT(20) NOT NULL, + `run` INT(11) NOT NULL, + `filterId` TINYINT(4) NOT NULL, + `camcol` TINYINT(4) NOT NULL, + `field` INT(11) NOT NULL, + `path` VARCHAR(255) NOT NULL + ); + +And, suppose we are going to create the ``PRIMARY`` key index based on the very first column ``scienceCcdExposureId``. +In this case the request object will look like this: + +.. code-block:: json + + { "database" : "sdss_stripe82_01", + "table" : "Science_Ccd_Exposure_NoFile", + "index" : "PRIMARY", + "spec" : "UNIQUE", + "comment" : "This is the primary key index", + "columns" : [ + { "column" : "scienceCcdExposureId", + "length" : 0, + "ascending" : 1 + } + ], + "auth_key" : "" + } + +The request deliberately misses the optional ``overlap`` attribute since it won't apply to the regular tables. + +Here is how the request could be submitted to the service using ``curl``: + +.. code-block:: bash + + curl 'http://localhost:25081/replication/sql/index' \ + -X POST -H "Content-Type: application/json" \ + -d '{"database":"sdss_stripe82_01","table":"Science_Ccd_Exposure_NoFile", + "index":"PRIMARY","spec":"UNIQUE","comment":"This is the primary key index", + "columns":[{"column":"scienceCcdExposureId","length":0,"ascending":1}], + "auth_key":""}' + +.. _admin-data-table-index-delete: + +Deleting +-------- + +To delete an existing index, a user must submit a request to the service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``DELETE`` + - ``/replication/sql/index`` + +Where the request object has the following schema: + +.. code-block:: + + { "database" : , + "table" : , + "overlap" : , + "index" : , + "auth_key" : + } + +Where: + +``database`` : *string* + The required name of the database where the table resides. + +``table`` : *string* + The required *base* name of the table where the index will be created. + +``overlap`` : *number* := ``0`` + The optional *overlap* flagg indicating a sub-type of the *chunk* table. The value should be one of the following: + + - ``1`` : *full overlap* + - ``0`` : *chunk* + +``index`` : *string* + The required name of the index to be dropped. + +Here is an example of the index deletion request. It's based on the same table that was mentioned in the previous section. +The request object will look like this: + +.. code-block:: json + + { "database" : "sdss_stripe82_01", + "table" : "Science_Ccd_Exposure_NoFile", + "index" : "PRIMARY", + "auth_key" : "" + } + +Here is how the request could be submitted to the service using ``curl``: + +.. code-block:: bash + + curl 'http://localhost:25081/replication/sql/index' \ + -X DELETE -H "Content-Type: application/json" \ + -d '{"database":"sdss_stripe82_01","table":"Science_Ccd_Exposure_NoFile", + "index":"PRIMARY", + "auth_key":""}' + +.. _admin-data-table-index-inspect: + +Inspecting +---------- + +To inspect the existing indexes, a user must submit a request to the service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/replication/sql/index/:database/:table[?overlap={0|1}]`` + +Where the service path has the following parameters: + +``database`` : *string* + The name of a database affected by the operation. + +``table`` : *string* + The name of the table for which the indexes are required to be collected. + +The optional query parameyter is + +``overlap`` : *number* := ``0`` + The optional *overlap* flagg indicating a sub-type of the *chunk* table. The value should be one of the following: + + - ``1`` : *full overlap* + - ``0`` : *chunk* + +In case of successful completion of the request the JSON object returned by the service will have the following schema: + +.. code-block:: + + { "status": { + "database" : , + "table" : , + "overlap" : , + "indexes" : [ + { "name" : , + "unique" : , + "type" : , + "comment" : , + "status" : , + "num_replicas_total" : , + "num_replicas" : , + "columns" : [ + { "name" : , + "seq" : , + "sub_part" : , + "collation" : + }, + ... + ] + }, + ... + ] + } + } + +Where: + +``name`` : *string* + The name of the index (the key). + +``unique`` : *number* + The numeric flag indicates of the index's keys are unique, where a value of ``0`` means they're unique. Any other + value would mean the opposite. + +``type`` : *string* + The type of index, such as ``BTREE``, ``SPATIAL``, ``PRIMARY``, ``FULLTEXT``, etc. + +``comment`` : *string* + An optional explanation for the index passed to the index creation statement: + + .. code-block:: sql + + CREATE ... INDEX ... COMMENT 'string' ... + +``status`` : *string* + The status of the index. This parameter considers the aggregate status of the index across all replicas of the table. + Possible values here are: + + - ``COMPLETE`` : the same index (same type, columns) is present in all replicas of the table (or its chunks in the case + of the partitioned table) + - ``INCOMPLETE`` : the same index is present in a subset of replicas of the table, where all indexes have the same + definition. + - ``INCONSISTENT`` : instances of the index that have the same name have different definitions in some replicas + + .. warning:: + + The result object reported by the service will not provide any further details on the last status ``INCONSISTENT`` + apart from indicating the inconsistency. It will be up to the data administrator to investigate which replicas have + unexpected index definitions. + +``num_replicas_total`` : *number* + The total number of replicas that exist for the table. This is the target number of replicas where the index is expected + to be present. + +``num_replicas`` : *number* + The number of replicas where the index was found to be present. If this number is not the same as the one reported + in the attribute + ``num_replicas_total`` then the index will be ``INCOMPLETE``. + +``columns`` : *array* + The collection of columns that were included in the index definition. Each entry of the collection has: + + ``name`` : *string* + The name of the column + ``seq`` : *number* + The 1-based position of the column in the index. + ``sub_part`` : *number* + The index prefix. That is, the number of indexed characters if the column is only partly indexed 0 if + the entire column is indexed. + ``collation`` : *string* + How the column is sorted in the index. This can have values ``ASC``, ``DESC``, or ``NOT_SORTED``. + +The following request will report indexes from the fully-replicated table ``ivoa.ObsCore``: + +.. code-block:: bash + + curl http://localhost:25081/replication/sql/index/ivoa/ObsCore -X GET + +The (truncated and formatted for readability) result of an operation performed in a Qserv deployment with 6-workers may +look like this: + +.. code-block:: json + + { "status" : { + "database" : "ivoa" + "indexes" : [ + { "name" : "idx_dataproduct_subtype", + "type" : "BTREE", + "unique" : 0, + "status" : "COMPLETE", + "num_replicas" : 6, + "num_replicas_total" : 6, + "comment" : "The regular index on the column dataproduct_subtype", + "columns" : [ + { "collation" : "ASC", + "name" : "dataproduct_subtype", + "seq" : 1, + "sub_part" : 0 + } + ] + }, + { "name" : "idx_s_region_bounds", + "type" : "SPATIAL", + "unique" : 0, + "status" : "COMPLETE", + "num_replicas" : 6, + "num_replicas_total" : 6, + "comment" : "The spatial index on the geometric region s_region_bounds", + "columns" : [ + { "collation" : "ASC", + "name" : "s_region_bounds", + "seq" : 1, + "sub_part" : 32 + } + ] + }, + { "name" : "idx_lsst_tract_patch", + "type" : "BTREE", + "unique" : 0, + "status" : "COMPLETE", + "num_replicas" : 6, + "num_replicas_total" : 6, + "comment" : "The composite index on the columns lsst_tract and lsst_patch", + "columns" : [ + { "collation" : "ASC", + "name" : "lsst_tract", + "seq" : 1, + "sub_part" : 0 + }, + { "collation" : "ASC", + "name" : "lsst_patch", + "seq" : 2, + "sub_part" : 0 + } + ] + }, + } + +.. note:: + + - The second index ``idx_s_region_bounds`` is spatial. It's based on the binary column of which only + the first 32 bytes are indexed. + + - The third index ``idx_lsst_tract_patch`` is defined over two columns. diff --git a/doc/admin/index.rst b/doc/admin/index.rst index 89a01074d..c47817e72 100644 --- a/doc/admin/index.rst +++ b/doc/admin/index.rst @@ -1,7 +1,5 @@ -.. warning:: - **Information in this guide is known to be outdated.** A documentation sprint is underway which will - include updates and revisions to this guide. +.. _admin: ##################### Administrator's Guide @@ -11,3 +9,5 @@ Administrator's Guide :maxdepth: 4 k8s + row-counters + data-table-indexes diff --git a/doc/admin/row-counters.rst b/doc/admin/row-counters.rst new file mode 100644 index 000000000..a1d75f7bb --- /dev/null +++ b/doc/admin/row-counters.rst @@ -0,0 +1,176 @@ + +.. _admin-row-counters: + +========================= +Row counters optimization +========================= + +.. _admin-row-counters-intro: + +Introduction +------------ + +Shortly after the first public instances of Qserv were made available to the users, it was observed that many users +were launching the following query: + +.. code-block:: sql + + SELECT COUNT(*) FROM .
    + +Normally, Qserv would process the query by broadcasting the query to all workers to count rows at each chunk +table and aggregate results into a single number at Czar. This is basically the very same mechanism that is found +behind the *shared scan* (or just *scan*) queries. The performnce of the *scan* queries is known to vary depending on +the following factors: + +- the number of chunks in the table of interest +- the number of workers +- and the presence of other competing queries (especially the slow ones) + +In the best case scenario such scan would take seconds, in the worst one - many minutes or even hours. +This could quickly cause (and has caused) frustration among users since this query looks like (and in reality is) +the very trivial non-scan query. + +To address this situation, Qserv has a built-in optimization that is targeting exactly this class of queries. +Here is how it works. For each data table Qserv Czar would have an optional metadata table to store the number +of rows for each chunk. The table is populated and managed by the Qserv Replication system. + +Note that this optimization is presently an option. And these are the reasons: + +- Counter collection requires scanning all chunk tables, which would take time. Doing this during + the catalog *publishing* time would prolong the ingest time and increase the chances of instabilities + for the workflows (in general, the longer some operation is going - the higher the probability of runing into + the infrastructure-related faulures). +- The counters are not needed for the purposes of the data ingest *per se*. These are just optimizations for the queries. +- Building the counters before the ingested data have been Q&A-ed may not be a good idea. +- The counters may need to be rebuilt if the data have been changed (after fix ups to the ingested catalogs) + +The rest of this section along with the formal description of the corresponding REST services explains how to build +and manage the counters. + +.. note:: + + In the future, the per-chunk counters will be used for optimizing another class of the unconditional queries + presented below: + + .. code-block:: sql + + SELECT * FROM .
    LIMIT + SELECT `col`,`col2` FROM .
    LIMIT + + For these "indiscriminate" data probes Qserv would dispatch chunk queries to a subset of random chunks that have enough + rows to satisfy the requirements specified in ``LIMIT ``. + + +.. _admin-row-counters-build: + +Building and deploying +---------------------- + +.. warning:: + + Depending on a scale of a catalog (data size of the affected table), it may take a while before this operation + will be complete. + +.. note:: + + Please, be advised that the very same operation could be performed at the catalog publishing time as explained in: + + - :ref:`ingest-db-table-management-publish-db` (REST) + + The choice of doing this at the catalog publishing time, or doing this as a separate operation explained in this document + is left to the Qserv administrators or developers of the ingest workflows. The general recommendation is to make it + a separate stage of the ingest workflow. In this case, the overall transition time of a catalog to the final published + state would be faster. In the end, the row counters optimization is optional, and it doesn't affect the overall + functionality of Qserv or query results seen by users. + +To build and deploy the counters one would need to use the following REST service: + +- :ref:`ingest-row-counters-deploy` (REST) + +The service needs to be invoked for every table of the ingested catalog. This is the typical example of using this service +that would work regardless if the very same operation was already done before: + +.. code-block:: bash + + curl http://localhost:25080/ingest/table-stats \ + -X POST -H "Content-Type: application/json" \ + -d '{"database":"test101", + "table":"Object", + "overlap_selector":"CHUNK_AND_OVERLAP", + "force_rescan":1, + "row_counters_state_update_policy":"ENABLED", + "row_counters_deploy_at_qserv":1, + "auth_key":""}' + +This would work for tables of any type: *director*, *dependent*, *RefMatch*, or *regular* (fully replicated). If the counters +already existed in the Replication system's database, they would still be rescanned and redeployed in there. + +It may be a good idea to compare the performance of Qserv for executing the above-mentioned queries before and after running +this operation. Normally, if the table statistics are available at Qserv, it should take a small fraction of +a second (about 10 milliseconds) to see the result on the lightly loaded Qserv. + +.. _admin-row-counters-delete: + +Deleting +-------- + +Sometimes, if there is doubt that the row counters were incorrectly scanned, or when Q&A-in the ingested catalog, +a data administrator may want to remove the counters and let Qserv do the full scan of the table instead. This can be done +by using the following REST service: + + +- :ref:`ingest-row-counters-delete` (REST) + +Likewise, the previously explained service, this one should also be invoked for each table needing attention. Here is +an example: + +.. code-block:: bash + + curl http://localhost:25080/ingest/table-stats/test101/Object \ + -X DELETE -H "Content-Type: application/json" \ + -d '{"overlap_selector":"CHUNK_AND_OVERLAP","qserv_only":1,"auth_key":""}' + +Note that with a combination of the parameters shown above, the statistics will be removed from Qserv only. +So, the system would not need to rescan the tables again should the statistics need to be rebuilt. The counters could be simply +redeployed later at Qserv. To remove the counters from the Replication system's persistent state as well +the request should have ``qserv_only=0``. + +An alternative technique explained in the next section is to tell Qserv not to use the counters for optimizing queries. + + +.. _admin-row-counters-disable: + +Disabling the optimization at run-time +--------------------------------------- + +.. warning:: + + This is a global setting that affects all users of Qserv. All new quries will be ru w/o the optimization. + It should be used with caution. Normally, it is meant to be used by the Qserv data administrator to investigate + suspected issues with Qserv or the catalogs it serves. + +To complement the previously explained methods for scanning, deploying, or deleting row counters for query optimization, +Qserv also supports the run-time switch. The switch is turned on or off by the following statement to be submitted via +the front-ends of Qserv: + +.. code-block:: sql + + SET GLOBAL QSERV_ROW_COUNTER_OPTIMIZATION = 1 + SET GLOBAL QSERV_ROW_COUNTER_OPTIMIZATION = 0 + + +The default behavior of Qserv when the variable is not set is to enable the optimization for tables where the counters +are available. + +.. _admin-row-counters-retrieve: + +Inspecting +---------- + +It's also possible to retrieve the counters from the Replication system's state using the following REST service: + +- :ref:`ingest-row-counters-inspect` (REST) + +The information obtained in this way could be used for various purposes, such as investigating suspected issues with +the counters, monitoring data placement in the chunks, or making visual representations of the chunk density maps. +See the description of the REST service for further details on this subject. diff --git a/doc/conf.py b/doc/conf.py index 1c35a00ea..e481eb922 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -42,6 +42,7 @@ r"^https://rubinobs.atlassian.net/wiki/", r"^https://rubinobs.atlassian.net/browse/", r"^https://www.slac.stanford.edu/", + r".*/_images/", ] html_additional_pages = { diff --git a/doc/ingest/api/advanced/index.rst b/doc/ingest/api/advanced/index.rst new file mode 100644 index 000000000..93ce56128 --- /dev/null +++ b/doc/ingest/api/advanced/index.rst @@ -0,0 +1,131 @@ + +.. _ingest-api-advanced: + +================== +Advanced Scenarios +================== + +.. _ingest-api-advanced-multiple-transactions: + +Multiple transactions +---------------------- + +.. _ingest-api-advanced-unpublishing-databases: + +Ingesting tables into the published catalogs +-------------------------------------------- + +.. _ingest-api-advanced-transaction-abort: + +Aborting transactions +---------------------- + +When should a transaction be aborted? +What happens when a transaction is aborted? +How long does it take to abort a transaction? +How to abort a transaction? +What to do if a transaction cannot be aborted? +What happens if a transaction is aborted while contributions are being processed? +Will the transaction be aborted if the Master Replication Controller is restarted? +Is it possible to have unfinished transactions in the system when publishing a catalog? + +.. _ingest-api-advanced-contribution-requests: + +Options for making contribution requests +---------------------------------------- + +.. _ingest-api-advanced-global-config: + +Global configuration options +---------------------------- + +Certain configuration parameters of Qserv and the Replication/Ingest system may affect the ingest activities for +all databases. This section explains which parameters are available and how they can could be retrieved via the REST API. + +The number of workers +^^^^^^^^^^^^^^^^^^^^^ + +The first parameter is the number of workers which are available for processing the contributions. The number +can be obtained using the following REST service: + +- :ref:`ingest-config-global-workers` + +The workflow needs to analyze a section ``config.workers`` to select workers in the following state (both apply): + +- ``is-enabled=1`` +- ``is-read-only=0`` + +There are a few possibilities how the workflow could use this information. For example, the workflow +could start a separate transaction (or a set of transactions) per worker. + +The second group of parameters found in the section ``config.general.worker`` is related to resources which +are available to the worker ingest services for processing contributions. This is how the workflow could use +some of the parameters: + +- ``num-loader-processing-threads``: + + The parameter affects a flow of ingest requests made via the proprietary binary protocol using the command-line + tool :ref:`ingest-tools-qserv-replica-file`. To achieve the maximum throughput of the ingest the workflows + should aim at having each participated worker loaded with as many parallel requests as there are threads + reported by this parameter. + + .. warning:: + + Exceeding the number of threads will result on clients waiting for connections to be established. + In some cases this may lead to the performance degradation if the network connection + is unstable. + +- ``num-http-loader-processing-threads``: + + The parameter affects a flow of ingest requests made via the HTTP-based ingest service. The service is used + for processing *synchronous* contribution requests and for submitting the *asynchronous* requests to the service. + + The workflow may use a value of the parameter differently, depenidng on a type of the contribution request. + Requests which are *synchronous* should be submitted to the service in a way that the number of such requests + per worker was close to the number of threads reported by this parameter. In this case the workflow should + expect the maximum throughput of the ingest. The *asynchronous* requests aren't affected by the parameter. + +- ``num-async-loader-processing-threads``: + + The parameter represents the number of ingest request processing threads in a thread pool that processes + the *asynchronous* contribution requests. The workflow should aim at having the number of *asynchronous* + requests submitted to the service close to the number of threads reported by this parameter. The workflow should + monitor the satus of the *asynchronous* requestsbeing processed by each worker and submit new requests + to the service when the number of the requests being processed is less than the number of threads. + + .. note:: + + An alternative approach is to submit all *asynchronous* requests to the service at once. The service + will take care of processing the requests in the same order they were submitted. This approach may not + work well where a specific order of the requests is important, or if all input data is not available + at the time of the submission. + +- ``ingest-charset-name``: + + The name of a character set for parsing the payload of the contributions. The workflow may override the default + value of the parameter if the payload of the contributions is encoded in a different character set. See an + attrubute ``charset_name`` in: + + - :ref:`ingest-worker-contrib-by-ref` (REST) + - :ref:`ingest-worker-contrib-by-val` (REST) + +- ``ingest-num-retries``, ``ingest-max-retries``: + + These parameters are related to the number of the automatic retries of the failed *asynchronous* requests + specific in the parameter ``num_retries`` of the contribution request. The workflow may adjust the number + of such retries if needed. A good example is when the workflow knows that a connection to the data source + (a Web server or the object store) is unstable, or if the server might be overloaded. The workflow may increase + the number of retries to ensure that the data is ingested successfully. + + .. note:: + + The parameter ``ingest-max-retries`` is a hard limit for the number of retries regardless of what's + specified in the request's attribute ``num_retries``. + +- ``loader-max-warnings``: + + This parameter sets the default number for the number of warnings that the worker ingest service can + capture from MySQL after attempting to ingest a contribution. The workflow may adjust the parameter + for individual contributions by setting the desired limit in the request's attribute ``max_warnings``. + The main purpose for setting the limit higher than the default value is to debug problem with the + data of the contributions. diff --git a/doc/ingest/api/appendix/index.rst b/doc/ingest/api/appendix/index.rst new file mode 100644 index 000000000..f7bf53fd6 --- /dev/null +++ b/doc/ingest/api/appendix/index.rst @@ -0,0 +1,6 @@ +.. _ingest-api-appendix: + +======== +APPENDIX +======== + diff --git a/doc/ingest/api/concepts/contributions.rst b/doc/ingest/api/concepts/contributions.rst new file mode 100644 index 000000000..f92e6f27e --- /dev/null +++ b/doc/ingest/api/concepts/contributions.rst @@ -0,0 +1,67 @@ + +.. _ingest-api-concepts-contributions: + +Table contributions +=================== + +The API defines the *contribution* as a set of rows that is being ingested into a table via +a separate request. The contribution ingest requests are considered as atomic operations with +a few important caveats: + +- The contributions are not committed to the table until the transaction is committed even + if the contribution request was successful. + +- Failed contribution requests have to be evaluated by the workflow to see if the target table + was left in a consistent state. This is indicated by the ``retry-allowed`` attributed returned + in the response object. There are two scenarios for what the workflow would do based on The + value of the flag: + + - ``retry-allowed=0`` - the workflow has to roll back the transaction and make another + contribution request in a scope of a new transaction. See more on this subject in: + + - :ref:`ingest-api-advanced-transaction-abort` (ADVANCED) + - :ref:`ingest-trans-management-end` (REST) + + - ``retry-allowed=1`` - the workflow can re-try the contribution in a scope of the same + transaction using: + + - :ref:`ingest-worker-contrib-retry` (REST) + +Note that for contributions submitted by reference there is an option to configure a request +to automatically retry the failed contributions. The maximum number of such retries is controlled +by the ``num_retries`` attribute of the request: + +- :ref:`ingest-worker-contrib-by-ref` (REST) + +Contributions pushed to the service by value can not be automatically retried. The workflow +would have to decide on the retrying the failed contributions explicitly. + +Data (rows) of the contributions are typically stored in the ``CSV``-formatted files. In this +case the files would be either directly pushed to the worker Ingest server or uploaded by +the Ingest service from a location that is accessible to the worker: + +- :ref:`ingest-worker-contrib-by-val` (REST) +- :ref:`ingest-worker-contrib-by-ref` (REST) + +The first option (ingesting by value) also allows pushing data of contributions +directly from the memory of the client process (worklow) w/o the need to store the data in the files. + +Contributions have other important characteristic, such as: + +- Each contribution request is always made in a scope of a transaction. This association is + important for the data provenance and the data tagging purposes. +- The information on contributions is preserved in the persistent state of the Ingest system. +- Contributions have unique identifiers that are assigned by the Ingest system. + +The system allows to pull the information on the contributions given their identifiers: + +- :ref:`ingest-info-contrib-requests` (REST) + +An alternative option is to query the information on contributions submitted in a scope of +a transaction: + +- :ref:`ingest-trans-management-status-one` (REST) + +The schema of the contribution descriptor objects is covered by: + +- :ref:`ingest-worker-contrib-descriptor` diff --git a/doc/ingest/api/concepts/families.rst b/doc/ingest/api/concepts/families.rst new file mode 100644 index 000000000..79b63bd86 --- /dev/null +++ b/doc/ingest/api/concepts/families.rst @@ -0,0 +1,11 @@ + +.. _ingest-api-concepts-database-families: + +Database families +================= + +Explain roles and implications of the database families in Qserv. + +- to allow joins between the tables accros the same family +- required by the Ingest workflow + diff --git a/doc/ingest/api/concepts/index.rst b/doc/ingest/api/concepts/index.rst new file mode 100644 index 000000000..65bccd87c --- /dev/null +++ b/doc/ingest/api/concepts/index.rst @@ -0,0 +1,35 @@ + +.. _ingest-api-concepts: + +============= +Main concepts +============= + +.. hint:: + + This section of the document begins with the high-level overview of the Qserv ingest API. + Please read this section carefully to learn about the main concepts of the API and a sequence + of operations for ingesting catalogs into Qserv. + + After completing the overview, a reader has two options for what to read next: + + - Study the core concepts of the API in depth by visiting subsections: + + - :ref:`ingest-api-concepts-table-types` + - :ref:`ingest-api-concepts-transactions` + - :ref:`ingest-api-concepts-publishing-data` + - etc. + + - Go straight to the practical example of a simple workflow presented at: + + - :ref:`ingest-api-simple` + +.. toctree:: + :maxdepth: 4 + + overview + table-types + transactions + contributions + publishing + families diff --git a/doc/ingest/api/concepts/overview.rst b/doc/ingest/api/concepts/overview.rst new file mode 100644 index 000000000..79b2648b5 --- /dev/null +++ b/doc/ingest/api/concepts/overview.rst @@ -0,0 +1,155 @@ +.. _ingest-api-concepts-overview: + +Overview of the ingest workflow +=============================== + +In the nutshell, any ingest workflow has to accomlish quite a few tasks in order to ingest data into Qserv. +These tasks are presented in the correct order below: + +Plan the ingest +--------------- + +.. hint:: + + You may also contact Qserv experts or Qserv administrators to get help on the planning stage. + +There is a number of important questions to be answered and decisions to be made ahead of time in the following +areas before starting ingesting data into Qserv. Knowing these facts allows to organize the ingest activities in +the most efficient way. + +Creating a new database or adding tables to the existing one? + +- :ref:`ingest-api-concepts-publishing-data` (CONCEPTS) + +What are the types of tables to be ingested? + +- :ref:`ingest-api-concepts-table-types` (CONCEPTS) + +What should be the values of the partitioning parameters of the partitioned tables? + +- :ref:`ingest-api-concepts-database-families` (CONCEPTS) + +What is a scale of the planned ingest effort? + +- The amount of data (rows, bytes) to be ingested in each table +- The number of the ``CSV`` files to be ingested +- Sizes of the files +- The number of the workers that are available in Qserv +- :ref:`ingest-api-advanced-multiple-transactions` (ADVANCED) + +Where the ready to ingest data will be located? + +- Are there any data staging areas available? +- :ref:`ingest-api-advanced-contribution-requests` (ADVANCED) + +Prepare the input data +---------------------- + +Data files (table *contributions*) to be ingested into Qserv need to be in the ``CSV`` format. It's up to the workflow +to ensure that the data is in the right format and that it's sanitized to ensure the values of the columns +are compatible with the MySQL expectations. + +- :ref:`ingest-data` (DATA) + +Prepare configuration files +--------------------------- + +The configurations of the ingested entities (databases, tables, etc.) are presented to the Ingest system +in a form of thw JSON objects. + +Register or un-publish a database +--------------------------------- + +- :ref:`ingest-api-concepts-publishing-data` (CONCEPTS) +- :ref:`ingest-db-table-management-register-db` (REST) +- :ref:`ingest-db-table-management-unpublish-db` (REST) + +Register tables +--------------- + +- name +- type + + - type-specific attributes, some which are referring to other tables (names and the foreign keys) + - schema (including column names and types) + +- :ref:`ingest-db-table-management-register-table` (REST) + +Configure the Ingest service +---------------------------- + +This step is optional. And it's mostly needed to adjust the default configuration parameters of the Ingest service +to allow pulling contributions from the data staging areas, such as web servers, cloud storage, etc. Examples of +the configuration parameters are: timeouts, the number of parallel requests, SSL/TLS certificates, HTTP/HTTPS proxy +settings, etc. More information on this subject can be found in: + +- :ref:`ingest-config` (REST) + +These parameters can be adjusted in real time as needed. The changes get into effect immediately. Note that +the parameters are set on the database level. For example, the configuration parameters set for the database ``db1`` +will not affect the ingest activities for the database ``db2``. + +.. note:: + + Please, be aware that the ingest activities can be also affected by the global configuration parameters of + the Replication/Ingest system: + + - :ref:`ingest-api-advanced-global-config` (ADVANCED) + +Start transactions +------------------ + +- :ref:`ingest-api-concepts-transactions` (CONCEPTS) +- :ref:`ingest-trans-management-start` (REST) + +Figure out locations of tables and chunks +----------------------------------------- + +- Connection parameters of the workers where the table and chunk data (*contributions*) will be sent. +- Note that it's a responsibility of the workflow to contact the workers and to provide them with the data + or a reference to the data. +- The API provides the REST services for obtaining the desired information for the data products + that are being ingested. + +- :ref:`table-location` (REST) + +Send the data to the workers +---------------------------- + +Initiate the ingest activities: + +- :ref:`ingest-api-concepts-contributions` (CONCEPTS) +- :ref:`ingest-worker-contrib-by-ref` (REST) +- :ref:`ingest-worker-contrib-by-val` (REST) + +Monitor the progress of the ingest activities +---------------------------------------------- + +- The workflow can query the REST services to get the status of databases, tables, transactions + and the data contribution requests. + +Commit the transactions +----------------------- + +- :ref:`ingest-api-concepts-transactions` (CONCEPTS) +- :ref:`ingest-api-advanced-transaction-abort` (ADVANCED) +- :ref:`ingest-trans-management-end` (REST) + +Publish the database +-------------------- + +- the table would be published automatically +- when the stage is fiished the database and the tables will be visible to the users +- :ref:`ingest-api-concepts-publishing-data` (CONCEPTS) +- :ref:`ingest-db-table-management-publish-db` (REST) + +Verify the ingested data products +--------------------------------- + +- the data can be queried +- the data can be compared to the original data + +Perform the optional post-ingest data management operation on the ingested tables +--------------------------------------------------------------------------------- + +- :ref:`ingest-api-post-ingest` (API) diff --git a/doc/ingest/api/concepts/publishing.rst b/doc/ingest/api/concepts/publishing.rst new file mode 100644 index 000000000..556a8b282 --- /dev/null +++ b/doc/ingest/api/concepts/publishing.rst @@ -0,0 +1,12 @@ + +.. _ingest-api-concepts-publishing-data: + +Publishing databases and tables +=============================== + +Explain the concept of the published databases and tables in Qserv. + +Also mention: + +- :ref:`ingest-api-advanced-unpublishing-databases` +- :ref:`ingest-api-post-ingest` diff --git a/doc/ingest/api/concepts/table-types.rst b/doc/ingest/api/concepts/table-types.rst new file mode 100644 index 000000000..8333a0965 --- /dev/null +++ b/doc/ingest/api/concepts/table-types.rst @@ -0,0 +1,34 @@ +.. _ingest-api-concepts-table-types: + +Types of tables in Qserv +======================== + +.. note: + + Consider moving this section to the general documentatin on Qserv and refer to it from where + it's needed. + +Explain the tables and drow diagrams for: + +- regular (fully replicated) tables +- partitioned tables, including sub-types + + - director tables + - dependent tables + + - simple (1 director) + - ref-match (2 directors) + +Design of the partitioned tables. Draw a diagram that includes workers and chunk. + + +Draw a diagram of the table type classification and dependencies between them + +- regular (fully-replicated) + A copy of the table exists at each worker + +- partitioned (distributed) + - director + - dependent + - simple + - ref-match diff --git a/doc/ingest/api/concepts/transactions.rst b/doc/ingest/api/concepts/transactions.rst new file mode 100644 index 000000000..9df04ced7 --- /dev/null +++ b/doc/ingest/api/concepts/transactions.rst @@ -0,0 +1,257 @@ +.. _ingest-api-concepts-transactions: + +Transactions +============ + +The distributed transaction mechanism is one of the key technologies that was +implemented in the Qserv Ingest system to allow for the incremental updates of the overall state of the data and metadata +while ensuring the consistency of the ingested catalogs. Transactions also play an important role in allowing +the high-performance ingest activities to be performed in a distributed environment. Transactions if used correct may +significantly increase the level of parallelism of the ingest workflows. Transactions are not visible to end users. + +Transactions are open in a scope of a database. It's a responsibility of the workflows to manage transactions as needed +for the ingest activities uisng the following REST services: + +- :ref:`ingest-trans-management` (REST) + +Isolation and parallelism +------------------------- + +The first role of the transaction is to provide the isolation of the ingest activities. The transactions allow for the +parallel ingest of the data into the tables located at the many workers of the Qserv cluster, and into the same table +located at the same worker. The transactions are started and commited independently of each other. The transactions +are not visible to the users and are not used for the user queries. + +To understand why the transactions help to increase the level of parallelism of the ingest activities, read +the last section on this page: + +- :ref:`ingest-api-concepts-transactions-impl` (CONCEPTS) + +Row tagging +----------- + +The second role of the transactions is to implement the tagging mechanism for the ingested data. All rows +ingested into to the data tables and the *director* index tables are tagged with the transaction identifiers +that is unique for each transaction. Hence, all contribution requests made into the tables via this API are +associated with a specific identifier. The identifiers are usually sent in the service request and response objects +in an attribute ``transaction_id``. As an example of the attribute, see a description of the following REST service: + +- :ref:`ingest-worker-contrib-by-ref` (REST) + +An effect of such tagging can be seen as a special column called ``qserv_trans_id`` that is automatically added by +the Ingest system into the table schema of each table. In the current implementation of the system, this is the very +first column of the table. The column is of the ``UNSIGNED INT`` type and is not nullable. The column is visible +to Qserv users and is queriable. Here is an illustration of a query and the corresponding result set illustrating the concept: + +.. code-block:: sql + + SELECT `qserv_trans_id`, `objectId`,`chunkId` + FROM `dp02_dc2_catalogs`.`Object` + WHERE `qserv_trans_id` IN (860, 861); + + +----------------+---------------------+---------+ + | qserv_trans_id | objectId | chunkId | + +----------------+---------------------+---------+ + | 860 | 1249546586455828954 | 57871 | + | 860 | 1249546586455828968 | 57871 | + . . . . + | 861 | 1252546054176403713 | 57891 | + | 861 | 1252546054176403722 | 57891 | + +----------------+---------------------+---------+ + +.. note:: + + The database administrator can decide to drop the column from the table schema if there is a need to save the space + in the table. The column is not used by Qserv for any other purposes than the ingest activities. And once the ingest + is completed, the column is not needed anymore except for Q&A-ing the data, bookeeping and data provenance. + +Checkpointing +------------- + +Transactions also provide the checkpointing mechanism that allows rolling back to a prior consistent state of the affected tables +should any problem occur during the ingest activities. Transactions may spans across many workers and tables located +at the workers. It's up to the workflow to decide what contrubutions to ingest and in what order to ingest those in +a scope of each transaction. + +The following diagram illustrates the concept of the transactions in Qserv. There are 3 transactions that are started and +commited sequentially (in the real life scenarios the transactions can be and should be started and commited in parallel, +and indepedently of each other). Data are ingested into two separate table located at 2 workers. The diagram also shows +a failure to ingest the data into table ``Table-A`` at ``Worker-X`` in a scope of ``Transaction-2``: + +.. image:: /_static/ingest-transactions-failed.png + :target: ../../../_images/ingest-transactions-failed.png + :alt: Failed Transaction Contribution + +At this point the table ``Table-A`` at ``Worker-X`` is found in an inconsistent state. The workflow can decide to roll back +the failed transaction and to re-try the ingest activities in a scope of the new transaction. The rollback is performed by +the worker ingest service: + +- :ref:`ingest-trans-management-end` (REST) + +Also read the following document to learn more about the transaction abort: + +- :ref:`ingest-api-advanced-transaction-abort` (ADVANCED) + +Removing the failed transaction would result in the following state of the tables, which is *clean* and consistent: + +.. image:: /_static/ingest-transactions-aborted.png + :target: ../../../_images/ingest-transactions-aborted.png + :alt: Aborted Transaction + +After that, the workflow can re-try **ALL** ingest activities that were meant to be done in a scope of the previously +failed transaction by starting another transaction. If the ingest activities are successful, the tables will be in the +consistent state: + +.. image:: /_static/ingest-transactions-resolved.png + :target: ../../../_images/ingest-transactions-resolved.png + :alt: Another Transaction + + +Taransaction status and state +----------------------------- + +Each transaction is in a well-defined *state* at each moment of time. The state is a part of the broader collection +if the transaction attributes called the transaction *status*. All of this can be obtained by calling services +documented in the following section: + +- :ref:`ingest-trans-management-status` (REST) +- :ref:`ingest-trans-management-states` (REST) + +The services provide a flexible filtering mechanism for finding the transactions of interest in various scopes and states +and reporting the information at different levels of details as needed by the workflows or other applications. + +These are just a few typical applications for this information in a context of the workflows: + +- *Dynamic* transaction management (versus the *static* management where all transactions would be started at once): + + - Starting the lmited number of transactions at the beginning of the ingest + - Monitoring the progress and performance of the transactions + - Committing transactions where all table contributes were successfully ingested + - Starting new transactions to load more contributions to meet the performance goals + +- Locating the failed transactions and re-trying the ingest activities in a scope of the new transactions. +- Locating failed table contribution requests that were made in a scope of a transaction to see if it's possible + to retry the contributions w/o aborting the transaction. +- Building a Web dashboard. + +Contexts +-------- + +When starting (or finishing a transaction) using the corresponding services (see below) a workflow may optionally +attach an piece of arbitrary workflow-defined information (the JSON object) to the transaction. The object is called +the *context*. It will be stored within the Replication/Ingest system's database and be associated with the transaction. +The object could be as large as ``16 MB``. In effect, the context is a part of the transaction's persistent state. + +The initial version of the context object is passed along the transaction start request in the attribute ``context``: + +- :ref:`ingest-trans-management-start` (REST) + +The context object may also be updated when aborting or committing a transaction by: + +- :ref:`ingest-trans-management-end` (REST) + +Contexts are also retrieved by the status retrieval services: + +- :ref:`ingest-trans-management-status` (REST) + +The workflow may use the contexts for the following reasons: + +- Store the information on the input contributions made in a scope of a transaction to be used later for the recovery + from the failures. The information may include locations of the input files, as well as any other information + allowing to retry the contributions. Making the workflows to depend on the contexts may simplify the implementation + of the workflows by allowing to avoid the need to store the information in the external databases or files. + Altogether, the contexts may improve robustness of the workflows. +- Store the information for the purpose of internal bookkeeping that would be independent of the user workflow's + infrastructure or environment. +- Store the additional information to be used as a source of metadata for data provenance systems. + +Obviously, the workflow implementation may have its own mechanism for that, and it probably should. However, attaching +the metadata to transactions in the persistent state of the system along with the transactions has a few important benefits. +In particular, it guarantees consistency between transactions and contexts. Secondly, it provides the precise timing for +the ingest operations (the start and finish times are measured by the Ingest system at the right moments). +Thirdly, the information may be seen from the general-purpose Web Dashboard application of Qserv and could also be used +by the database support teams for building various metrics on the performance of the Qserv Ingest system. + + +.. _ingest-api-concepts-transactions-impl: + +Implementation Details +---------------------- + +The Qserv transactions are quite different from the ones in the typical RDBMS implementations. Firstly, they are not designed +as an an isolation mechanis for executing user queries, and the are not visible to Qserv users. In Qserv, tables that are being +ingested are not seen or queriable by the users anyway. The main purpose of the transactions in Qserv is to allow for +the incremental updates of the distributed state of data in Qserv across many (potentially - hundreds of) workers. +Each worker runs its own instance of the MySQL/MariaDB server which is not aware of the of the others. Some might say that +transactions are associated with *vertical slices* of rows in the tables that are located at the workers. + +The second technical problem to be addressed by the transactions is a lack of the transaction support in the MyISAM table +engine that is used in Qserv for the data tables. The MyISAM engine is used in Qserv due to it ssimplicity and high performance. +Unfortunately, failuires while ingesting data into the MyISAM tables can leave the table in a corrupted state. The transactions +provide a mechanism allowing to roll back the tables to a consistent state in case of the failures. The current implementation +of the transactions in Qserv is based on the MySQL/MariaDB partitions: + +- https://mariadb.com/kb/en/partitioning-overview/ + + +.. warning:: + + When the catalog is being published, the partitioned MyISAM tables are converted to the regular format. + This operation is performed by the Qserv Ingest system. + The conversion is a time-consuming operation and may take a long time to complete for + a single table. An observed performance of the operation per table is on a scale of ``20 MB/s`` to ``50 MB/s``. + However, a typical catalog will have thousands of such chunk tables which would be processed in parallel + at all workers of the Qserv cluster. The resulting performance of the conversion would be on a scale of + many ``GB/s``, and the operation would be completed in a reasonable time. + + - A definition of the *reasonable time* is given rather loosely here. An overall idea is that + such conversion should be on the same scale (smaller) as the table ingest *per se*. A similar + philosophy is applied to other data management operations in Qserv besides the ingest. + +From a prospective of the workflows, these are the most important limitations of the transactions: + +- Transaction identifiers are the 32-bit unsignd integer numbers. The maximum number of the transactions that can be + started in the system is 2^32 - 1 = 4,294,967,295. The transactions are not re-used, so the number of the transactions + that can be started in the system is limited by the number of the unique transaction identifiers that can be generated + by the system. + +- The transaction with the identifier ``0`` is reserved for the system for the so called *default* transaction. + The workflows can't ingest any contributions in a context of that transaction, or manage this special transaction. + +- MySQL tables only allow up to ``8,000`` partitions per table. This is a limitation of the MySQL/MariaDB partitioning mechanism. + And there is a certain overhead in MySQL for each partition. Hence, it's not recommended to start more than ``1,000`` transactions + during the ingest. + +Transaction numbers directly map to the partition identifiers of the MySQL/MariaDB partitioned tables. Here is an example +of a few chunk tables of a catalog that is still being ingested: + +.. code-block:: bash + + -rw-rw----+ 1 rubinqsv gu 4868 Sep 10 20:48 gaia_source_1012.frm + -rw-rw----+ 1 rubinqsv gu 48 Sep 10 20:48 gaia_source_1012.par + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1012#P#p0.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1012#P#p0.MYI + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1012#P#p1623.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1012#P#p1623.MYI + -rw-rw----+ 1 rubinqsv gu 31000308 Sep 10 20:48 gaia_source_1012#P#p1628.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 11 19:49 gaia_source_1012#P#p1628.MYI + -rw-rw----+ 1 rubinqsv gu 4868 Sep 10 20:48 gaia_source_1020.frm + -rw-rw----+ 1 rubinqsv gu 48 Sep 10 20:48 gaia_source_1020.par + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1020#P#p0.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1020#P#p0.MYI + -rw-rw----+ 1 rubinqsv gu 51622084 Sep 10 20:48 gaia_source_1020#P#p1624.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 11 19:49 gaia_source_1020#P#p1624.MYI + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1020#P#p1630.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1020#P#p1630.MYI + -rw-rw----+ 1 rubinqsv gu 4868 Sep 10 20:47 gaia_source_1028.frm + -rw-rw----+ 1 rubinqsv gu 48 Sep 10 20:47 gaia_source_1028.par + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1028#P#p0.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1028#P#p0.MYI + -rw-rw----+ 1 rubinqsv gu 739825104 Sep 10 20:48 gaia_source_1028#P#p1625.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 11 19:49 gaia_source_1028#P#p1625.MYI + -rw-rw----+ 1 rubinqsv gu 0 Sep 10 20:46 gaia_source_1028#P#p1629.MYD + -rw-rw----+ 1 rubinqsv gu 2048 Sep 10 20:46 gaia_source_1028#P#p1629.MYI + +This snapshot was taken by looking at the MariaDB data directory at one of the Qserv workers. Note that the tables +are partitioned by the transaction numbers, where the transaction identifiers are the numbers after the ``#P#`` in +the file names. diff --git a/doc/ingest/api/index.rst b/doc/ingest/api/index.rst index 75b56ddd4..88ba5b74a 100644 --- a/doc/ingest/api/index.rst +++ b/doc/ingest/api/index.rst @@ -1,20 +1,22 @@ + +.. note:: + + Information in this guide corresponds to the version **38** of the Qserv REST API. Keep in mind + that each implementation of the API has a specific version. The version number will change + if any changes to the implementation or the API that might affect users will be made. + The current document will be kept updated to reflect the latest version of the API. + ##################################### The Ingest Workflow Developer's Guide ##################################### -TBC - - -.. list-table:: Title - :widths: 25 25 50 - :header-rows: 1 +.. toctree:: + :maxdepth: 4 - * - Heading row 1, column 1 - - Heading row 1, column 2 - - Heading row 1, column 3 - * - Row 1, column 1 - - - - Row 1, column 3 - * - Row 2, column 1 - - Row 2, column 2 - - Row 2, column 3 + introduction + concepts/index + simple/index + advanced/index + post-ingest/index + reference/index + appendix/index diff --git a/doc/ingest/api/introduction.rst b/doc/ingest/api/introduction.rst new file mode 100644 index 000000000..b860129d0 --- /dev/null +++ b/doc/ingest/api/introduction.rst @@ -0,0 +1,91 @@ +Introduction +============ + +This document presents an API that is available in Qserv for constructing the data ingest applications (also mentioned +in the document as *ingest workflows*). The API is designed to provide a high-performance and reliable mechanism for +ingesting large quantities of data where the high performance or reliability of the ingests is at stake. +The document is intended to be a practical guide for the developers who are building those applications. +It provides a high-level overview of the API, its main components, and the typical workflows that can be built using the API. + +At the very high level, the Qserv Ingest system is comprised of: + +- The REST server that is integrated into the Master Replication Controller. The server provides a collection + of services for managing metadata and states of the new catalogs to be ingested. The server also coordinates + its own operations with Qserv itself and the Qserv Replication System to prevent interferences with those + and minimize failures during catalog ingest activities. +- The Worker Ingest REST service run at each Qserv worker node alongside the Qserv worker itself and the worker MariaDB server. + The role of these services is to actually ingest the client's data into the corresponding MySQL tables. + The services would also do an additional (albeit, minimal) preprocessing and data transformation (where or when needed) + before ingesting the input data into MySQL. Each worker server also includes its own REST server for processing + the "by reference" ingest requests as well as various metadata requests in the scope of the workers. + +Implementation-wise, the Ingest System heavily relies on services and functions of the Replication System including +the Replication System's Controller Framework, various (including the Configuration) services, and the worker-side +server infrastructure of the Replication System. + +Client workflows interact with the system's services via open interfaces (based on the HTTP protocol, REST services, +JSON data format, etc.) and use ready-to-use tools to fulfill their goals of ingesting catalogs. + +Here is a brief summary of the Qserv Ingest System's features: + +- It introduces the well-defined states and semantics into the ingest process. With that, a process of ingesting a new catalog + now has to go through a sequence of specific steps maintaining a progressive state of the catalog within Qserv + while it's being ingested. The state transitions and the corresponding enforcements made by the system would + always ensure that the catalog would be in a consistent state during each step of the process. + Altogether, this model increases the robustness of the process, and it also makes it more efficient. + +- To facilitate and implement the above-mentioned state transitions the new system introduces a distributed + *tagging* and *checkpointing* mechanism called *super-transactions*. The transactions allow for incremental + updates of the overall state of the data and metadata while allowing to safely roll back to a prior consistent + state should any problem occur during data loading within such transactions. + + - The data tagging capability of the transactions can be also used by the ingest workflows and by + the Qserv administrators for bookkeeping of the ingest activities and for the quality control of + the ingested catalogs. + +- In its very foundation, the system has been designed for constructing high-performance and parallel ingest + workflows w/o compromising the consistency of the ingested catalogs. + +- For the actual data loading, the system offers plenty of options, inluding pushing data into Qserv directly + via a proprietary binary protocol using :ref:`ingest-tools-qserv-replica-file`, :ref:`ingest-worker-contrib-by-val` + in the HTTP request body, or :ref:`ingest-worker-contrib-by-ref`. In the latter case, the input data (so called table + *contributions*) will be pulled by the worker services from remote locations as instructed by the ingest workflows. + The presently supported sources include the object stores (via the HTTP/HTTPS protocols) and the locally mounted + distributed filesystems (via the POSIX protocol). + + - The ongoing work on the system includes the development of the support for the ingesting contributions + from the S3 object stores. + +- The data loading services also collect various information on the ongoing status of the ingest activities, + abnormal conditions that may occur during reading, interpreting, or loading the data into Qserv, as well + as the metadata for the data that is loaded. The information is retained within the persistent + state of the Replication/Ingest System for the monitoring and debugging purposes. A feedback is provided + to the workflows on various aspects of the ingest activities. The feedback is useful for the workflows to adjust their + behavior and to ensure the quality of the data being ingested. + + - To get further info on this subject, see sections :ref:`ingest-general-error-reporting` and + :ref:`ingest-worker-contrib-descriptor-warnings`. + In addition, the API provides REST services for obtaining metadata on the state of catalogs, tables, distributed + transactions, contribution requests, the progress of the requested operations, etc. + +**What the Ingest System does NOT do**: + +- As per its current implementation (which may change in the future) it does not automatically partition + input files. This task is expected to be a responsibility of the ingest workflows. The only data format + is is presently supported for the table payload are ``CSV`` and ``JSON`` (primarily for ingesting + user-generated data products as explained in :ref:`http-frontend-ingest`). + +- It does not (with an exception of adding an extra leading column ``qserv_trans_id`` required by + the implementation of the previously mentioned *super-transactions*) pre-process the input ``CSV`` + payload sent to the Ingest Data Servers by the workflows for loading into tables. + It's up to the workflows to sanitize the input data and to make them ready to be ingested into Qserv. + +More information on the requirements and the low-level technical details of its implementation (unless it's +needed for the purposes of this document's goals) can be found elsewhere. + +It's recommended to read the document sequentially. Most ideas presented in the document are introduced in +a section :ref:`ingest-api-concepts` and illustrated with a simple practical example in :ref:`ingest-api-simple`. +The section is followed by a few more sections covering :ref:`ingest-api-advanced` and :ref:`ingest-api-post-ingest`. +The :ref:`ingest-api-reference` section of the document provides complete descriptions of the REST services and tools +mentioned in the document. The last section :ref:`ingest-api-appendix` offers the supplementary material that may +be useful for the developers building the ingest workflows. diff --git a/doc/ingest/api/post-ingest/index.rst b/doc/ingest/api/post-ingest/index.rst new file mode 100644 index 000000000..e07b57187 --- /dev/null +++ b/doc/ingest/api/post-ingest/index.rst @@ -0,0 +1,11 @@ + +.. _ingest-api-post-ingest: + +================================= +Post-Ingest Data Management Tasks +================================= + +The following optional steps are performed after the data has been ingested: + +- :ref:`admin-row-counters` +- :ref:`admin-data-table-index` diff --git a/doc/ingest/api/reference/index.rst b/doc/ingest/api/reference/index.rst new file mode 100644 index 000000000..24a58e83d --- /dev/null +++ b/doc/ingest/api/reference/index.rst @@ -0,0 +1,12 @@ + +.. _ingest-api-reference: + +###################### +Ingest API Reference +###################### + +.. toctree:: + :maxdepth: 4 + + rest/index + tools diff --git a/doc/ingest/api/reference/rest/controller/config.rst b/doc/ingest/api/reference/rest/controller/config.rst new file mode 100644 index 000000000..65f47786a --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/config.rst @@ -0,0 +1,426 @@ +.. _ingest-config: + +Configuring parameters of the ingests +===================================== + +.. _ingest-config-set: + +Setting configuration parameters +-------------------------------- + +Parameters are set for a database (regardless of the *published* status) using the following service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``PUT`` + - ``/ingest/config`` + +The request object has the following schema: + +.. code-block:: + + { "database" : , + "SSL_VERIFYHOST" : , + "SSL_VERIFYPEER" : , + "CAPATH" : , + "CAINFO" : , + "CAINFO_VAL" : , + "PROXY_SSL_VERIFYHOST" : , + "PROXY_SSL_VERIFYPEER" : , + "PROXY_CAPATH" : , + "PROXY_CAINFO" : , + "PROXY_CAINFO_VAL" : , + "CURLOPT_PROXY" : , + "CURLOPT_NOPROXY" : , + "CURLOPT_HTTPPROXYTUNNEL" : , + "CONNECTTIMEOUT" : , + "TIMEOUT" : , + "LOW_SPEED_LIMIT" : , + "LOW_SPEED_TIME" : , + "ASYNC_PROC_LIMIT" : + } + +Where: + +``database`` : *string* : **required** + The required name of a database affected by the operation. + +``SSL_VERIFYHOST`` : *number* = ``2`` + The optional flag that tells the system to verify the host of the peer. If the value is set + to ``0`` the system will not check the host name against the certificate. Any other value would tell the system + to perform the check. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html. + +``SSL_VERIFYPEER`` : *number* = ``1`` + The optional flag that tells the system to verify the peer's certificate. If the value is set + to ``0`` the system will not check the certificate. Any other value would tell the system to perform the check. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html. + +``CAPATH`` : *string* = ``/etc/ssl/certs`` + The optional path to a directory holding multiple CA certificates. The system will use the certificates + in the directory to verify the peer's certificate. If the value is set to an empty string the system will not use + the certificates. + + Putting the empty string as a value of the parameter will effectively turn this option off as if it has never been + configured for the database. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_CAPATH.html. + +``CAINFO`` : *string* = ``/etc/ssl/certs/ca-certificates.crt`` + The optional path to a file holding a bundle of CA certificates. The system will use the certificates + in the file to verify the peer's certificate. If the value is set to an empty string the system will not use + the certificates. + + Putting the empty string as a value of the parameter will effectively turn this option off as if it has never been + configured for the database. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_CAINFO.html. + +``CAINFO_VAL`` : *string* = ``""`` + The optional value of a certificate bundle for a peer. This parameter is used in those cases when it's + impossible to inject the bundle directly into the Ingest workers' environments. If a non-empty value of the parameter + is provided then ingest servers will use it instead of the one mentioned (if any) in the above-described + attribute ``CAINFO``. + + **Attention**: Values of the attribute are the actual certificates, not file paths like in the case of ``CAINFO``. + +``PROXY_SSL_VERIFYHOST`` : *number* = ``2`` + The optional flag that tells the system to verify the host of the proxy. If the value is set + to ``0`` the system will not check the host name against the certificate. Any other value would tell the system + to perform the check. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_PROXY_SSL_VERIFYHOST.html. + +``PROXY_SSL_VERIFYPEER`` : *number* = ``1`` + The optional flag that tells the system to verify the peer's certificate. If the value is set + to ``0`` the system will not check the certificate. Any other value would tell the system to perform the check. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_PROXY_SSL_VERIFYPEER.html. + +``PROXY_CAPATH`` : *string* = ``""`` + The optional path to a directory holding multiple CA certificates. The system will use the certificates + in the directory to verify the peer's certificate. If the value is set to an empty string the system will not use + the certificates. + + Putting the empty string as a value of the parameter will effectively turn this option off as if it has never been + configured for the database. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_PROXY_CAPATH.html. + +``PROXY_CAINFO`` : *string* = ``""`` + The optional path to a file holding a bundle of CA certificates. The system will use the certificates + in the file to verify the peer's certificate. If the value is set to an empty string the system will not use + the certificates. + + Putting the empty string as a value of the parameter will effectively turn this option off as if it has never been + configured for the database. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_PROXY_CAINFO.html. + +``PROXY_CAINFO_VAL`` : *string* = ``""`` + The optional value of a certificate bundle for a proxy. This parameter is used in those cases when it's + impossible to inject the bundle directly into the Ingest workers' environments. If a non-empty value of the parameter + is provided then ingest servers will use it instead of the one mentioned (if any) in the above-described + attribute ``PROXY_CAINFO``. + + **Attention**: Values of the attribute are the actual certificates, not file paths like in the case of ``PROXY_CAINFO``. + +``CURLOPT_PROXY`` : *string* = ``""`` + Set the optional proxy to use for the upcoming request. The parameter should be a null-terminated string + holding the host name or dotted numerical IP address. A numerical IPv6 address must be written within ``[brackets]``. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_PROXY.html. + +``CURLOPT_NOPROXY`` : *string* = ``""`` + The optional string consists of a comma-separated list of host names that do not require a proxy + to get reached, even if one is specified. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_NOPROXY.html. + +``CURLOPT_HTTPPROXYTUNNEL`` : *number* = ``0`` + Set the optional tunnel parameter to ``1`` to tunnel all operations through the HTTP proxy + (set with ``CURLOPT_PROXY``). + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_HTTPPROXYTUNNEL.html. + +``CONNECTTIMEOUT`` : *number* = ``0`` + The optional maximum time in seconds that the system will wait for a connection to be established. + The default value means that the system will wait indefinitely. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_CONNECTTIMEOUT.html + +``TIMEOUT`` : *number* = ``0`` + The optional maximum time in seconds that the system will wait for a response from the server. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_TIMEOUT.html + +``LOW_SPEED_LIMIT`` : *number* = ``0`` + The optional transfer speed in bytes per second that the system considers too slow and will abort the transfer. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_LOW_SPEED_LIMIT.html + +``LOW_SPEED_TIME`` : *number* = ``0`` + The optional time in seconds that the system will wait for the transfer speed to be above the limit + set by ``LOW_SPEED_LIMIT``. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_LOW_SPEED_TIME.html + +``ASYNC_PROC_LIMIT`` : *number* = ``0`` + The optional maximum concurrency limit for the number of contributions to be processed in a scope of + the database. The actual number of parallel requests may be further lowered by the hard limit specified by + the Replication System worker's configuration parameter (``worker``, ``num-async-loader-processing-threads``). + The parameter can be adjusted in real time as needed. It gets into effect immediately. Putting ``0`` as a value of + the parameter will effectively turn this option off as if it has never been configured for the database. + + This attribute directly maps to https://curl.se/libcurl/c/CURLOPT_LOW_SPEED_TIME.html + + **Note**: The parameter is available as of API version ``14``. + +If a request is successfully finished it returns the standard JSON object w/o any additional data but +the standard completion status. + +.. _ingest-config-get: + +Retrieving configuration parameters +----------------------------------- + +.. warning:: + As of version ``14`` of the API, the name of the database is required to be passed in the request's query instead of + passing it in the JSON body. The older implementation was wrong. + + +.. list-table:: + :widths: 10 25 65 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``GET`` + - ``/ingest/config`` + - ``database=`` + +Where the mandatory query parameter ``database`` specifies the name of a database affected by the operation. + +If the operation is successfully finished it returns an extended JSON object that has the following schema (in addition +to the standard status and error reporting attributes): + +.. code-block:: + + { "database" : , + "SSL_VERIFYHOST" : , + "SSL_VERIFYPEER" : , + "CAPATH" : , + "CAINFO" : , + "CAINFO_VAL" : , + "PROXY_SSL_VERIFYHOST" : , + "PROXY_SSL_VERIFYPEER" : , + "PROXY_CAPATH" : , + "PROXY_CAINFO" : , + "PROXY_CAINFO_VAL" : , + "CURLOPT_PROXY" : , + "CURLOPT_NOPROXY" : , + "CURLOPT_HTTPPROXYTUNNEL" : , + "CONNECTTIMEOUT" : , + "TIMEOUT" : , + "LOW_SPEED_LIMIT" : , + "LOW_SPEED_TIME" : , + "ASYNC_PROC_LIMIT" : + } + +The attributes of the response object are the same as the ones described in the section :ref:`ingest-config-set`. + +.. _ingest-config-global-workers: + +Global configuration parameters of workers +------------------------------------------ + +.. note:: + This is the same service that was described in: + + - :ref:`ingest-db-table-management-config` (REST) + + The response object of the service also returns the information on the workers. + +There are two sectons related to workers in the response object. The first section ``config.general.worker`` +includes the general parameters of the ingest services. Values of the parameters are the same for all +workers. The second section ``config.workers`` has the information on the individual workers. + +The general information on all workers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The schema of the relevant section of the respionse object is illustrated by the following example: + +.. code-block:: json + + { "config": { + "general" : { + "worker" : { + "num-loader-processing-threads" : 64, + "num-http-loader-processing-threads" : 8, + "num-async-loader-processing-threads" : 8, + + "ingest-charset-name" : "latin1", + + "ingest-max-retries" : 10, + "ingest-num-retries" : 1, + + "loader-max-warnings" : 64, + + "async-loader-auto-resume" : 1, + "async-loader-cleanup-on-resume" : 1, + }, + } + } + } + +Where: + +``config.general.worker`` : *object* + A collection of the general parameters of the worker ingest service. + +``num-loader-processing-threads`` : *number* + The number of ingest request processing threads in the service that supports the proprietary + binary protocol. + +``num-http-loader-processing-threads`` : *number* + The number of ingest request processing threads in the HTTP-based ingest service. Note that + the service is used for processing *synchronous* contribution requess and for submitting + the *asynchronous* requests to the service. + +``num-async-loader-processing-threads`` : *number* + The number of ingest request processing threads in a thread pool that processes + the *asynchronous* contribution requests. + +``ingest-charset-name`` : *string* + The name of a character set for parsing the payload of the contributions. + +``ingest-max-retries`` : *number* + The maximum number of the automated retries of failed contribution attempts + in cases when such retries are still possible. The parameter represents the *hard* + limit for the number of retries regardless of what's specified in the related + parameter ``ingest-num-retries`` or in the contributions requests made by the workflows. + The primary purpose of the parameter is to prevent accidental overloading + of the ingest system should a very large number of retries accidentally specified + by the ingest workflows for individual contributions. Setting a value of the parameter + to ``0`` will unconditionally disable any retries. + +``ingest-num-retries`` : *number* + The default number of the automated retries of failed contribution attempts + in cases when such retries are still possible. The limit can be changed for + individual contributions. Note that the effective number of retries specified + by this parameter or the one set in the contribution requests can not + exceed the *hard* limit set in the related parameter ``ingest-max-retries``. + Setting a value of the parameter to 0 will disable automatic retries (unless they are + explicitly enabled or requested by the ingest workflows for individual contributions). + +``loader-max-warnings`` : *number* + The maximum number of warnings to retain after executing ``LOAD DATA [LOCAL] INFILE`` + when ingesting contributions into worker MySQL database. The warnings (if any) will be recorded in + the persisent state of the Replication/Ingest system and returned to the ingest workflow upon request. + +``async-loader-auto-resume`` : *number* + The flag controlling the behavior of the worker's *asynchronous* ingest service after + (the deliberate or accidental) restarts. If the value of the parameter is not ``0`` then the service + will resume processing incomplete (queued or on-going) requests. Setting a value of the parameter + to ``0`` will result in the unconditional failing of all incomplete contribution requests existed prior + the restart. + + .. warning:: + + Requests failed in the last (loading) stage can't be resumed, and they will require aborting + the corresponding transaction. If the automaticu resume is enabled rhese request will be automatically + closed and marked as failed. + +``async-loader-cleanup-on-resume`` : *number* + The flag controlling the behavior of worker's *asynchronous* ingest service after + restarting the service. If the value of the parameter is not ``0`` the service will try to clean + up the temporary files that might be left on disk for incomplete (queued or ongoing) requests. + The option may be disabled to allow debugging the service. + +Worker-specific information +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The schema of the relevant section of the respionse object is illustrated by the following example: + +.. code-block:: json + + { "config": { + "workers" : [ + { "name" : "db02", + "is-enabled" : 1, + "is-read-only" : 0, + + "loader-host" : { + "addr" : "172.24.49.52", + "name" : "sdfqserv002.sdf.slac.stanford.edu" + }, + "loader-port" : 25002, + "loader-tmp-dir" : "/qserv/data/ingest", + + "http-loader-host" : { + "name" : "sdfqserv002.sdf.slac.stanford.edu", + "addr" : "172.24.49.52" + }, + "http-loader-port" : 25004, + "http-loader-tmp-dir" : "/qserv/data/ingest", + }, + ] + } + } + +Where: + +``config.workers`` : *array* + A collection of worker nodes, where each object represents a worker node. + +``name`` : *string* + The unique identifier of a worker node. + +``is-enabled`` : *number* + The flag that tells if the worker node is enabled. If the value is set to ``0`` the worker node is disabled. + Workers which are not enables do not participate in the ingest activities. + +``is-read-only`` : *number* + The flag that tells if the worker node is read-only. If the value is set to ``0`` the worker node is read-write. + Workers which are in the read-only statte do not participate in the ingest activities. + +**Parameters of the ingest service that supports the proprietary binary protocol**: + +``loader-host`` : *object* + The object with the information about the loader host. + + - ``addr`` : *string* + The IP address of the lder host. + + - ``name`` : *string* + The FQDN (fully-qualified domain name) of the host. + +``loader-port`` : *number* + The port number of the ingest service. + +``loader-tmp-dir`` : *string* + The path to the temporary directory on the loader host that is used by the ingest service + as a staging area for the contributions. + +**Parameters of the HTTP-based ingest service**: + +``http-loader-host`` : *object* + The object with the information about the loader host. + + - ``addr`` : *string* + The IP address of the lder host. + + - ``name`` : *string* + The FQDN (fully-qualified domain name) of the host. + +``http-loader-port`` : *number* + The port number of the ingest service. + +``http-loader-tmp-dir`` : *string* + The path to the temporary directory on the loader host that is used by the ingest service + as a staging area for the contributions. diff --git a/doc/ingest/api/reference/rest/controller/db-table-management.rst b/doc/ingest/api/reference/rest/controller/db-table-management.rst new file mode 100644 index 000000000..32da34884 --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/db-table-management.rst @@ -0,0 +1,559 @@ +Database and table management +============================= + +.. _ingest-db-table-management-config: + +Finding existing databases and database families +------------------------------------------------ + +The following service pulls all configuration information of of the Replication/Ingest System, including info +on the known database families, databases and tables: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/replication/config`` + +Upon successful (see :ref:`ingest-general-error-reporting`) completion of the request, the service will return an object +that has the following schema (of which only the database and database family-related fields are shown): + +.. code-block:: json + + { + "config": { + "database_families" : [ + { + "overlap" : 0.01667, + "min_replication_level" : 3, + "num_sub_stripes" : 3, + "name" : "production", + "num_stripes" : 340 + } + ], + "databases" : [ + { + "database" : "dp01_dc2_catalogs_02", + "create_time" : 0, + "is_published" : 1, + "publish_time" : 1662688661000, + "family_name" : "production", + "tables" : [ + { + "ang_sep" : 0, + "is_director" : 1, + "latitude_key" : "coord_dec", + "create_time" : 1662774817703, + "unique_primary_key" : 1, + "flag" : "", + "name" : "Source", + "director_database_name" : "", + "is_ref_match" : 0, + "is_partitioned" : 1, + "longitude_key" : "coord_ra", + "database" : "dp02_dc2_catalogs", + "director_table" : "", + "director_key2" : "", + "director_database_name2" : "", + "director_key" : "sourceId", + "director_table2" : "", + "director_table_name2" : "", + "is_published" : 1, + "director_table_name" : "", + "publish_time" : 1663033002753, + "columns" : [ + { + "name" : "qserv_trans_id", + "type" : "INT NOT NULL" + }, + { + "type" : "BIGINT NOT NULL", + "name" : "sourceId" + }, + { + "type" : "DOUBLE NOT NULL", + "name" : "coord_ra" + }, + { + "type" : "DOUBLE NOT NULL", + "name" : "coord_dec" + } + ] + } + ] + } + ] + } + } + +**Notes**: + +- The sample object was truncated for brevity. The actual number of families, databases, tables and columns were + much higher in the real response. +- The number of attributes varies depending on a particular table type. The example above shows + attributes for the table ``Source``. This table is *partitioned* and is a *director* (all *director*-type tables + are partitioned in Qserv). + + +.. _ingest-db-table-management-register-db: + +Registering databases +---------------------- + +Each database has to be registered in Qserv before one can create tables and ingest data. The following +service of the Replication Controller allows registering a database: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/database`` + +The service requires a JSON object of the following schema: + +.. code-block:: + + { + "database" : , + "num_stripes" : , + "num_sub_stripes" : , + "overlap" : , + "auto_build_secondary_index" : , + "local_load_secondary_index" : + } + +Where: + +``database`` : *string* + The required name of the database to be created. + +``num_stripes`` : *number* + The required number of stripes that was used when partitioning data of all tables to be ingested in a scope of the database. + +``num_sub_stripes`` : *number* + The required number of sub-stripes that was used when partitioning data of all tables to be ingested in a scope of the database. + +``overlap`` : *number* + The required overlap between the stripes. + +``auto_build_secondary_index`` : *number* = ``1`` + The flag that specifies the desired mode for building the *director* (used to be known as the *secondary*) + indexes of the director tables of the catalog. The flag controls the automatic building of the indexes, where: + + - ``1``: Build the index automatically during transaction commit time. + - ``0``: Do not build the index automatically during transaction commit time. In this case, it will be up to a workflow + to trigger the index building as a separated "post-ingest" action using the corresponding service: + + - :ref:`ingest-director-index-build` + + **Note**: Catalogs in Qserv may have more than one director table. This option applies to all such tables. + +.. warning:: + + - The service will return an error if the database with the same name already exists in the system. + - Values of attributes ``num_stripes``, ``num_sub_stripes`` and ``overlap`` are expected to match + the corresponding partitioning parameters used when partitioning all partitioned tables of the new database. + Note that the current implementation of the Qserv Ingest system will not validate contributions to the partitioned + tables to enforce this requirement. Only the structural correctness will be checked. It's up to a workflow + to ensure the data ingested into tables are correct. + - Building the *director* index during transaction commit time (for the relevant tables) may have a significant + impact on the performance of the transaction commit operation. The impact is proportional to the size of the + contributions made into the table during the transaction. This may orotolng the transaction commit time. + An alternative option is to build the indexes as a separated "post-ingest" action using the corresponding service: + + - :ref:`ingest-director-index-build` + +If the operation is successfully finished (see :ref:`ingest-general-error-reporting`) a JSON object returned by the service +will have the following attribute: + +.. code-block:: + + { + "database": { + ... + } + } + +The object containing the database configuration information has the same schema as it was explained earlier in section: + +- :ref:`ingest-db-table-management-config` + + +.. _ingest-db-table-management-register-table: + +Registering tables +------------------ + +All tables, regardless if they are *partitioned* or *regular* (fully replicated on all worker nodes), have to be registered +using the following Replication Controller's service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/table`` + +The service requires a JSON object of the following schema: + +Where a JSON object sent to the service with the request shall describe that table. This is a schema of the object for +the **partitioned** tables is presented below: + +.. code-block:: + + { + "database" : , + "table" : , + "is_partitioned" : , + "schema" : [ + { "name" : , + "type" : + }, + ... + ], + "director_table" : , + "director_key" : , + "director_table2" : , + "director_key2" : , + "latitude_key" : , + "longitude_key" : , + "flag" : , + "ang_sep" : , + "unique_primary_key" : + } + +A description of the *regular* tables has a fewer number of attributes (attributes that which are specific to the *partitioned* +tables are missing): + +.. code-block:: + + { + "database" : , + "table" : , + "is_partitioned" : , + "schema": [ + { + "name" : , + "type" : + }, + ... + ] + } + +Where the attributes are: + +``database`` : *string* + The required name of the existing database. + +``table`` : *string* + The required name of a table to be created. + +``is_partitioned`` : *number* + The required type of table. Allowed values: + + - ``1`` for partitioned tables (including any subtypes) + - ``0`` for the regular tables. + +``schema`` : *array* + The required definition of the table schema, where each entry of the array is an object with the following attributes: + + - ``name``: The name of the column. + - ``type``: The type of the column. The type must adhere to the MySQL requirements for column types. + +``director_table`` : *string* + The name of the corresponding first (or left) *director* table. The name is required to be not empty for + the *dependent* tables and it has to be empty for the *director* tables. This is the only way to differentiate between + two types of *partitioned* tables. + + **Note**: The *ref-match* tables are considered as the *dependent* tables since they have columns that are pointing + to the corresponding *director* tables. See attributes: ``director_key``, ``director_table2``, and ``director_key2``. + +``director_key`` : *string* + The required name of a column in a *partitioned* table. A role of the column depends on a subtype of + the table: + + - *director*: the primary key of the table + - *dependent*: the foreign key pointing to the corresponding column of the *director* table + +``director_table2`` : *string* + The name of the corresponding second (or right) *director* table. The non-empty value + name is required for the *ref-match* tables and it has to be empty for the *director* and *dependent* tables. + + **Note**: The very presence of this attribute in the input configuration would imply an intent to register + a "ref-match* table. In this case, non-empty values of the attributes ``director_key2`` , ``flag`` and ``ang_sep`` + will be required in order to succeed with the registration. + +``director_key2`` : *string* + The name of a column that is associated (AKA *foreign key*) with corresponding column of the second *director* table. + A value of this attribute is required for and it must not be empty when registering the *ref-match* tables. + It will be ignored for other table types. See a description of the attribute ``director_table2``. + +``latitude_key`` : *string* + The required name of a column in a *director* table represents latitude. It's optional for the *dependent* tables. + +``longitude_key`` : *string* + The required name of a column in a *director* table represents longitude. It's optional for the *dependent* tables. + +``flag`` : *string* + The name of the special column that is required to be present on the *ref-match* tables. + Values of the column are populated by the tool ``sph-partition-matches`` when partitioning the input files + of the *ref-match* tables. The data type of this column is usually: + + .. code-block:: sql + + INT UNSIGNED + +``ang_sep`` : *double* + The value of the angular separation for the matched objects that is used by Qserv to process queries which + involve the *ref-match* tables. The value is in radians. The value is required to be non-zero for the *ref-match* tables. + +``unique_primary_key`` : *number* = ``0`` + The optional flag allows to drop the uniqueness requirement for the *director* keys of the table. The parameter + is meant to be used for testing new table products, or for the *director* tables that won't have any dependants (child tables). + Allowed values: + + - ``0``: The primary key is not unique. + - ``1``: The primary key is unique. + +.. warning:: + + - The table schema does not include definitions of indexes. Those are managed separately after the table is published. + The index management interface is documented in a dedicated document + + - **TODO**: Managing indexes of MySQL tables at Qserv workers. + + - The service will return an error if the table with the same name already exists in the system, or + if the database didn' exist at a time when teh request was delivered to the service. + + - The service will return an error if the table schema is not correct. The schema will be checked for the correctness. + +.. note:: Requirements for the table schema: + + - The variable-length columns are not allowed in Qserv for the *director* and *ref-match* tables. All columns of these + tables must have fixed lengths. These are the variable length types: ``VARCHAR``, ``VARBINARY``, ``BLOB``, ``TEXT``, + ``GEOMETRY`` and ``JSON``. + + - The *partitioned* tables are required to have parameters ``director_key``, ``latitude_key`` and ``longitude_key``. + - The *director* tables are required to have non-empty column names in the parameters ``director_key``, ``latitude_key`` and ``longitude_key``. + - The *dependent* tables are required to have a non-empty column name specified in the parameter ``director_key``. + - The *dependent* tables are allowed to have empty values in the parameters ``latitude_key`` and ``longitude_key``. + + - For tables where the attributes ``latitude_key`` and ``longitude_key`` are provided (either because they are required + of if they are optional), values must be either both non-empty or empty. An attempt to specify only one of the attribute + or have a non-empty value in an attribute while the other one has it empty will result in an error. + + - All columns mentioned in attributes ``director_key``, ``director_key2``, ``flag``, ``latitude_key`` and ``longitude_key`` + must be present in the table schema. + + - Do not use quotes around the names or type specifications. + + - Do not start the columm names with teh reserved prefix ``qserv``. This prefix is reserved for the Qserv-specific columns. + +An example of the schema definition for the table ``Source``: + +.. code-block:: json + + [ + { + "name" : "sourceId" + "type" : "BIGINT NOT NULL", + }, + { + "name" : "coord_ra" + "type" : "DOUBLE NOT NULL", + }, + { + "name" : "coord_dec" + "type" : "DOUBLE NOT NULL", + } + ] + +If the operation is successfully finished (see :ref:`ingest-general-error-reporting`) a JSON object returned by the service +will have the following attribute: + +.. code-block:: + + { + "database": { + ... + } + } + +The object will contain the updated database configuration information that will also include the new table. +The object will have the same schema as it was explained earlier in section: + +- :ref:`ingest-db-table-management-config` + +**Notes on the table names**: + +- Generally, the names of the tables must adhere to the MySQL requirements for identifiers + as explained in: + + - https://dev.mysql.com/doc/refman/8.0/en/identifier-qualifiers.html + +- The names of identifiers (including tables) in Qserv are case-insensitive. This is not the general requirement + in MySQL, where the case sensitivity of identifiers is configurable one way or another. This requirement + is enforced by the configuration of MySQL in Qserv. + +- The length of the name should not exceed 64 characters as per: + + - https://dev.mysql.com/doc/refman/8.0/en/identifier-length.html + +- The names should **not** start with the prefix ``qserv``. This prefix is reserved for the Qserv-specific tables. + + +.. _ingest-db-table-management-publish-db: + +Publishing databases +-------------------- + +Databases are published (made visible to Qserv users) by calling this service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``PUT`` + - ``/ingest/database/:database`` + +The name of the database is provided as a parameter ``database`` of the resource path. There are a few optional +parameters to be sent in the JSON body of the request: + +.. code-block:: + + { + "consolidate_secondary_index" : , + "row_counters_deploy_at_qserv" : + } + +Where: + +``consolidate_secondary_index`` : *number* = ``0`` + The optional parameter that controls the final format of all the *director* index tables of the database. + Normally, the *director* indexes are MySQL-partitioned tables. If the value of this optional parameter is + not ``0`` then the Ingest System will consolidate the MySQL partitions and turn the tables into the monolitical form. + + .. warning:: + + Depending on the scale of the catalog (sizes of the affected tables), this operation may be quite lengthy (up to many hours). + Besides, based on the up to the date experience with using the MySQL-partitioned director indexes, the impact of the partitions + on the index's performance is rather negligible. So, it's safe to ignore this option in most but very special cases that are not + discussed by the document. + + One can find more info on the MySQL partitioning at: + + - https://dev.mysql.com/doc/refman/8.0/en/partitioning.html + +``row_counters_deploy_at_qserv`` : *number* = ``0`` + This optional flag that triggers scanning and deploying the row counters as explained at: + + - :ref:`admin-row-counters` (ADMIN) + - :ref:`ingest-row-counters-deploy` (REST) + + To trigger this operation the ingest workflow should provide a value that is not ``0``. In this case the row counters + collection service will be invoked with the following combination of parameters: + + .. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - attr + - value + * - ``overlap_selector`` + - ``CHUNK_AND_OVERLAP`` + * - ``force_rescan`` + - ``1`` + * - ``row_counters_state_update_policy`` + - ``ENABLED`` + * - ``row_counters_deploy_at_qserv`` + - ``1`` + +.. warning:: + + The row counters deployment is a very resource-consuming operation. It may take a long time to complete + depending on the size of the catalog. This will also delay the catalog publiushing stage of an ingest compaign. + A better approach is to deploy the row counters as the "post-ingest" operation as explained in: + + - (**TODO** link) Deploying row counters as a post-ingest operation + +.. note:: + + The catalogs may be also unpublished to add more tables. The relevant REST service is documented in: + + - (**TODO** link) Un-publishing databases to allow adding more tables + + +.. _ingest-db-table-management-unpublish-db: + +Un-publishing databases to allow adding more tables +--------------------------------------------------- + +Unpublished databases as well as previously ingested tables will be still visible to users of Qserv. +The main purpose of this operation is to allow adding new tables to the existing catalogs. +The new tables won't be seen by users until the catalog is published back using the following REST service: + +- :ref:`ingest-db-table-management-publish-db` + +Databases are un-published by calling this service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``PUT`` + - ``/replication/config/database/:database`` + +The name of the database is provided in a parameter ``database`` of the resource. The only mandatory parameter +to be sent in the JSON body of the request is: + +``admin_auth_key`` : *string* + The administrator-level authentication key that is required to publish the database. + The key is used to prevent unauthorized access to the service. + + **Note**: The key is different from the one used to publish the database. The eleveated privileges + are needed to reduce risks of disrupting user access to the previously loaded and published databases. + + +.. _ingest-db-table-management-delete: + +Deleting databases and tables +----------------------------- + +These services can be used for deleting non-*published* (the ones that are still ingested) as well as *published* databases, +or tables, including deleting all relevant persistent structures from Qserv: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``DELETE`` + - | ``/ingest/database/:database`` + | ``/ingest/table/:database/:table`` + +To delete a non-*published* database (or a table from such database) a client has to provide the normal level authentication +key ``auth_key`` in a request to the service: + +.. code-block:: + + { "auth_key" : + } + +The name of the databases affected by the operation is specified at the resource's path. + +Deleting databases (or tables from those databases) that have already been published requires a user to have +elevated administrator-level privileges. These privileges are associated with the authentication key ``admin_auth_key`` +to be sent with a request instead of ``auth_key``: + +.. code-block:: + + { "admin_auth_key" : + } + +Upon successful completion of the request (for both above-mentioned states of the database), the service will return the standard +response as explained in the section mentoned below. After that, the database (or the table, depending on a scope of a request) +name can be reused for further ingests if needed. + +- :ref:`ingest-general-error-reporting` + diff --git a/doc/ingest/api/reference/rest/controller/director-index.rst b/doc/ingest/api/reference/rest/controller/director-index.rst new file mode 100644 index 000000000..edb0224b0 --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/director-index.rst @@ -0,0 +1,139 @@ +Director Index Management +========================= + +.. _ingest-director-index-build: + +(Re-)building the Index +----------------------- + +.. note:: API version notes: + + - As of version ``21``, the service can no longer be used to (re-)build indexes of all *director* + tables of a catalog. It's not required to provide the name of the affected table in the parameter ``director_table``. + + - As of version ``22``, the service no longer support the option ``allow_for_published``. Any attempts to specify + the option will result in a warning reported by the service back to a client. The service will ignore the option. + +.. warning:: + Be advised that the amount of time needed to build an index of a large-scale catalog may be quite large. + The current implementation of the secondary index is based on MySQL's InnoDB table engine. The insert + time into this B-Tree table has logarithmic performance. It may take many hours to build catalogs of + billions of objects. In some earlier tests, the build time was 20 hours for a catalog of 20 billion objects. + + +The service of the **Master Replication Controller** builds or rebuilds (if needed) the *director* (used to be known as +the *secondary*) index table of a database. The target table must be *published* at the time of this operation. + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/index/secondary`` + +The request object has the following schema: + +.. code-block:: + + { "database" : , + "director_table" : , + "rebuild" : , + "local" : + } + +Where: + +``database`` : *string* + The required name of a database affected by the operation. + +``director_table`` : *string* + The required name of the *director* table for which the index is required to be (re-)built. + +``rebuild`` : *number* = ``0`` + The optional flag that allows recreating an existing index. If the value is set to ``0`` the service + will refuse to proceed with the request if the index already exists. Any other value would tell the service + to drop (if exists) the index table before re-creating and re-populating it with entries. + +``local`` : *number* = ``0`` + The optional flag that tells the service how to ingest data into the index table, where: + + - ``0``: Index contributions are required to be directly placed by the Replication/Ingest System at a location + that is directly accessible by the MySQL server hosting the index table. This could be either some local folder + of a host where the service is being run or a folder located at a network filesystem mounted on the host. + Once a file is in place, it would be ingested into the destination table using this protocol: + + .. code-block:: sql + + LOAD DATA INFILE ... + + **Note**: Be aware that this option may not be always possible (or cause complications) in Kubernetes-based + deployments of Qserv. + + - ``1`` (or any other numeric value): Index contributions would be ingested into the table using this protocol: + + .. code-block:: sql + + LOAD DATA LOCAL INFILE ... + + **Note**: Files would be first copied by MySQL at some temporary folder owned by the MySQL service before being + ingested into the table. This option has the following caveats: + + - The protocol must be enabled in the MySQL server configuration by setting a system variable: ``local_infile=1``. + - The temporary folder of the MySQL server is required to have sufficient space to temporarily accommodate index + contribution files before they'd be loaded into the table. In the worst-case scenario, there should be enough + space to accommodate all contributions of a given catalog. One could make a reasonable estimate for the latter + by knowing the total number of rows in the director table of the catalog, the size of the primary + key (typically the ``objectId`` column) of the table, as well as types of the ``chunk`` and ``subChunk`` + columns (which are usually the 32-bit integer numbers in Qserv). + - This ingest option would also affect (lower) the overall performance of the operation due to additional + data transfers required for copying file contributions from a location managed by the **Master Replication Controller** + to the temporary folder of the MySQL server. + +If the operation succeeded, the service will respond with the default JSON object which will not carry any additional +attributes on top of what's mandated in :ref:`ingest-general-error-reporting`. + +In case of errors encountered during an actual attempt to build the index was made, the object may have a non-trivial +value of the ``error_ext``. The object wil carry specific reasons for the failures. The schema of the object +is presented below: + +.. code-block:: + + "error_ext" : { +
    : { + : { + : , + ... + }, + }, + ... + } + +Where: + +``table`` : *string* + The placeholder for the name of the director table. + +``worker`` : *string* + The placeholder for the name of the worker service that failed to build the index. + +``chunk`` : *number* + The placeholder for the chunk number. + +``error`` : *string* + The placeholder for the error message. + +Here is an example of how this object might look like: + +.. code-block:: + + "error_ext" : { + "object" : { + "qserv-db01" : { + 122 : "Failed to connect to the worker service", + 3456 : "error: Table 'tes96__Object' already exists, errno: 1050", + }, + "qserv-db23" : { + 123 : "Failed to connect to the worker service" + } + } + } diff --git a/doc/ingest/api/reference/rest/controller/index.rst b/doc/ingest/api/reference/rest/controller/index.rst new file mode 100644 index 000000000..427d79ace --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/index.rst @@ -0,0 +1,14 @@ +############################# +Master Replication Controller +############################# + +.. toctree:: + :maxdepth: 4 + + config + db-table-management + trans-management + table-location + info + director-index + row-counters diff --git a/doc/ingest/api/reference/rest/controller/info.rst b/doc/ingest/api/reference/rest/controller/info.rst new file mode 100644 index 000000000..7194a567f --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/info.rst @@ -0,0 +1,137 @@ +Information services +==================== + +.. _ingest-info-chunks: + +Chunk disposition +----------------- + +.. warning:: + Do not use this service for the chunk placement decisions during catalog ingestion. The service is for + informational purposes only. + +The service of the **Master Replication Controller** return information about the chunk *replicas* in a scope of a given database: + +.. list-table:: + :widths: 10 15 75 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``GET`` + - ``/ingest/chunks`` + - ``database=`` + +Where: + +``name`` : *string* + The required name of a database affected by the operation. + +The resulting object has the following schema: + +.. code-block:: + + { + "replica": [ + { + "chunk" : , + "worker": , + "table" : { + : { + "overlap_rows" : , + "overlap_data_size" : , + "overlap_index_size" : , + "rows" : , + "data_size" : , + "index_size" : + }, + ... + } + }, + ... + ] + } + +Where: + +``replica`` : *array* + A collection of chunk **replicas**, where each object representes a chunk replica. Replicas of a chunk + are essentially the same chunk, but placed on different workers. + +``chunk`` : *number* + The chunk number. + +``worker`` : *string* + The unique identifier of a worker where the chunk replica is located. + +``table`` : *object* + The object with the information about the chunk replica in the scope of + a particular *partitioned* table. + + **Attention**: The current implementation is incomplete. It will return ``0`` for all attributes + of the table object. + +``overlap_rows`` : *number* + The number of rows in the chunk's overlap table. + +``overlap_data_size`` : *number* + The number of bytes in the chunk's overlap table (measured by the size of the corresponding file). + +``overlap_index_size`` : *number* + The number of bytes in the index of the chunk's overlap table (measured by the size + of the corresponding file). + +``rows`` : *number* + The number of rows in the chunk table. + +``data_size`` : *number* + The number of bytes in the chunk table (measured by the size of the corresponding file). + +``index_size`` : *number* + The number of bytes in the index of the chunk table (measured by the size of + the corresponding file). + +.. _ingest-info-contrib-requests: + +Status of the contribution request +---------------------------------- + +The service of the **Master Replication Controller** returns information on a contribution request: + +.. list-table:: + :widths: 10 15 75 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``GET`` + - ``/ingest/trans/contrib/:id`` + - | ``include_warnings=<0|1>`` + | ``include_retries=<0|1>`` + +Where: + +``id`` : *number* + The required unique identifier of the contribution request that was submitted + to a Worker Ingest service earlier. + +``include_warnings`` : *number* = ``0`` + The optional flag telling the service to include warnings into the response. Any value + that is not ``0`` is considered as ``1``, meaning that the warnings should be included. + +``include_retries`` : *number* = ``0`` + The optional flag telling the service to include retries into the response. Any value + that is not ``0`` is considered as ``1``, meaning that the retries should be included. + +The resulting object has the following schema: + +.. code-block:: + + { "contribution" : + } + +Where the detailed description on the enclosed contribution object is provided in the section: + +- :ref:`ingest-trans-management-descriptor-contrib-long` diff --git a/doc/ingest/api/reference/rest/controller/row-counters.rst b/doc/ingest/api/reference/rest/controller/row-counters.rst new file mode 100644 index 000000000..0e2197a3e --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/row-counters.rst @@ -0,0 +1,193 @@ + +Row counters +============ + +.. _ingest-row-counters-deploy: + +Collecting row counters and deploying them at Qserv +--------------------------------------------------- + +The service collects row counters in the specified table and (optionally) deploys the counters +in Qserv to allow optimizations of the relevant queries. The database may or may not be in +the published state at the time of this operation. + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/table-stats`` + +Where the request object has the following schema: + +.. code-block:: + + { "database" : , + "table" : , + "overlap_selector" : , + "force_rescan" : , + "row_counters_state_update_policy" : , + "row_counters_deploy_at_qserv" : + } + +Where: + +``database`` : *string* + The required name of a database affected by the operation. + +``table`` : *string* + The required name of the table for which the row counters are required to be collected. + +``overlap_selector`` : *string* = ``CHUNK_AND_OVERLAP`` + The optional selector for a flavor of the table for which the counters will be collected. + Possible options are: + + - ``CHUNK_AND_OVERLAP``: Both the chunk table itself and the overlap table. + - ``CHUNK``: Only the chunk table. + - ``OVERLAP``: Only the overlap table. + + **Note**: This parameter applies to the *partitioned* tables only. It's ignored for the *regular* (fully replicated) + tables. + +``force_rescan`` : *number* = ``0`` + The optional flag that tells the service to rescan the counters that were recorded earlier. + If the value is set to ``0`` the service will not rescan the counters if the previous version already exists. + If the value is set to ``1`` (or any other number) the service will rescan the counters regardless of + the previous version. + +``row_counters_state_update_policy`` : *string* = ``DISABLED`` + The optional parameter that drives the counters update policy within the persistent + state of the Replication/Ingest system. These are the possible options: + + - ``DISABLED``: The service will collect the counters but it will not update the persistent state. + - ``ENABLED``: Update the counters in the system if the scan was successful and if no counters were + recorded earlier. + - ``FORCED``: Same as ``ENABLED`` except it allows overriding the previous state of the counters. + +``row_counters_deploy_at_qserv`` : *number* = ``0`` + The optional flag tells the service if the counters should be deployed at Qserv. + If the value is set to ``0`` the service will not deploy the counters. Any other value would tell + the service to drop the previous version of the counters (if any existed) in Qserv and update the counters. + +.. _ingest-row-counters-delete: + +Deleting row counters for a table +---------------------------------- + +The service removes the previously collected row counters of the specified table from Qserv and (optionally if requested) +from the Replication system's persistent state. The database may or may not be published at the time of this operation: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``DELETE`` + - ``/ingest/table-stats/:database/:table`` + +Where the service path has the following parameters: + +``database`` : *string* + The name of a database affected by the operation. + +``table`` : *string* + The name of the table for which the row counters are required to be collected. + +The request object sent in the JSON body has the following schema: + +.. code-block:: + + { "overlap_selector" : , + "qserv_only" : + } + +Where: + +``overlap_selector`` : *string* = ``CHUNK_AND_OVERLAP`` + The optional selector for a flavor of the table for which the counters will be collected. + Possible options are: + + - ``CHUNK_AND_OVERLAP``: Both the chunk table itself and the overlap table. + - ``CHUNK``: Only the chunk table. + - ``OVERLAP``: Only the overlap table. + + **Note**: This parameter applies to the *partitioned* tables only. It's ignored for the *regular* (fully replicated) + tables. + +``qserv_only`` : *number* = ``0`` + The optional flag tells the service if the counters should be removed + from Qserv and from the Replication system's persistent state as well: + + - ``0``: Remove the counters from both Qserv and the Replication system's persistent state. + - ``1`` (or any other number which is not ``0``): Remove the counters only from Qserv. + +.. _ingest-row-counters-inspect: + +Inspecting rows counters of a table +----------------------------------- + +The service retturns a status of the previously collected (if any) row counters of the specified table from +the Replication system's persistent state. The database may or may not be published at the time of this operation. + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/ingest/table-stats/:database/:table`` + +Where: + +``database`` : *string* + The name of a database affected by the operation. + +``table`` : *string* + The name of the table for which the row counters are required to be collected. + +The response returned by the service has the following JSON schema: + +.. code-block:: + + { "database" : , + "table" : , + "entries": [ + { "transaction_id" : , + "chunk" : , + "is_overlap" : , + "num_rows" : , + "update_time" : + }, + ... + ] + } + +Where: + +``database`` : *string* + The name of a database that was specified in the service resource path. + +``table`` : *string* + The name of the table was specified in the service resource path. + +``entries`` : *array* + The array of the collected row counters entries. + +``transaction_id`` : *number* + The unique identifier of a *super-transaction*. + +``chunk`` : *number* + The chunk number of the entry. + + **Note**: A value of ``0`` will be reported for the *regular* (fully-replicated) tables. + +``is_overlap`` : *number* + The flag indicates if the entry is reported for the chunk overlap (a value would differ from ``0``) + rather than for the chunk itself (a value would be ``0``). + + **Note**: The parameter should be ignored for the *regular* (fully-replicated) tables. + +``num_rows`` : *number* + The number of rows in in a scope of (``transaction_id``, ``chunk``, ``is_overlap``). + +``update_time`` : *number* + The last time the counter was collected. The time is given as the number of milliseconds since + the UNIX *Epoch* time. \ No newline at end of file diff --git a/doc/ingest/api/reference/rest/controller/table-location.rst b/doc/ingest/api/reference/rest/controller/table-location.rst new file mode 100644 index 000000000..a80c13fa7 --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/table-location.rst @@ -0,0 +1,243 @@ + +.. _table-location: + +Table location services +======================= + +.. _table-location-regular: + +Locate regular tables +--------------------- + +.. warning:: + This service was incorrectly designed by requiring the name of a database (attribute ``database``) be passed + in the ``GET`` request's body. The same problem exists for the alternative method accepting a transaction identifier + (attribute ``transaction_id``). This is not a standard practice. The ``GET`` requests are not supposed to have the body. + The body may be stripped by some HTTP clients or proxies. Both problems will be fixed in the next releases of Qserv + by moving the parameters into the query part of the URL. + +The service returns connection parameters of the Worker Data Ingest Services which are available for ingesting +the regular (fully replicated) tables: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/ingest/regular`` + +Where the request object passed in a request's body has the following schema, in which a client would have to provide the name of a database: + +.. code-block:: + + { "database" : + } + +The database should not be published at a time when the request was being called. Otherwise the service will return an error. + +The service also supports an alternative method accepting a transaction identifier (transactions are always associated with +the corresponding databases): + +.. code-block:: + + { "transaction_id" : + } + +If the transaction identifier was provided then the transaction is required to be in the ``STARTED`` state at the time of a request. +See the section :ref:`ingest-trans-management` for more details on transactions. + +In case of successful completion the service returns the following object: + +.. code-block:: + + { "locations" : [ + { "worker" : , + "host" : , + "host_name" : , + "port" : , + "http_host" : , + "http_host_name" : , + "http_port" : + }, + ... + ] + } + +Where, each object in the array represents a particular worker. See an explanation of the attributes in: + +- :ref:`table-location-connect-params` + +**Note**: If the service will returns an empty array then Qserv is either not properly configured, +or it's not ready to ingest the tables. + +.. _table-location-chunks: + +Allocate/locate chunks of the partitioned tables +------------------------------------------------ + +The current implementation of the system offers two services for allocating (or determining locations of existing) chunks: + +- :ref:`table-location-chunks-one` +- :ref:`table-location-chunks-many` + +Both techniques are explained in the current section. The choice of a particular technique depends on the requirements +of a workflow. However, the second service is recommended as it's more efficient in allocating large quanities of chunks. + +Also note, that once a chunk is assigned (allocated) to a particular worker node all subsequent requests for the chunk are guaranteed +to return the same name of a worker as a location of the chunk. Making multiple requests for the same chunk is safe. Chunk allocation +requests require a valid super-transaction in the ``STARTED`` state. See the section :ref:`ingest-trans-management` for more details on transactions. + +.. _table-location-chunks-one: + +Single chunk allocation +~~~~~~~~~~~~~~~~~~~~~~~ + +The following service is meant to be used for a single chunk allocation/location: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/chunk`` + +Where the request object has the following schema, in which a client would have to provide the name of a database: + +.. code-block:: + + { "database" : , + "chunk" : + } + +The service also supports an alternative method accepting a transaction identifier (transactions are always associated with the corresponding databases): + +.. code-block:: + + { "transaction_id" : , + "chunk" : + } + +If a request succeeded, the System would respond with the following JSON object: + +.. code-block:: + + { "locations" : [ + { "worker" : , + "host" : , + "host_name" : , + "port" : , + "http_host" : , + "http_host_name" : , + "http_port" : + }, + ... + ] + } + +Where, the object represents a worker where the Ingest system requests the workflow to forward the chunk contributions. +See an explanation of the attributes in: + +- :ref:`table-location-connect-params` + +.. _table-location-chunks-many: + +Multiple chunks allocation +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For allocating multiple chunks one would have to use the following service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/chunks`` + +Where the request object has the following schema, in which a client would have to provide the name of a database: + +.. code-block:: + + { "database" : , + "chunks" : [, , ... ] + } + +Like the above-explained case of the single chunk allocation service, this one also supports an alternative method accepting +a transaction identifier (transactions are always associated with the corresponding databases): + +.. code-block:: + + { "transaction_id" : , + "chunks" : [, , ... ] + } + +**Note** the difference in the object schema - unlike the single-chunk allocator, this one expects an array of chunk numbers. + +The resulting object has the following schema: + +.. code-block:: + + { "locations" : [ + { "chunk" : , + "worker" : , + "host" : , + "host_name" : , + "port" : , + "http_host" : , + "http_host_name" : , + "http_port" : + }, + ... + ] + } + +Where, each object in the array represents a particular worker. See an explanation of the attributes in: + +- :ref:`table-location-connect-params` + +.. _table-location-connect-params: + +Connection parameters of the workers +------------------------------------- + +.. warning:: + In the current implementation of the Ingest system, values of the hostname attributes ``host_name`` and ``http_host_name`` are captured + by the worker services themselves. The names may not be in the FQDN format. Therefore this information has to be used with caution and + only in those contexts where the reported names could be reliably mapped to the external FQDN or IP addresses of the corresponding hosts + (or Kubernetes *pods*). + +Attributes of the returned object are: + +``chunk`` : *number* + The unique identifier of the chunk in Qserv. + + **Note**: This attribute is reported in the chunk location/allocation services: + + - :ref:`table-location-chunks` + +``worker`` : *string* + The unique identifier of the worker in Qserv. + + **Note**: The worker's identifier is not the same as the worker's host name. + +``host`` : *string* + The IP address of the worker's Ingest service that supports the proprietary binary protocol. + +``host_name`` : *string* + The DNS name of the worker's Ingest service that supports the proprietary binary protocol. + +``port`` : *number* + The port number of the worker's Ingest service that supports the proprietary binary protocol. This service requires + the content of an input file be sent directly to the service client. The Replication/Ingest system provides + an application :ref:`ingest-tools-qserv-replica-file` that relies on this protocol. + +``http_host`` : *string* + The IP address of the worker's Ingest service that supports the HTTP protocol. + +``http_host_name`` : *string* + The DNS name of the worker's Ingest service that supports the HTTP protocol. + +``http_port`` : *number* + The port number of the worker's Ingest service that supports the HTTP protocol. The REST server that's placed + in front of the service allows ingesting a single file from a variety of external sources, such as the locally + mounted (at the worker's host) filesystem, or a remote object store. It's also possible to push the content of a file + in the request body ether as teh JSON object or as a binary stream (``multipart/form-data``). diff --git a/doc/ingest/api/reference/rest/controller/trans-management.rst b/doc/ingest/api/reference/rest/controller/trans-management.rst new file mode 100644 index 000000000..193e9e084 --- /dev/null +++ b/doc/ingest/api/reference/rest/controller/trans-management.rst @@ -0,0 +1,794 @@ +.. _ingest-trans-management: + +Transaction management +====================== + +.. note:: + + - The transaction management services which modify a state of transactions are available only to the authorized users. + The authorization is based on the authentication key. The key is used to prevent unauthorized access to the services. + + - The schema of the JSON object returned for each transaction is the same for all services in the group. + The schema is described in the section: + + - :ref:`ingest-trans-management-descriptor` + +.. _ingest-trans-management-status: + +Status of a transaction +----------------------- + +There are two services in this group. They are documented in the dedicated sections below. + +.. _ingest-trans-management-status-many: + +Database transactions +^^^^^^^^^^^^^^^^^^^^^ + +The service returns the information on many transactions in a scope of a database or databases selected via optional +filters passed via the request's query. The service is meant to be used by workflows for monitoring the status of +transactions and for debugging purposes. To see an actual progress of a transaction (e.g. to see the contributions +loaded into the destination table) a workflow should use the service: :ref:`ingest-trans-management-status-one`. + +.. list-table:: + :widths: 10 15 75 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``GET`` + - ``/ingest/trans`` + - | ``database=`` + | ``family=`` + | ``all_databases={0|1}`` + | ``is_published={0|1}`` + | ``include_context={0|1}`` + | ``contrib={0|1}`` + | ``contrib_long={0|1}`` + | ``include_log={0|1}`` + | ``include_warnings={0|1}`` + | ``include_retries={0|1}`` + +Where: + +``database`` : *string* = ``""`` + The optional name of the database to filter the transactions by. If the parameter is present and if + it's not empty then attributes ``family``, ``all_databases`` and ``is_published`` are ignored. + +``family`` : *string* = ``""`` + The optional name of the database family. If the parameter is present and if + it's not empty then a scope of a request will be narrowed to databases - members of the given family. + Otherwise all databases regardless of their family membership will be considered. + + **Notes**: + + - The parameter is ignored if the parameter ``database`` is present. + - The final selection of the databases is also conditioned by the values of the optional parameters + ``all_databases`` and ``is_published``. See the description of the parameters for more details. + +``all_databases`` : *number* = ``0`` + The optional flag which is used for further filtering of databases selected by the parameter family. + A value of ``0`` tells the service that the parameter ``is_published`` should be used to further filter database + selection to the desired subset. Any other value would mean no additional filters (hence ignoring ``is_published``), + hence including databases selected by the parameter family. + + **Note**: The parameter is ignored if the parameter ``database`` is present. + +``is_published`` : *number* = ``0`` + The optional flag is used only if enabled by setting the previous parameter ``all_databases=0``. + A value of ``0`` tells the service to narrow the database selection to databases which are not *published*. + Any other value would select the *published* databases. + + **Note**: The parameter is ignored if the parameter ``database`` is present or when ``all_databases=1``. + +``include_context`` : *number* = ``0`` + The optional flag tells the service to include the transaction context object in the report for each transaction. + See the documentation on services :ref:`ingest-trans-management-start` or :ref:`ingest-trans-management-end` for further + details. + + .. warning:: + + Potentially, each context object could be as large as **16 MB**. Enable this option only if you really need + to see contexts for all transactions. Otherwise use an alternative (single transaction) request to pull one + transaction at a time. + +``contrib`` : *number* = ``0`` + The optional flag tells the service whether the transaction contribution objects should be included + into the report. See details on this flag in the dedicated section below. + + .. warning:: + + Even though individual contribution objects aren't large, the total number of contribution ingested + in a scope of each transaction (and all transactions of a database, etc.) could be quite large. + This would result in a significant emount of data reported by the service. In extreme cases, the response + object could be **1 GB** or larger. Enable this option only if you really need to see contributions + for selected transactions. Otherwise use an alternative (single transaction) request to pull one transaction + at a time: :ref:`ingest-trans-management-status-one`. + +``contrib_long`` : *number* = ``0`` + This optional flag is considered only if ``contrib=1``. Setting a value of the flag to any value other + than ``0`` will result in returning detailed info on the contributions. Otherwise (if a value of the parameter + is set to ``0``) only the summary report on contributions will be returned. + +``include_log`` : *number* = ``0`` + The optional flag tells the service to include the transaction log in the report for each transaction. + The log is a list of events that were generated by the system in response to the transaction management + reequests. Each entry in the log is a JSON object that includes the timestamp of the event, the event type, + etc. See **TODO** for the details on the log entries. + +``include_warnings`` : *number* = ``0`` + The optional flag, if set to any value that differs from ``0``, tells the service to include MySQL warnings + captured when loading contributions into the destination table. Warnings are reported in a context of + contributiond should they be allow in the report. + + **Note**: The parameter is ignored if ``contrib=0`` or if ``contrib_long=0``. + +``include_retries`` : *number* = ``0`` + The optional flag, if set to any value that differs from ``0``, tells the service to include the information + on the retries to load contributions that were made during the transaction. Retries are reported in a context of + contributiond should they be allow in the report. + + **Note**: The parameter is ignored if ``contrib=0`` or if ``contrib_long=0``. + +This is an example of the most typical request to the service for pulling info on all transactions of ``gaia_edr3``: + +.. code-block:: bash + + curl -X GET "http://localhost:25081/ingest/trans?database=gaia_edr3" + +The service will return a JSON object with the summary report on the transactions in the following JSON object: + +.. code-block:: json + + { + "success" : 1, + "warning" : "No version number was provided in the request's query.", + "error" : "", + "error_ext" : {}, + "databases" : { + "gaia_edr3" : { + "is_published" : 0, + "num_chunks" : 1558, + "transactions" : [ + { + "database" : "gaia_edr3", + "log" : [], + "start_time" : 1726026383559, + "end_time" : 0, + "begin_time" : 1726026383558, + "id" : 1632, + "state" : "STARTED", + "transition_time" : 0, + "context" : {} + }, + { + "end_time" : 1727826539501, + "context" : {}, + "begin_time" : 1726026383552, + "log" : [], + "transition_time" : 1727826539218, + "database" : "gaia_edr3", + "start_time" : 1726026383553, + "state" : "ABORTED", + "id" : 1631 + }, + { + "database" : "gaia_edr3", + "end_time" : 1727826728260, + "id" : 1630, + "transition_time" : 1727826728259, + "start_time" : 1726026383547, + "begin_time" : 1726026383546, + "log" : [], + "state" : "FINISHED", + "context" : {} + }, + +**Note**: that the report doesn't have any entries for the contributions. The contributions are not included in the report since +the parameter ``contrib`` was not set to ``1``. The log entries are also missing since the parameter ``include_log`` was not set to ``1``. +Also, the transaction context objects are not included in the report since the parameter ``include_context`` was not set to ``1``. + +.. _ingest-trans-management-status-one: + +Single transaction finder +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The service returns the information on a single transaction identified by its unique identifier ```` passed +via the request's query: + +.. list-table:: + :widths: 10 15 75 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``GET`` + - ``/ingest/trans/`` + - | ``include_context={0|1}`` + | ``contrib={0|1}`` + | ``contrib_long={0|1}`` + | ``include_log={0|1}`` + | ``include_warnings={0|1}`` + | ``include_retries={0|1}`` + +Where the parameters are the same as for the service :ref:`ingest-trans-management-status-many`. + +This is an example of using the service for pulling info on a transaction ``1630`` and obtaining +the summary report on contributions and the transaction context: + +.. code-block:: bash + + curl -X GET "http://localhost:25881/ingest/trans/1630?contrib=1" + +The service returns a JSON object that has the following structure (the report is truncated by removing stats +on all workers but ``db12`` for brevity): + +.. code-block:: json + + { + "databases" : { + "gaia_edr3" : { + "num_chunks" : 1558, + "is_published" : 0, + "transactions" : [ + { + "id" : 1630, + "database" : "gaia_edr3", + "end_time" : 1727826728260, + "start_time" : 1726026383547, + "begin_time" : 1726026383546, + "transition_time" : 1727826728259, + "log" : [], + "context" : {}, + "state" : "FINISHED", + "contrib" : { + "summary" : { + "num_failed_retries" : 0, + "num_chunk_files" : 156, + "last_contrib_end" : 1726026945059, + "num_regular_files" : 0, + "num_rows" : 223420722, + "table" : { + "gaia_source" : { + "num_failed_retries" : 0, + "overlap" : { + "num_rows" : 6391934, + "num_warnings" : 0, + "num_rows_loaded" : 6391934, + "data_size_gb" : 5.97671127319336, + "num_files" : 155, + "num_failed_retries" : 0 + }, + "num_files" : 156, + "num_rows_loaded" : 217028788, + "num_warnings" : 0, + "data_size_gb" : 201.872497558594, + "num_rows" : 217028788 + } + }, + "num_workers" : 9, + "first_contrib_begin" : 1726026383616, + "num_rows_loaded" : 223420722, + "worker" : { + "db12" : { + "num_failed_retries" : 0, + "num_regular_files" : 0, + "num_chunk_files" : 18, + "num_rows_loaded" : 52289369, + "num_warnings" : 0, + "data_size_gb" : 48.6947402954102, + "num_chunk_overlap_files" : 23, + "num_rows" : 52289369 + }, + }, + "num_warnings" : 0, + "num_files_by_status" : { + "LOAD_FAILED" : 0, + "IN_PROGRESS" : 0, + "CANCELLED" : 0, + "CREATE_FAILED" : 0, + "READ_FAILED" : 0, + "FINISHED" : 311, + "START_FAILED" : 0 + }, + "num_chunk_overlap_files" : 155, + "data_size_gb" : 207.849166870117 + }, + "files" : [] + } + }, + +**Note**: the report doesn't have any entries for individual contributions in the attribute ``files``. Only the summary info +in the attribute ``summary`` is provided. + + +.. _ingest-trans-management-start: + +Start a transaction +------------------- + +Transactions are started by this service: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/trans`` + +The following JSON object is required to be sent in the body of a request: + +.. code-block:: + + { "database" : , + "context" : + } + +Where: + +``database`` : *string* + The required name of the database definintg a scope of the new transaction. + +``context`` : *object* = ``{}`` + The optional arbitrary workflow-defined object to be stored in the persistet state of + the Ingest System for the transaction. It's up to the workflow to decide what to store in the object. + For exaqmple, this information could be used later for recovering from errors during the ingest, for + general bookkeeping, data provenance, visualization purposes, etc. A value of this attribute, if provided, + must be a valid JSON object. The object could be empty. + + **Note**: The current implementation of the Qserv Ingest system limits the size of the context object by **16 MB**. + +In case of successfull completion of a request (see :ref:`ingest-general-error-reporting`) the service will return +the JSON object with a description of the new transaction: + +.. code-block:: + + { + "databases" : { + : { + "num_chunks" : , + "transactions" : [ + { + "begin_time" : , + "context" : {...}, + "database" : , + "end_time" : , + "id" : , + "log" : [], + "start_time" : , + "state" : "STARTED", + "transition_time" : + } + ] + } + }, + "success" : , + ... + } + } + +Where the attribute ``id`` representing a unique identifier of the transaction is the most important attribute +found in the object. A alue of the identifier needs to be memorized by a workflow to be used in the subsequent +requests to the transaction management services. + +The attribute ``start_time`` will be set to the current time in milliseconds since the UNIX *Epoch*. +And the state of the new transaction will be set to ``STARTED``. The ``end_time`` will be ``0``. A value of +the attribute ``context`` will be the same as it was provided on the input to the service, or the default +value if none was provided. + +.. _ingest-trans-management-end: + +Commit or abort a transaction +----------------------------- + +.. note:: + + - The current design of the service is not correct. The ``abort`` flag should be passed in the request's query + rather than in the body of the request. The service will be updated in the future to reflect the correct design. + + +Transactions are aborted or committed by the following service: + +.. list-table:: + :widths: 10 25 65 + :header-rows: 1 + + * - method + - service + - query parameters + * - ``PUT`` + - ``/ingest/trans/:id`` + - ``abort=<0|1>`` + +A unique identifier of the transaction is passed into the service in the resource's path parameter ``id``. +The only mandatory parameter of the request query is ``abort``. The value of the parameter is ``0`` to tell the services +that the transaction has to be committed normally. Any other number will be interpreted as a request to abort the transaction. + +Other parameters defining a request are passed via the request's body: + +.. code-block:: + + { + "context" : + } + +Where: + +``context`` : *object* = ``{}`` + The optional arbitrary workflow-defined object to be stored in the persistet state of + the Ingest System for the transaction. It's up to the workflow to decide what to store in the object. + For exaqmple, this information could be used later for recovering from errors during the ingest, for + general bookkeeping, data provenance, visualization purposes, etc. A value of this attribute, if provided, + must be a valid JSON object. The object could be empty. + + **Notes**: + + - A value provided in the attribute will replace the initial value specified (if any) at the transaction + start time (see :ref:`ingest-trans-management-start`). + - The current implementation of the Qserv Ingest system limits the size of the context object by **16 MB**. + +Upon successful completion of either request (see :ref:`ingest-general-error-reporting`) the service would return an updated +status of the transaction in a JSON object as it was explained in the section :ref:`ingest-trans-management-start`. + +State transitions of the transactions: + +- Aborted transactions will end up in the ``ABORTED`` state. +- Transactions that were committed will end up in the ``FINISHED`` state. +- In case of any problems encountered during an attempt to end a transaction, other states may be also reported + by the service. + +It's also safe to repeat either of the requests. The service will complain if the transaction won't be in +the ``STARTED`` state at a time when the request was received by the service. + +More information on the statuses of transactions can be found at: + +- :ref:`ingest-trans-management-status` + +.. _ingest-trans-management-descriptor: + +Transaction descriptor +---------------------- + +.. note:: + + This section uses a database ``gaia_edr3`` and transaction ``1630`` as an example. + +The content of a JSON object returned by the services varies depending on a presense of the optional parameters: + +- ``include_context={0|1}`` +- ``contrib={0|1}`` +- ``contrib_long={0|1}`` +- ``include_log={0|1}`` +- ``include_warnings={0|1}`` +- ``include_retries={0|1}`` + +Subsections below describe the gradual expantion of the JSON object returned by the services as the optional parameters +are set to ``1``. + +.. _ingest-trans-management-descriptor-short: + +Shortest form +^^^^^^^^^^^^^ + +The shortest form of the JSON object returned by the services when all optional parameters are set to ``0`` is: + +.. code-block:: + + { + "databases" : { + "gaia_edr3" : { + "is_published" : <0|1>, + "num_chunks" : , + "transactions" : [ + { + "id" : 1630, + "database" : "gaia_edr3", + "begin_time" : , + "start_time" : , + "end_time" : , + "transition_time" : , + "state" : , + "context" : , + "log" : + }, + +Where: + +``is_published`` : *number* + The flag tells whether the database is *published* or not. + +``num_chunks`` : *number* + The total number of chunks in the database, regardless if any contributons were made into the chunks + in a context of any transaction. Chunks need to be registered in Qserv before the corresponding MySQL tables + can be populated with data. This information is meant to be used for the monitoring and Q&A purposes. + +``id`` : *number* + The unique identifier of the transaction. + +``database`` : *string* + The name of the database the transaction is associated with. + +``begin_time`` : *number* + The timestamp of the transaction creation in milliseconds since the UNIX *Epoch*. The value is + set by the service when the transaction is registered in the system and assigned + a state ``IS_STARTING``. The value is guaranteed to be not ``0``. + +``start_time`` : *number* + The timestamp of the transaction start in milliseconds since the UNIX *Epoch*. The value is + set by the service when the transaction is started (gets into the ``STARTED`` state). + The value is ``0`` while while teh transaction is still in a state ``IS_STARTING``. + +``end_time`` : *number* + The timestamp of the transaction end in milliseconds since the UNIX *Epoch*. The value is + set by the service when the transaction is ended (committed, aborted or failed). A value + of the atrribite is ``0`` if the transaction is still active. + +``transition_time`` : *number* + The timestamp of the last state transition in milliseconds since the UNIX *Epoch*. The value is + set by the service when the transaction gets into states ``IS_FINISHING`` (the committing process + was initiated) or ``IS_ABORTING`` (the aborting process was initiated). The value would be set + to ``0`` before that. + +``state`` : *string* + The current state of the transaction. The possible values and their meanings are explained in + the dedicated section: + + - :ref:`ingest-trans-management-states` + +``context`` : *object* + The object that was provided by a workflow at the transaction start time, or updated during transaction + commit/abort time. The object could be empty. The object could be used for the recovery from errors during + the ingest, for general bookkeeping, data provenance, visualization purposes, etc. + +``log`` : *array* + The array of log entries. Each entry is a JSON object that has the following attributes: + + - ``id`` : *number* - The unique identifier of the log entry. + - ``transaction_state`` *string* : - The state of the transaction at the time the log entry was generated. + - ``name`` : *string* - The name of the event that triggered the log entry. + - ``time`` : *number* - The timestamp of the event in milliseconds since the UNIX *Epoch*. + - ``data`` : *object* - The data associated with the event. + +.. _ingest-trans-management-descriptor-contrib-summary: + +With a summary of contributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Setting the query parameters to ``contrib=1`` (regardless if ``contrib_long`` is set to ``0`` or ``1``) +will result in expaning the ``transaction`` block with the ``summary`` object. The object will +include the summary info on all contributions made in a sewcope of the transaction. + +The following object illustrates the idea (where most of the previous explained attributes and all +worker-level stats but the one for ``db12`` are omitted for brevity): + +.. code-block:: + + "transactions" : [ + { + "contrib" : { + "summary" : { + "first_contrib_begin" : 1726026383616, + "last_contrib_end" : 1726026945059, + "num_rows" : 223420722, + "num_rows_loaded" : 223420722, + "num_regular_files" : 0, + "num_chunk_files" : 156, + "num_failed_retries" : 0, + "num_workers" : 9, + "table" : { + "gaia_source" : { + "data_size_gb" : 201.872497558594, + "num_rows_loaded" : 217028788, + "num_rows" : 217028788, + "num_files" : 156, + "num_failed_retries" : 0, + "num_warnings" : 0 + "overlap" : { + "data_size_gb" : 5.97671127319336, + "num_rows" : 6391934, + "num_rows_loaded" : 6391934, + "num_files" : 155, + "num_failed_retries" : 0, + "num_warnings" : 0 + } + } + }, + "worker" : { + "db12" : { + "data_size_gb" : 48.6947402954102, + "num_rows" : 52289369, + "num_rows_loaded" : 52289369, + "num_regular_files" : 0, + "num_chunk_files" : 18, + "num_chunk_overlap_files" : 23, + "num_failed_retries" : 0, + "num_warnings" : 0, + }, + } + } + +The ``summary`` object includes 3 sets of attributes: + +- The general stats on the contributions made in a scope of the transaction. +- The stats on the contributions made into the table ``gaia_source`` across all workers. +- The stats on the contributions made into into tables by the worker ``db12``. + +These are the general (transaction-level) stats: + +``first_contrib_begin`` : *number* + The timestamp of the first contribution in milliseconds since the UNIX *Epoch*. This is the time when a processing of the contribution started. + +``last_contrib_end`` : *number* + The timestamp of the last contribution in milliseconds since the UNIX *Epoch*. This is the time when a processing of the contribution ended. + +``num_rows`` : *number* + The total number of rows parsed in all input contributions made in a scope of the transaction. + +``num_rows_loaded`` : *number* + The total number of rows that were actually loaded into the destination table(s) in all contributions made in a scope of the transaction. + + **Note**: Normally the number of rows loaded should be equal to the number of rows parsed. If the numbers differ it means that some + rows were rejected during the ingest process. The workflow should be always monitoring any mismatches in these values and trigger alerts. + +``num_regular_files`` : *number* + The total number of regular files (not chunk files) parsed in all input contributions. + +``num_chunk_files`` : *number* + The total number of chunk files parsed in all input contributions. + +``num_failed_retries`` : *number* + The total number of retries that failed during the ingest process. + + **Note**: In most cases it's okay that the number of failed retries is not zero. The system is designed to retry + the ingest of the failed contributions. A problem is when the number of such failures detected in the scope of + a single contribution exceeds a limit set at the Ingest system. The workflow should be always monitoring + the number of failed retries and trigger alerts if the number is too high. + +``num_workers`` : *number* + The total number of workers that were involved in the ingest process. + + +.. _ingest-trans-management-descriptor-contrib-long: + +With detailed info on contributions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Setting the query parameters to ``contrib=1`` and ``contrib_long=1`` will result in expaning the ``contrib`` object +with the ``files`` array. Each entry (JSON object) in the array represents a contribution. The objects provides +the detailed info on all contributions made in a scope of the transaction: + +.. code-block:: + + "transactions" : [ + { + "contrib" : { + "files" : [ + , + ... + + ] + } + } + ] + +The schema of the contribution objects is covered by: + +- :ref:`ingest-worker-contrib-descriptor` + +**Note**: Extended info on warnings and retries posted during contribution loading are still disabled in this case. +To enable warnings use the parameter ``include_warnings=1``. To enable retries use the parameter ``include_retries=1``. + +.. _ingest-trans-management-states: + +Transaction states +------------------ + +Transactions have well-defined states and the state transition algorithm. Normally, Ingest System moves a transaction +from one state to another in response the explicit transaction management requests made by a workflow. In some cases +the Replication/Ingest system may also change the states. + +.. image:: /_static/ingest-transaction-fsm.png + :target: ../../../../../_images/ingest-transaction-fsm.png + :alt: State Transition Diagram + +A few comments on the diagram: + +- States ``STARTED``, ``FINISHED`` and ``ABORTED`` which are shown in grey boxes are the *intended* stable states of + a transaction. These states are *expected* to be reached by the transactin management requests. +- States ``START_FAILED``, ``FINISH_FAILED`` and ``ABORT_FAILED`` which are shown in red are the *unintended* intermediate + stable states of a transaction. the transaction gets into these states when the system encounters problems during + processing of the corresponding transaction management requests. Transitions into these states are shown as red dashed lines. + The only way to get out of these states is to fix the underlying problem (could be a problem with an infrastructure, data + or bugs in the Inges system or Qserv) and issue another transaction management request to *abort* the transaction. + + .. hint:: + + - In many cases a reason of the failure is reported in the response object returned by the corresponding transaction + management request. + +- States ``IS_STARTING``, ``IS_FINISHING`` and ``IS_ABORTING`` are the *transient* unstable states which are meant to be + passed through by a transaction on its way to the desired *intended* stable state. The states are used by the system + to indicate a significant (and often - lengthy) transformation of the data or metadata triggered by the state transition + of the transaction. + + - In some cases the transaction may be staying on one of these states for a while. For example, when the *commit* request + was initiated for the transaction and if the database options specified by a workflow require the system to build + the *director* index of the *director* table at the *commit* time of the transactions. The system will keep + the transaction in the state ``IS_FINISHING`` until the index is built. The state will be changed to ``FINISHED`` + once the index is built successfully. + + - It's possible that a transaction may get stuck in one of these *transient* states. The only scenario when this may + happen in the current implementation would be when the Master Replication Controller gets restarted while the transaction + is in one of these states. The system will not be able to resume the transaction processing after the restart. + This limitation will be addresed in the future. + + +The following table explains possible state transitions of a transaction: + +.. list-table:: + :widths: 10 80 10 + :header-rows: 1 + + * - state + - description + - next states + * - ``IS_STARTING`` + - The initial (transient) state assigned to a transaction right after it's registered in the system + in response to a request to start a transaction: :ref:`ingest-trans-management-start`. + This transient state that should be changed to ``STARTED`` or ``START_FAILED``. + The former state is assigned to a transaction that was successfully started, the latter + to a transaction that failed to start. + + - | ``START`` + | ``START_FAILED`` + + * - ``STARTED`` + - The active state of a transaction that is ready to accept data ingest requests. + When the system receives a request to commit or abort the transaction (see :ref:`ingest-trans-management-end`) + the state would transition to the corresponding transient states ``IS_FINISHING`` or ``IS_ABORTING``. + - | ``IS_FINISHING`` + | ``IS_ABORTING`` + + * - ``IS_FINISHING`` + - The transient state assigned to a transaction that is in the process of being committed. + Depending on the database options specified by a workflow, the transaction may stay in this state + for a while. + The state will change to ``FINISHED`` in case of the succesfull completion of a request, or it may + land in in the ``FINISH_FAILED`` state in case of any problems en countered during the request + execution. A transaction may also get into the ``IS_ABORTING`` state if a workflow issues the abort + request while the transaction is being finished. + + - | ``FINISHED`` + | ``FINISH_FAILED`` + | ``IS_ABORTING`` + + * - ``IS_ABORTING`` + - The transitional state triggered by the transaction abort request (see :ref:`ingest-trans-management-end`). + - | ``ABORTED`` + | ``ABORT_FAILED`` + + * - ``FINISHED`` + - The final state of a transaction that was successfully committed. + - + + * - ``ABORTED`` + - The final state of a transaction that was successfully aborted. + - + + * - ``START_FAILED`` + - The (inactive) state of a transaction that failed to start. The state allows + a workflow to initiate the transaction abort request. + - ``IS_ABORTING`` + + * - ``FINISH_FAILED`` + - The (inactive) state of a transaction that failed to to be commited. The state allows + a workflow to initiate the transaction abort request. + - ``IS_ABORTING`` + + * - ``ABORT_FAILED`` + - The (inactive) state of a transaction that failed to to be aborted. The state allows + a workflow to initiate another transaction abort request (or requests). + - ``IS_ABORTING`` + diff --git a/doc/ingest/api/reference/rest/general.rst b/doc/ingest/api/reference/rest/general.rst new file mode 100644 index 000000000..85603dd92 --- /dev/null +++ b/doc/ingest/api/reference/rest/general.rst @@ -0,0 +1,314 @@ +General guidelines +================== + +.. _ingest-general-request-headers: + +Request headers +--------------- + +All (but those where it's explicitly stated otherwise) services accepting requests send with ``POST``, ``PUT`` or ``DELETE`` +methods require the following HTTP header to be sent in the request's body along with the JSON request object: + +.. code-block:: + + Content-Type: application/json + +When requests are sent using the command line application ``curl`` then the following option must be used: + +.. code-block:: bash + + curl -X -H "Content-Type: application/json" + +In this case a JSON object can be specified using one of the following methods: + +.. code-block:: bash + + echo '{...}' | curl -X -H
    -d@- + curl -X -H
    -d '{...}' + +Where ``{...}`` represents a JSON object with details of the request. The object may not be required for some requests. +Specific requirements for this will be mentioned in each service. If the object is not required for a for particular +request then the body is allowed to be empty, or it could be an empty JSON object ``{}``. + +All (no exception) services return results and errors as JSON objects as explained in the next subsection below. + +.. _ingest-general-error-reporting: + +Error reporting when calling the services +----------------------------------------- + +.. note: + + The error reporting mechanism implemented in the System serves as a foundation for building reliable workflows. + +All services explained in the document adhere to the usual conventions adopted by the Web community for designing and using the REST APIs. In particular, HTTP code 200 is returned if a request is well-formed and accepted by the corresponding service. Any other code shall be treated as an error. However, the implementation of the System further extends the error reporting mechanism by guaranteeing that all services did the fine-grain error reporting in the response objects. All services of the API are guaranteed to return an JSON object if the HTTP code is 200. The objects would have the following mandatory attributes (other attributes depend on a request): + +.. code-block:: + + { "success" : , + "error" : , + "error_ext" : , + ... + } + +**Note**: depending on the service, additional attributes may be present in the response object. + +Therefore, even if a request is completed with HTTP code ``200``, a client (a workflow) must inspect the above-mentioned +fields in the returned object. These are the rules for inspecting the status attributes: + +- Successful completion of a request is indicated by having success=1 in the response. In these cases, the other + two fields should be ignored. +- Otherwise, a human-readable explanation of a problem would be found in the error field. +- Request-specific extended information on errors is optionally provided in the error_ext field. + +Optional warnings +^^^^^^^^^^^^^^^^^ + +**Note**: Warnings were introduced as of version ``12`` of the API. + +REST services may also return the optional attribute ``warning`` a caller about potential problems with a request. +The very presence of such a warning doesn't necessarily mean that the request failed. Users are still required +to use the above-described error reporting mechanism for inspecting the completion status of requests. +Warnings carry the additional information that may be present in any response regardless if it succeeded or not. +It's up to a user to interpret this information based on a specific request and the context it was made. + +Here is what to expect within the response object if the warning was reported: + +.. code-block:: + + { "success" : , + "warning" : , + ... + } + +.. _ingest-general-auth: + +Authorization and authentication +-------------------------------- + +All services accepting requests sent with ``POST``, ``PUT`` or ``DELETE`` methods require the following attribute +to be present in the request object: + +``auth_key`` : *string* + The authentication key that is required for an operation. The key is used to prevent unauthorized access to the service. + +Certain requests (where it's specificly stated by the description of the service) may require the elevated privileges +to be specified in the following attribute: + +``admin_auth_key`` : *string* + The Administrator-level authentication key that is required for an operation. The key is used to prevent unauthorized + access to the service that will modify existing data visible to Qserv users. + +.. _ingest-general-versioning: + +Protocol Versioning +------------------- + +The API adheres to the optional version control mechanism introduced in: + +- https://rubinobs.atlassian.net/browse/DM-35456 + +Workflow developers are encouraged to use the mechanism to reinforce the integrity of the applications. + +There are two ways the workflows can use the version numbers: + +- *pull mode*: Ask the Replication Controller explicitly what version it implements and cross-check the returned + version versus a number expected by the application. +- *push mode*: Pass the expected version number as a parameter when calling services and let + the services verify if that version matches one of the frontend implementations. + +Workflow developers are free to use neither, either of two, or both methods of reinforcing their applications. + +Pull mode +^^^^^^^^^ + +To support the first scenario, the API provides a special metadata service that will return +the version number (along with some other information on the frontend): + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/meta/version`` + +The request object for this request is not required, or it could be an empty JSON object ``{}``. +In case of its successful completion, the service will return a JSON object that will include +the following attributes (along with the other standard attributed that are used for error reporting): + +.. code-block:: + + { "kind" : , + "name" : , + "id" : , + "instance_id" : , + "version" : , + "database_schema_version" : , + "success" : , + "warning" : , + "error" : , + "error_ext" : + } + +Where, the service-specific attributes are: + +``kind`` : *string* + The name of the service. The following name is always reported: + + .. code-block:: + + replication-controller + +``name`` : *string* + The unique name of the frontend within a given Qserv. The current implementation will always return: + + .. code-block:: + + http + +``id`` : *number* + A unique identifier of the Replication Controller. The number returned here may vary. + +``instance_id`` : *string* + An identifier of the Qserv instance. A value of the attribute depends on a particular deployment of Qserv. + +``version`` : *number* + The current version number of the API. + +``database_schema_version`` : *number* + The schema version number of the Replication System's Database. + +Example: + +.. code-block:: json + + { "kind" : "replication-controller", + "id" : "9037c818-4820-4b5e-9219-edbf971823b2", + "instance_id" : "qserv_proj", + "version" : 27, + "database_schema_version" : 14, + "success" : 1, + "error" : "", + "error_ext" : {}, + "warning" : "" + } + +Push mode +^^^^^^^^^ + +In the case of the second scenario, an application will pass the desired version number as +a request parameter. The number would be a part of the request's query for the method. For example, +the following request for checking the status of the ongoing query might look like this: + +.. code-block:: bash + + curl 'http://localhost:25004/trans/contrib/1234?version=35' -X GET + +For other HTTP methods used by the API, the number is required to be provided within the body +of a request as shown below: + +.. code-block:: bash + + curl 'http://localhost:25004/trans/contrib' -X POST \ + -H 'Content-Type: application/json' \ + -d'{"version":35, ..."}' + +If the number does not match expectations, such a request will fail and the service return the following +response. Here is an example of what will happen if the wrong version number ``29`` is specified instead +of ``35`` (as per the current version of the API): + +.. code-block:: json + + { "success" : 0, + "error" : "The requested version 29 of the API is not in the range supported by the service.", + "error_ext": { + "max_version" : 35, + "min_version" : 32 + }, + "warning" : "" + } + +.. _ingest-general-binary-encoding: + +Binary encoding of the data in JSON +----------------------------------- + +The API supports encoding of the binary data into JSON. The encoding specification is provided as a parameter +``binary_encoding`` when calling several services. The parameter may be optional and if not provided, the default +value is ``hex``. The parameter is used by the services and by the client applications in two different ways: + +- When a client is sending data to a service, the client is required to tell the service how the binary data are encoded. + The service would invoke the corresponding decoding algorithm to decode the data into the original representation. + +- A service designed for sending data to a client is expected to get the name of the desired encoding + algorithm in a request to the service. The service would then encode the binary data into the JSON object + using the specified algorithm. + +The following options for the values of the parameter are allowed in the current version of the API: + +- ``hex`` - for serializing each byte into the hexadecimal format of 2 ASCII characters per each byte + of the binary data, where the encoded characters will be in a range of ``0 .. F``. In this case, + the encoded value will be packaged into the JSON string. +- ``b64`` - for serializing bytes into a string using the ``Base64`` algorithm with padding (to ensure 4-byte alignment). +- ``array`` - for serializing bytes into the JSON array of numbers in a range of ``0 .. 255``. + +Here is an example of the same sequence of 4-bytes encoded into the hexadecimal format: + +.. code-block:: + + 0A11FFD2 + +The array representation of the same binary sequence would look like this: + +.. code-block:: json + + [10,17,255,210] + +MySQL types (regardless of the case) that include the following keywords are treated as binary: + +.. code-block:: sql + + BIT + BINARY + BLOB + +For example, these are the binary types: + +.. code-block:: sql + + BIT(1) + BINARY(8) + VARBINARY(16) + TINYBLOB + BLOB + MEDIUMBLOB + LONGBLOB + + +.. _ingest-general-base-table-names: + +Base versus final table names +----------------------------- + +In descriptions of several services, the documentation uses an adjective *base* when referring to tables affected +by requests to the services. In reality, those *base* tables are exactly the names of the Qserv tables as they are seen +by Qserv users. In the distributed realm of Qserv each such table is collectively represented by many *final* tables +distributed across Qserv worker nodes. The names of the *final* tables depend on the table type: + +- *regular* (fully replicated) tables have the same name as the *base* table +- *partitioned* (chunked) tables have names constructed using the *base* name and the chunk numbers and values + of the overlap attribute of the table. + +Formally, the names of the *final* tables are constructed as follows: + +.. code-block:: + + = | _ | FullOverlap_ + +For example: + +.. code-block:: + + Filter + Object_1234 + ObjectFullOverlap_1234 diff --git a/doc/ingest/api/reference/rest/index.rst b/doc/ingest/api/reference/rest/index.rst new file mode 100644 index 000000000..84746cc61 --- /dev/null +++ b/doc/ingest/api/reference/rest/index.rst @@ -0,0 +1,10 @@ +############# +REST Services +############# + +.. toctree:: + :maxdepth: 3 + + general + controller/index + worker/index diff --git a/doc/ingest/api/reference/rest/worker/index.rst b/doc/ingest/api/reference/rest/worker/index.rst new file mode 100644 index 000000000..74ad3f34b --- /dev/null +++ b/doc/ingest/api/reference/rest/worker/index.rst @@ -0,0 +1,900 @@ +#################### +Worker Ingest Server +#################### + +.. note:: + + Services explained in this section are provided directly by Qserv workers, not by the main REST server of + the Master Replication Controller. Each Qserv worker runs a dedicated Ingest Server that is reponsible for + ingesting and managing catalogs located on the coresponding worker. Ingest workflows interact directly with + workers using this API. The DNS names (IP addresses) of the corresponding hosts and the relevant port numbers + of the worker services are returned by requests sent to the Master Replication Controller's services: + + - :ref:`table-location-chunks` + - :ref:`table-location-chunks-one` + - :ref:`table-location-regular` + +.. _ingest-worker-contrib-by-ref: + +Ingesting contributions by reference +==================================== + +Contribution ingest requests can be initiated using one of these techniques: + +- *synchronous processing*: a client will get blocked for the duration of the request before it finishes (or failed) + to be executed. After that, the client would have to analyze the final state of the request from a response sent + by the service. +- *asynchronous processing*: a client will not be blocked. Once the request's parameters were successfully parsed and + analyzed (and accepted), the request will be queued for asynchronous processing. After that, the service will send back + a response with the unique identifier and the current status of the request. The workflow will have to use the identifier + to track the progression of the request. For requests that failed the validation stage information on reasons for + the failure will be returned. + +The following REST services implement these protocols: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - | ``/ingest/file`` + | ``/ingest/file-async`` + +The services expect a caller to provide a description of a request in the request's body in a form of a JSON object. +The object should adhere to the following schema: + +.. code-block:: + + { + "transaction_id" : , + "table" : , + "chunk" : , + "overlap" : , + + "url" : , + + "fields_terminated_by" : , + "fields_enclosed_by" : , + "fields_escaped_by" : , + "lines_terminated_by" : , + "charset_name" : , + + "http_method" : , + "http_data" : , + "http_headers" : , + + "max_num_warnings" : , + "num_retries" : + } + + +Where: + +``transaction_id`` : *number* + The required unique identifier of a transaction that is required to be in the ``STARTED`` state + at a time when a request is received by a service. More information on the transaction management and transaction + states can be found in: :ref:`ingest-trans-management`. + +``table`` : *string* + The required *base* name of a table receiving the contribution. See :ref:`ingest-general-base-table-names` for more details + on the meaning of the attriute *base* in a context of this API. + +``chunk`` : *number* + The required chunk number for the partitioned tables. + + **Note**: ignored for the *regular* tables. + +``overlap`` : *number* + The required numeric flag indicates a kind of partitioned table (``0`` if this is not the *overlap* + table or any other number of this is the *overlap* table). + + **Note**: ignored for the *regular* tables. + +``url`` : *string* + The required location of a file to be ingested. The current implementation supports the following schemes: + + - ``file:///``: A file on a filesystem that is mounted locally on the corresponding worker. Note that + the file path must be absolute. See details on this subject at: https://en.wikipedia.org/wiki/File_URI_scheme. + + - ``http://``, ``https://``: A file on a web server. For either of these schemes, additional + attributes (if needed) for pulling a file over the specified protocol could be provided in optional parameters: + ``http_method``, ``http_data`` and ``http_headers``. Descriptions of the parameters are provided below in this table. + + **Note**: Workflows may also configure the behavior of the ``libcurl`` library by settting the library-specific + options at a level of a database. See instructions at: :ref:`ingest-config`. + +``fields_terminated_by`` : *string* = ``\t`` + The optional parameter of the desired CSV dialect: a character that separates fields in a row. + The dafault value assumes the tab character. + +``fields_enclosed_by`` : *string* = ``""`` + The optional parameter of the desired CSV dialect: a character that encloses fields in a row. + The default value assumes no quotes around fields. + +``fields_escaped_by`` : *string* = ``\\`` + The optional parameter of the desired CSV dialect: a character that escapes special characters in a field. + The default value assumes two backslash characters. + +``lines_terminated_by`` : *string* = ``\n`` + The optional parameter of the desired CSV dialect: a character that separates rows. + The default value assumes the newline character. + +``charset_name`` : *string* = ``latin1`` + The optional parameters specify the desired character set name to be assumed when ingesting + the contribution. The default value may be also affected by the ingest services configuration. + See the following document for more details: + + - **TODO**: A reference to the page "Specifying character sets when ingesting tables into Qserv" + +``http_method`` : *string* = ``GET`` + The optional method that is used to pull a file over the HTTP protocol. + +``http_data`` : *string* = ``""`` + The optional data that is sent in the body of the HTTP request. + The default value assumes no data are sent. + +``http_headers`` : *string* = ``""`` + The optional list of headers that are sent in the HTTP request. + The default value assumes no headers are sent. A value of the parameters is a string that contains + zero, one or many headers definition string separated by a colon, where each such definition should look like: + + .. code-block:: + + : + +``max_num_warnings`` : *number* = ``64`` + The optional limit for the number of notes, warnings, and errors to be retained by MySQL/MariaDB when + loading the contribution into the destination table. + + **Note**: The default number of the limit is determined by a configuration of the ingest services. + The default value of the parameter in MySQL/MariaDB is ``64``. The upper limit for the parameter is ``65535``. + Some workflows may choose to set a specific value for the limit when debugging data of the contributions. + + **TODO**: "Configuration Guide for the Replication/Ingest System" (a reference to the page) + +``num_retries`` : *number* : **optional** + The optional number of automated retries of failed contribution attempts in cases when + such retries are still possible. The limit can be further limited by the ingest service to a value that will + not exceed the "hard" limit set in the worker configuration parameter (``worker``, ``ingest-max-retries``). + Setting a value of the parameter to ``0`` will explicitly disable automatic retries regardless of the server's + configuration settings. + + **Notes**: + + - The parameter is ignored by the *synchronous* service. + - The default number of retries set in the Inget Server's configuration parameter + (``worker``, ``ingest-num-retries``) will be assumed. + + **TODO**: "Configuration Guide for the Replication/Ingest System" (a reference to the page) + +The service will return the following JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +.. _ingest-worker-contrib-by-val: + +Ingesting contributions by value +================================ + +Contributions can be also ingested by sending data directly to the worker server in the request body. There are two sevices +in this category. Both techniques are *synchronous* and the client will be blocked until the request is processed: + +- sending data as a JSON object +- sending data as a ``CSV`` file in the ``multipart/form-data`` formatted body + +Each technique has its own pros and cons. + +.. _ingest-worker-contrib-by-val-json: + +JSON object +----------- + +The following service allows a workflow to push both data and a description of the contribution request as a JSON object: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/data`` + +The service expects a caller to provide a description of a request in the request's body in a form of a JSON object: + +.. code-block:: + + { + "transaction_id" : , + "table" : , + "chunk" : , + "overlap" : , + "charset_name" : , + "binary_encoding" : , + "max_num_warnings" : , + "rows" : [ + , + ... + + ] + } + +Where: + +``transaction_id`` : *number* + The required unique identifier of a transaction that has to be in the ``STARTED`` state + at a time when a request is received by a service. More information on the transaction management and transaction + states can be found in: :ref:`ingest-trans-management`. + +``table`` : *string* + The required *base* name of a table receiving the contribution. See :ref:`ingest-general-base-table-names` for more details + on the meaning of the attriute *base* in a context of this API. + +``chunk`` : *number* + The required chunk number for the partitioned tables. + + **Note**: ignored for the *regular* tables. + +``overlap`` : *number* + The required numeric flag indicates a kind of partitioned table (``0`` if this is not the *overlap* + table or any other number of this is the *overlap* table). + + **Note**: ignored for the *regular* tables. + +``charset_name`` : *string* = ``latin1`` + The optional value depends on Qserv settings. + +``binary_encoding`` : *string* = ``hex`` + See :ref:`ingest-general-binary-encoding` for more details. + +``max_num_warnings`` : *number* = ``64`` + The optional limit for the number of notes, warnings, and errors to be retained by MySQL/MariaDB when + loading the contribution into the destination table. + + **Note**: The default number of the limit is determined by a configuration of the ingest services. + The default value of the parameter in MySQL/MariaDB is ``64``. The upper limit for the parameter is ``65535``. + Some workflows may choose to set a specific value for the limit when debugging data of the contributions. + + **TODO**: "Configuration Guide for the Replication/Ingest System" (a reference to the page) + +``rows`` : *array* + The required collection of the data rows to be ingested. Each element of the array represents a complete row, + where elements of the row represent values of the corresponding columns in the table schema: + + .. code-block:: + + [[, ... ], + ... + [, ... ] + ] + + **Note**: + + - The number of elements in each row must be the same as the number of columns in the table schema. + - Positions of the elements within rows should match the positions of the corresponding columns in the table schema. + - see the :ref:`ingest-db-table-management-register-table` section for the details on the table schema. + +The service will return the following JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +.. _ingest-worker-contrib-by-val-csv: + +CSV file +-------- + +.. warning:: + + The service expectes a certain order of the parts in the body of the request. The description of the contribution + request should be posted first, and the file payload should be posted second. There must be exactly one file payload + in the body of the request. No file or many files will be treated as an error and reported as such in the response. + +The following service allows a workflow to push both data (a ``CSV`` file) and a description of the contribution request in +the ``multipart/form-data`` formatted body: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``POST`` + - ``/ingest/csv`` + +The body should contain two parts posted in the following order: + +- a collection of the key-value pairs that represent the description of the contribution request +- a single file payload that contains the data to be ingested + +Where the keys which describe the contribution request are presented below: + +``transaction_id`` : *number* + The required unique identifier of a transaction that has to be in the ``STARTED`` state + at a time when a request is received by a service. More information on the transaction management and transaction + states can be found in: :ref:`ingest-trans-management`. + +``table`` : *string* + The required *base* name of a table receiving the contribution. See :ref:`ingest-general-base-table-names` for more details + on the meaning of the attriute *base* in a context of this API. + +``chunk`` : *number* + The required chunk number for the partitioned tables. + + **Note**: ignored for the *regular* tables. + +``overlap`` : *number* + The required numeric flag indicates a kind of partitioned table (``0`` if this is not the *overlap* + table or any other number of this is the *overlap* table). + + **Note**: ignored for the *regular* tables. + +``charset_name`` : *string* = ``latin1`` + The optional parameter that depends on Qserv settings. + +``fields_terminated_by`` : *string* = ``\t`` + The optional parameter of the desired CSV dialect: a character that separates fields in a row. + +``fields_enclosed_by`` : *string* = ``""`` + The optional parameter of the desired CSV dialect: a character that encloses fields in a row. + The default value assumes no quotes around fields. + +``fields_escaped_by`` : *string* = ``\\`` + The optional parameter of the desired CSV dialect: a character that escapes special characters in a field. + The default value assumes two backslash characters. + +``lines_terminated_by`` : *string* = ``\n`` + The default value of the optional parameter assumes the newline character. + +``max_num_warnings`` : *number* = ``64`` + The optional limit for the number of notes, warnings, and errors to be retained by MySQL/MariaDB when + loading the contribution into the destination table. + + **Note**: The default number of the limit is determined by a configuration of the ingest services. + The default value of the parameter in MySQL/MariaDB is ``64``. The upper limit for the parameter is ``65535``. + Some workflows may choose to set a specific value for the limit when debugging data of the contributions. + + **TODO**: "Configuration Guide for the Replication/Ingest System" (a reference to the page) + +The service will return the following JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +Here is an example of how the request could be formatted using ``curl``: + +.. code-block:: bash + + curl http://localhost:25004/ingest/csv \ + -X POST -H 'Content-Type: multipart/form-data' \ + -F 'transaction_id=1630'\ + -F 'table=gaia_source' \ + -F 'chunk=675' \ + -F 'overlap=0' \ + -F 'charset_name=latin1' \ + -F 'fields_terminated_by=,' \ + -F 'max_num_warnings=64' \ + -F 'file=@/path/to/file.csv' + +**Note**: the request header ``-H 'Content-Type: multipart/form-data'`` is not required when using ``curl``. The header +is added here for the sake of clarity. + +Another example is based on Python's ``requests`` library and the ``requests_toolbelt`` package: + +.. code-block:: python + + import requests + from requests_toolbelt.multipart.encoder import MultipartEncoder + + url = 'http://localhost:25004/ingest/csv' + encoder = MultipartEncoder( + fields = { + 'transaction_id': 1630, + 'table': 'gaia_source', + 'chunk': 675, + 'overlap': 0, + 'charset_name': 'latin1', + 'fields_terminated_by': ',', + 'max_num_warnings': 64, + "file": ('file.csv', open('/path/to/file.csv', 'rb'), 'text/csv') + } + response = requests.post(url, data=encoder) + print(response.json()) + +**Important**: The ``MultipartEncoder`` class from the ``requests_toolbelt`` package is used for both formatting +the request and sending it in the *streaming* mode. The mode is essential for avoiding memory problem +on the client side when pushing large contributons into the service. W/o the streaming mode the client +will try to load the whole file into memory before sending it to the server. + +.. _ingest-worker-contrib-get: + +Status of requests +================== + +There are two services in this group. The first one allows retrieving the status info of a single request by +its identifier. The second service is meant for querying statuses of all asynchronous requests of the given transaction. + +.. _ingest-worker-contrib-get-one: + +One request +----------- + +The service allows obtaining a status of the *asynchronous* contribution requests: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/ingest/file-async/:id`` + +The services expect a caller to provide a unique identifier ``id`` of the contribution request in the resource path. +Values of the identifiers are returned by services that accept the contribution requests. + +If the identifier is valid and the service could locate the desired record for the contributon it will return the following +JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +.. _ingest-worker-contrib-get-trans: + +All requests of a transaction +----------------------------- + +The service allows obtaining a status of the *asynchronous* contribution requests submitted in a scope of +a given transaction: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``GET`` + - ``/ingest/file-async/trans/:id`` + +The services expect a caller to provide a unique identifier ``id`` of the transaction in the resource path. +Values of the transaction identifiers are returned by services that manage transactions. See :ref:`ingest-trans-management` +for more details. + +If the identifier is valid and the service could locate the relevant contributons it will will return the following +JSON array: + +.. code-block:: + + { "contribs": [ + , + .. + + ] + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the contribution objects. + + +.. _ingest-worker-contrib-retry: + +Retrying failed contributions +============================= + +.. note:: + + - Services, presented in this section complement those that were meant for the initial submission of the contribution + requests posted by *by-reference*, regardless of the interface used (*synchronous* or *asynchronous*) as documented + in :ref:`ingest-worker-contrib-by-ref`. The eligibility requirememnts for the requests are further explained in: + + - **TODO**: "Automatic retries for the failed contribution requests" (a reference to the page) + + - Unlike the *automatic* retries that may be configured in the original contribution request, + the *explicit* retrying is a responsibility of the ingest workflow. + - The number of the explicit retries is not a subject for limits set for the automatic retries. + It's up to the workflow to decide how many such retries should be attempted. The workflow should coordinate + the retries with the transaction managemnet to avoid the situation when the same request is retried + while the transaction is already in a state that doesn't allow the contribution to be processed. + - The workflow should avoid making multiple parallel requests to retry the same contribution request. + The workflow should be always waiting for the response of the previous retry before making another one. + - The *automatic* retries are disabled by the Ingest service while processing the explicitly made retries. + +Both *synchronous* and *asynchronous* services are provided for the retrying of the failed contributions: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``PUT`` + - | ``/ingest/file/:id`` + | ``/ingest/file-async/:id`` + +The services expect a caller to provide a unique identifier ``id`` of the contribution request to be retried. + +The services will locate and evaluate the specified request to see if it's eligible for retrying. And if it's then +the request will be processed in accordance with the logic of the called service. Specifically: + +- If the *synchronous* interface was invoked then the request will be attempted right away and only once (no further + automatic replies). +- If the alternative *asynchronous* interface was invoked then the request will be placed at the very end of the input + queue. It will be processed in its turn when picked by one of the processing threads of the ingest server's pool. + Likewise, in the case of *synchronous* processing, only one attempt to process the request will be made. + +The service will return the following JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +.. _ingest-worker-contrib-cancel: + +Cancelling async requests +========================= + +.. warning:: + + In general, request cancellation is a non-deterministic operation that is prone to *race conditions*. + An outcome of the cancellation request depends on the current state of a request within the worker service: + + - If the request is still in the wait queue then the cancellation will be successful. + - If the request is already being processed by the ingest machinery then the cancellation will be successful + only if the request is still in the data *reading* state. + - Requests that are already in the *loading* state are presently not cancellable since MySQL table loading + is a non-interruptible operation. + - If the request is already in the *finished* or any form of the *failed* state then obviously no cancellation + will happen. + + The workflow should be always inspect the state of the requests after the cancellation attempts + to make sure that the requests were indeed cancelled. + +There are two services in this group. The first one allows canceling a single request by its identifier. +The second service is meant for cancelling all asyncgronous requests of the given transaction. + +.. _ingest-worker-contrib-cancel-one: + +One request +----------- + +The service allows cancelling an *asynchronous* contribution request: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``DELETE`` + - ``/ingest/file-async/:id`` + +The services expect a caller to provide a unique identifier ``id`` of the contribution request in the resource path. +Values of the identifiers are returned by services that accept the contribution requests. + +If the identifier is valid and the service could locate the desired record for the contributon it will make an attempt +to cancel it. The service will return the following JSON object: + +.. code-block:: + + { "contrib": { + ... + } + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the response object. + +.. _ingest-worker-contrib-cancel-trans: + +All requests of a transaction +----------------------------- + +The service allows cancelling all *asynchronous* contribution requests submitted in a scope of +a given transaction: + +.. list-table:: + :widths: 10 90 + :header-rows: 0 + + * - ``DELETE`` + - ``/ingest/file-async/trans/:id`` + +The services expect a caller to provide a unique identifier ``id`` of the corresponding transaction in the resource path. +Values of the transaction identifiers are returned by services that manage transactions. See :ref:`ingest-trans-management` +for more details. + +If the identifier is valid and the service could locate the relevant contributons it will make an attempt +to cancel them. The service will return the following JSON array: + +.. code-block:: + + { "contribs": [ + , + .. + + ] + } + +See the :ref:`ingest-worker-contrib-descriptor` section of document for the details on the schema of the contribution objects. + + +.. _ingest-worker-contrib-descriptor: + +Contribution descriptor +======================= + +The following object illustrates the schema and a sample payload of the contribution descriptor: + +.. code-block:: json + + { + "id" : 2651966, + "async" : 1, + "database" : "gaia_edr3", + "table" : "gaia_source", + "worker" : "db13", + "chunk" : 675, + "overlap" : 0, + "transaction_id" : 1630, + + "status" : "FINISHED", + "create_time" : 1726026383616, + "start_time" : 1726026383619, + "read_time" : 1726026396161, + "load_time" : 1726026412474, + + "url" : "http://sdfqserv001:18080/gaia_edr3/gaia_source/files/chunk_675.txt", + "http_method" : "GET", + "http_headers" : [], + "http_data" : "", + "tmp_file" : "/qserv/data/ingest/gaia_edr3-gaia_source-675-1630-7570-6e63-d0b6-6934.csv", + + "max_num_warnings" : 64, + "max_retries" : 4, + + "charset_name" : "latin1", + "dialect_input" : { + "fields_enclosed_by" : "\\0", + "lines_terminated_by" : "\\n", + "fields_escaped_by" : "\\\\", + "fields_terminated_by" : "," + }, + + "num_bytes" : 793031392, + "num_rows" : 776103, + "num_rows_loaded" : 776103, + + "http_error" : 0, + "error" : "", + "system_error" : 0, + "retry_allowed" : 0, + + "num_warnings" : 0, + "warnings" : [], + "num_failed_retries" : 0, + "failed_retries" : [] + } + + +The most important (for the ingest workflows) attributes of the contribution object are: + +``status`` : *string* + The status of the contribution requests. The possible values are: + + - ``IN_PROGRESS``: The transient state of a request before it's ``FINISHED`` or failed. + - ``CREATE_FAILED``: The request was received and rejected right away (incorrect parameters, etc.). + - ``START_FAILED``: The request couldn't start after being pulled from a queue due to changed conditions. + - ``READ_FAILED``: Reading/preprocessing of the input file failed. + - ``LOAD_FAILED``: Loading into MySQL failed. + - ``CANCELLED``: The request was explicitly cancelled by the ingest workflow (ASYNC contributions only). + - ``FINISHED``: The request succeeded, + +``create_time`` : *number* + The timestamp when the contribution request was received (milliseconds since the UNIX *Epoch*). + A value of the attribute is guaranteed to be not ``0``. + +``start_time`` : *number* + The timestamp when the contribution request was started (milliseconds since the UNIX *Epoch*). + A value of the attribute is ``0`` before the processing starts. + +``read_time`` : *number* + The timestamp when the Ingest service finished reading/preprocessing the input file (milliseconds since the UNIX *Epoch*). + A value of the attribute is ``0`` before the reading starts. + +``load_time`` : *number* + The timestamp when the Ingest service finished loading the contribution into the MySQL table (milliseconds since the UNIX *Epoch*). + A value of the attribute is ``0`` before the loading starts. + +``url`` : *string* + The URL of the input file that was used to create the contribution. Depending on a source of the data, + the URL *scheme* could be: + + - ``http``, ``https``: The file was pulled from a remote Web server. + - ``file``: The file was read from a filesystem that is mounted locally on the corresponding worker. The URL is a full path to the file. + - ``data-json``: The file was sent as a JSON object in the request body. The URL is a placeholder. + - ``data-csv``: The file was sent as a CSV file in the ``multipart/form-data`` formatted body. The URL is a placeholder. + + **Note** that there is no guarantee that the URL will be valid after the contribution is processed. + +``max_num_warnings`` : *number* + The maximum number of the MySQL warnings to be captured after loading the contribution into the MySQL table. + The number may correspond to a value that was explicitly set by workflow when making a contribution request. + Otheriwse the default number configured at the system is assumed. + +``max_retries`` : *number* + The maximum number of retries allowed for the contribution. The number may correspond to a value that was explicitly set by workflow + when making a contribution request. Otheriwse the default number configured at the system is assumed. + +``num_bytes`` : *number* + The total number of bytes in the input file. The value is set by the service after it finishes reading + the file and before it starts loading the data into the MySQL table. + +``num_rows`` : *number* + The total number of rows parsed by the ingest service in the input file. + +``num_rows_loaded`` : *number* + The total number of rows loaded into the MySQL table. Normally the number of rows loaded should be equal to the number of rows parsed. + If the numbers differ it means that some rows were rejected during the ingest process. The workflow should be always monitoring any + mismatches in these values and trigger alerts. + +``http_error`` : *number* + The HTTP error code captured by the service when pulling data of the contribution from a remote Web server. + This applies to the corresponidng URL *schemes*. The value is set only if the error was detected. + +``error`` : *string* + The error message captured by the service during the contribution processing. The value is set only if the error was detected. + +``system_error`` : *number* + The system error code captured by the service during the contribution processing. The value is set only if the error was detected. + +``retry_allowed`` : *number* + The flag that tells if the contribution is allowed to be retried. The value is set by the service when the contribution + processing was failed. The value is set to ``1`` if the contribution is allowed to be retried, and to ``0`` otherwise. + + **Important**: The workflow should be always analyze a value of this attribute to decide if the contribution should be retried. + If the retry is not possible then the workflow should give up on the corresponding transaction, abort the one, and start + the another transaction to ingest all contributions attempted in a scope of the aborted one. + +``num_warnings`` : *number* + The total number of MySQL warnings captured after loading the contribution into the MySQL table. + + **Note**: The number is reported correctly regardless if the array in the attribute ``warnings`` + is empty or not. + +``warnings`` : *array* + The array of MySQL warnings captured after loading the contribution into the MySQL table. Each entry is + an object that represents a warning/error/note. See the table in :ref:`ingest-worker-contrib-descriptor-warnings` + for the details on the schema of the object. + + **Notes**: The maximum number of warnings captured is limited by the value of the attribute ``max_num_warnings``. + +``num_failed_retries`` : *number* + The total number of retries that failed during the contribution processing. + + **Note**: The number is reported correctly regardless if the array in the attribute ``failed_retries`` + is empty or not. + +``failed_retries`` : *array* + The array of failed retries captured during the contribution processing. Each such retry is represented + by JSON object that has a schema explained in :ref:`ingest-worker-contrib-descriptor-retries`. + + **Note**: The maximum number of failed retries captured is limited by the value of the attribute ``max_retries``. + +.. _ingest-worker-contrib-descriptor-warnings: + +MySQL warnings +-------------- + +Warnings are captured into the JSON array of ``warnings``: + +.. code-block:: + + "warnings" : [ + , + ... + + ] + +The format of the object is presented below: + +``level`` : *string* + The severity of the warning reported by MySQL. Allowed values: + + - ``Note`` + - ``Warning`` + - ``Error`` + +``code`` : *number* + The numeric error code indicates a reason for the observed problem. + +``message`` : *string* + The human-readable explanation for the problem. + +Here is an example of what could be found in the array: + +.. code-block:: json + + "warnings" : [ + {"code" : 1406, "level" : "Warning", "message" : "Data too long for column 's_region_scisql' at row 3670"}, + {"code" : 1261, "level" : "Warning", "message" : "Row 3670 doesn't contain data for all columns"}, + {"code" : 1406, "level" : "Warning", "message" : "Data too long for column 's_region_scisql' at row 3913"}, + {"code" : 1261, "level" : "Warning", "message" : "Row 3913 doesn't contain data for all columns"}, + {"code" : 1406, "level" : "Warning", "message" : "Data too long for column 's_region_scisql' at row 3918"}, + {"code" : 1261, "level" : "Warning", "message" : "Row 3918 doesn't contain data for all columns"} + ], + +More details on the values can be found in the MySQL documentation: + +- https://dev.mysql.com/doc/refman/8.4/en/show-warnings.html + +.. _ingest-worker-contrib-descriptor-retries: + +Retries +------- + +Retries are captured into the JSON array of ``failed_retries``: + +.. code-block:: + + "failed_retries" : [ + , + ... + + ] + +The format of the object is presented below: + +.. code-block:: + + { "start_time" : , + "read_time" : , + "tmp_file" : , + "num_bytes" : , + "num_rows" : , + "http_error" : , + "system_error" : , + "error" : + } + +Where: + +``start_time`` : *number* + The timestamp when the retry attempt was started (milliseconds since the UNIX *Epoch*). + A value of the attribute is ``0`` before the processing starts. + +``read_time`` : *number* + The timestamp when the Ingest service finished reading/preprocessing the input file (milliseconds since the UNIX *Epoch*). + A value of the attribute is ``0`` before the reading starts. + +``num_bytes`` : *number* + The total number of bytes in the input file. The value is set by the service after it finishes reading + the file and before it starts loading the data into the MySQL table. + +``num_rows`` : *number* + The total number of rows parsed by the ingest service in the input file. + +``http_error`` : *number* + The HTTP error code captured by the service when pulling data of the contribution from a remote Web server. + This applies to the corresponidng URL *schemes*. The value is set only if the error was detected. + +``system_error`` : *number* + The system error code captured by the service during the contribution processing. The value is set only if the error was detected. + +``error`` : *string* + The error message captured by the service during the contribution processing. The value is set only if the error was detected. diff --git a/doc/ingest/api/reference/tools.rst b/doc/ingest/api/reference/tools.rst new file mode 100644 index 000000000..3642fc5fc --- /dev/null +++ b/doc/ingest/api/reference/tools.rst @@ -0,0 +1,17 @@ +###################### +The Command Line Tools +###################### + +Error reporting in the command-line tools +========================================= + +All command line tools return ``0`` to indicate the successful completion of the requested operation. +Other values shall be treated as errors. The error messages are printed to the standard error stream. +Additional information on the error can be found in the standard output stream. + +.. _ingest-tools-qserv-replica-file: + +qserv-replica-file +================== + +TBC. \ No newline at end of file diff --git a/doc/ingest/api/simple/index.rst b/doc/ingest/api/simple/index.rst new file mode 100644 index 000000000..3125deae7 --- /dev/null +++ b/doc/ingest/api/simple/index.rst @@ -0,0 +1,6 @@ + +.. _ingest-api-simple: + +=============== +Simple Workflow +=============== diff --git a/doc/ingest/data/index.rst b/doc/ingest/data/index.rst new file mode 100644 index 000000000..4c77d11ba --- /dev/null +++ b/doc/ingest/data/index.rst @@ -0,0 +1,291 @@ + +.. _ingest-data: + +Data preparation +================ + +More details on the data preparation steps. + +- data formats + + - supported CSV *dialects* and parameters + - relation to MySQL (it's MySQL-supported CSV in the end) + - handling binary data + +- data sanitization +- partitioning + + - directors + + - restrictions on data types for the *director* tables: + + - fixed width types only. + - explain why (sub-chunk materialization) + + - simple dependent tables + + - by spatial coordinates + - by object ID index + + - ref-match dependent tables + +- staging the input data + +- bookkeeping and data provenance + + - How to organize data, name files, manage metadata, push metadata to Qserv ingest system + using transaction *contexts* + + +In general there are two types of operations that have to be performed on the input data: + +- If the input files are in the Parquet format they have to be converted to the CSV format: +- For the *partitioned* tables artition the ``CSV`` files into chunks +- Place the input files in the right location where the workflow will be + +- ensure that the data is in the right format (CSV is the only supported format) and that it's sanitized + to ensure the values of the columns are compatible with the MySQL expectations: + + - one good example is the ``BOOL`` type that maps to the ``TINYINT`` type in MySQL. Values like ``true`` + and ``false`` are not supported by MySQL. Hence they need to be converted to ``1`` and ``0`` respectively. + + - another example are ``-inf`` and ``+inf`` values that are not supported by MySQL. They need to be + converted to the ``-1.7976931348623157E+308`` and ``1.7976931348623157E+308`` respectively. + + +.. _ingest-data-partitioning-ref-match: + +Partitioning data of the RefMatch tables +----------------------------------------- + +Introduction +^^^^^^^^^^^^ + +The ``RefMatch`` tables are a special class of tables that are designed to match rows between two independent *director* tables +belonging to the same or different catalogs. In this case, there is no obvious 1-to-1 match between rows of the director tables. +Instead, the pipelines compute a (spatial) match table between the two that provides a many-to-many relationship between both tables. +The complication is that a match record might reference a row (an *object*) and reference row that fall on opposite sides of +the partition boundary (into different chunks). Qserv deals with this by taking advantage of the overlap that must be stored +alongside each partition (this overlap is stored so that Qserv can avoid inter-worker communication when performing +spatial joins on the fly). + +Since the ``RefMatch`` tables are also partitioned tables the input data (CSV) of the tables have to be partitioned into chunks. +In order to partition the RefMatch tables one would have to use a special version of the partitioning tool sph-partition-matches. +A source code of the tool is found in the source tree of Qserv: https://github.com/lsst/qserv/blob/main/src/partition/sph-partition-matches.cc. +The corresponding binary is built and placed into the binary Docker image of Qserv. + +Here is an example illustrating how to launch the tool from the container: + +.. code-block:: bash + + % docker run -it qserv/lite-qserv:2022.9.1-rc1 sph-partition-matches --help + + sph-partition-matches [options] + + The match partitioner partitions one or more input CSV files in + preparation for loading by database worker nodes. This involves assigning + both positions in a match pair to a location in a 2-level subdivision + scheme, where a location consists of a chunk and sub-chunk ID, and + outputting the match pair once for each distinct location. Match pairs + are bucket-sorted by chunk ID, resulting in chunk files that can then + be distributed to worker nodes for loading. + A partitioned data-set can be built-up incrementally by running the + partitioner with disjoint input file sets and the same output directory. + Beware - the output CSV format, partitioning parameters, and worker + node count MUST be identical between runs. Additionally, only one + partitioner process should write to a given output directory at a + time. If any of these conditions are not met, then the resulting + chunk files will be corrupt and/or useless. + \_____________________ Common: + -h [ --help ] Demystify program usage. + -v [ --verbose ] Chatty output. + -c [ --config-file ] arg The name of a configuration file + containing program option values in a + ... + +The tool has two parameters specifying the locations of the input (CSV) file and the output folder where +the partitioned products will be stored: + +.. code-block:: bash + + % sph-partition-matches --help + .. + \_____________________ Output: + --out.dir arg The directory to write output files to. + \______________________ Input: + -i [ --in.path ] arg An input file or directory name. If the + name identifies a directory, then all + the files and symbolic links to files + in the directory are treated as inputs. + This option must be specified at least + once. + +.. hint:: + + If the tool is launched via the docker command as was shown above, one would have to mount the corresponding + host paths into the container. + +All tables, including both *director* tables and the ``RefMatch`` table itself, have to be partitioned using +the same values of the partitioning parameters, including: + +- The number of stripes +- The number of sub-stripes +- The overlap radius + +Values of the partitioning parameters should be specified using the following options (the default values shown below are meaningless +for any production scenario): + +.. code-block:: bash + + --part.num-stripes arg (=18) The number of latitude angle stripes to + divide the sky into. + --part.num-sub-stripes arg (=100) The number of sub-stripes to divide + each stripe into. + --part.overlap arg (=0.01) Chunk/sub-chunk overlap radius (deg). + +The next sections present two options for partitioning the input data. + +The spatial match within the given overlap radius +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is the most reliable way of partitioning the input data of the match tables. It is available when +the input rows of the match table carry the exact spatial coordinates of both matched rows (from the corresponding +*director* tables). + +In this scenario, the input data file (``CSV``) is expected to have 4 columns representing the spatial coordinates +of the matched rows from the *director* tables on the 1st ("left") and on the 2nd ("righ"). Roles and sample names +of the columns are presented in the table below: + +``dir1_ra`` + The *right ascent* coordinate (*longitude*) of the 1st matched entity (from the 1st *director* table). +``dir1_dec`` + The *declination* coordinate (*latitude*) of the 1st matched entity (from the 1st director table). +``dir2_ra`` + The *right ascent* coordinate (*longitude*) of the 2nd matched entity (from the 2nd *director* table). +``dir2_dec`` + The *declination* coordinate (*latitude*) of the 2nd matched entity (from the 2nd director table). + +The names of these columns need to be passed to the partitioning tool using two special parameters: + +.. code-block:: bash + + % sph-partition-matches \ + --part.pos1="dir1_ra,dir1_dec" \ + --part.pos2="dir2_ra,dir2_dec" + +.. note: + + The order of the columns in each packed pair pf columns is important. The names must be separated by commas. + +When using this technique for partitioning the match tables, it's required that the input CSV file(s) had at least those 4 columns +mentioned above. The actual number of columns could be larger. Values of all additional will be copied into the partitioned +products (the chunk files). The original order of the columns will be preserved. + +Here is an example of a sample ``CSV`` file that has values of the above-described spatial coordinates in the first 4 columns +and the object identifiers of the corresponding rows from the matched *director* tables in the last 2 columns: + +.. code-block:: + + 10.101,43.021,10.101,43.021,123456,6788404040 + 10.101,43.021,10.102,43.023,123456,6788404041 + +The last two columns are meant to store values of the following columns: + +``dir1_objectId`` + The unique object identifier of the 1st *director* table. +``dir2_objectId`` + The unique object identifier of the 2nd *director* table. + +The input CSV file shown above could be also presented in the tabular format: + +.. list-table:: + :widths: 10 10 10 10 10 10 + :header-rows: 1 + + * - ``dir1_ra`` + - ``dir1_dec`` + - ``dir2_ra`` + - ``dir2_dec`` + - ``dir1_objectId`` + - ``dir2_objectId`` + * - 0.101 + - 43.021 + - 10.101 + - 43.021 + - 123456 + - 6788404040 + * - 0.101 + - 43.021 + - 10.102 + - 43.023 + - 123456 + - 6788404041 + +Note that this is actually a 1-to-2 match, in which a single object (``123456``) of the 1st director has two matched +objects (``6788404040`` and ``6788404041``) in the 2nd director. Also, note that the second matched object has slightly +different spatial coordinates than the first one. If the value of the overlap parameter is bigger than the difference +between the coordinates then the tool will be able to match the objects successfully. For example, this would work if +a value of the overlap was set to ``0.01``. Otherwise, no match will be made and the row will be ignored by the tool. + +.. _warning: + + It is assumed that the input data of the ``RefMatch`` tables are correctly produced by the data processing + pipelines. Verifying the quality of the input data is beyond the scope of this document. However, one might + consider writing a special tool for pre-scanning the input files and finding problems in the files. + +Here is the complete practical example of how to run the tool with the assumptions made above: + +.. code-block:: bash + + % cat in.csv + 10.101,43.021,10.101,43.021,123456,6788404040 + 10.101,43.021,10.102,43.023,123456,6788404041 + + % cat config.json + { + "part":{ + "num-stripes":340. + "num-sub-stripes":3, + "overlap":0.01, + "pos1":"dir1_ra,dir1_dec", + "pos2":"dir2_ra,dir2_dec" + }, + "in":{ + "csv":{ + "null":"\\N", + "delimiter":",", + "field":[ + "dir1_ra", + "dir1_dec" + "dir2_ra", + "dir2_dec", + "dir1_objectId", + "dir2_objectId" + ] + } + }, + "out":{ + "csv":{ + "null":"\\N", + "delimiter":",", + "escape":"\\", + "no-quote":true + } + } + } + + % mkdir chunks + % sph-partition-matches -c config.json --in.path=in.csv --out.dir=chunks/ + +Partitioning using index maps +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + This section is under construction. Only the basic idea is presented here. + +This is an alternative way of partitioning the input data of the match tables. It is available when the input rows of the match table +do not carry the exact spatial coordinates of both matched rows (from the corresponding *director* tables). Instead, the input data +has to carry the unique object identifiers of the matched rows. The tool will use the object identifiers to find the spatial coordinates +of the matched rows in the *director* tables. The tool will use the index maps of the *director* tables to find the spatial coordinates +of the matched rows. diff --git a/doc/ingest/index.rst b/doc/ingest/index.rst index c9cbfaca1..7d24c567a 100644 --- a/doc/ingest/index.rst +++ b/doc/ingest/index.rst @@ -5,46 +5,10 @@ Ingesting catalogs ################## -.. toctree:: - :maxdepth: 2 +.. toctree:: + :maxdepth: 2 - api/index - qserv-ingest/index - -============ -Introduction -============ - -Unlike traditional RDBMS systems, Qserv does not support direct ingestion of data via -SQL ``INSERT`` statements. Neither one can create databases or tables directly via SQL DDL -statements like ``CREATE DATABASE``, ``CREATE TABLE`` and similar. Instead, data must be ingested -into Qserv using a collection of the REST services. The services represent the Qserv Ingest -API (covered in `The Ingest Workflow Developer's Guide `_) which provides the functionaly complete -set of tools and instructions needed for ingesting and managing data in Qserv. There are several -reasons for this design choice: - -- Implementing a parser for the SQL DDL and DML statements is a complex and time-consuming process. - Implementing a correct semantic of the SQL statements in a realm of the distributed database - is even more dounting task. -- The performace of the SQL-based ingest protocol is not sufficient for the high-throughput data ingestion. - - **Note**: Qserv is designed to handle the data volumes of the order of many Petabytes. -- The REST services (unlike the simple text-based SQL statements) allow for more *structural* data formats - for user inputs such as schemas (``JSON``) and data (``CSV``). Verifying the syntactical and semantical - correctness of the data is easier when the data are structured. -- The REST services provide a reliable and transparent mechanism for managing and tracking the distributed - state of the data products within Qserv. -- Many operations on the REST services can be made idempotent and can be easily retried in case of failures. -- By not being bound to a particular SQL dialect, the REST services provide a more flexible and portable - interface for the data ingestion. The API can be extended to support new types of the data management requests, - new data formats and data sources as needed without changing the core of the Qserv engine. - -The API serves as a foundation for designing and implementing the data ingestion processes that -are loosely called the *ingest workflows*. There may be many such workflows depending on a particular -use case, the amount of data to be ingested, data delivery requirements, and the overall complexity -of the data. - -Read `The Ingest Workflow Developer's Guide `_ for further details on the REST services and their -usage. An explanation of a simple Kubernetes-based ingest workflow application `qserv-ingest `_ -is also provided in this documentation portal. - -Also note that a simple ingest API is provided by :ref:`http-frontend` for integsting and managing user tables. + intro + api/index + data/index + qserv-ingest/index diff --git a/doc/ingest/intro.rst b/doc/ingest/intro.rst new file mode 100644 index 000000000..ba2e365ea --- /dev/null +++ b/doc/ingest/intro.rst @@ -0,0 +1,37 @@ +.. _ingest-introduction: + +============ +Introduction +============ + +Unlike traditional RDBMS systems, Qserv does not support direct ingestion of data via +SQL ``INSERT`` or MySQL's ``LOAD DATA INFILE`` statements. Neither one can create databases or tables +directly via SQL DDL statements like ``CREATE DATABASE``, ``CREATE TABLE`` and similar. Instead, data +are ingested and managed via the Qserv Ingest REST API which is fully covered in `The Ingest Workflow Developer's Guide `_. +There are several reasons for this design choice: + +- Implementing a parser for the SQL DDL and DML statements is a complex and time-consuming process. + Implementing a correct semantic of the SQL statements in a realm of the distributed database + is even more dounting task. +- The performace of the SQL-based ingest protocol is not sufficient for the high-throughput data ingestion. + - **Note**: Qserv is designed to handle the data volumes of the order of many Petabytes. +- The REST services (unlike the simple text-based SQL statements) allow for more *structural* data formats + for user inputs such as schemas (``JSON``) and data (``CSV``). Verifying the syntactical and semantical + correctness of the data is easier when the data are structured. +- The REST services provide a reliable and transparent mechanism for managing and tracking the distributed + state of the data products within Qserv. +- Many operations on the REST services can be made idempotent and can be easily retried in case of failures. +- By not being bound to a particular SQL dialect, the REST services provide a more flexible and portable + interface for the data ingestion. The API can be extended to support new types of the data management requests, + new data formats and data sources as needed without changing the core of the Qserv engine. + +The API serves as a foundation for designing and implementing the data ingestion processes that +are loosely called the *ingest workflows*. There may be many such workflows depending on a particular +use case, the amount of data to be ingested, data delivery requirements, and the overall complexity +of the data. + +Read `The Ingest Workflow Developer's Guide `_ for further details on the REST services and their +usage. An explanation of a simple Kubernetes-based ingest workflow application `qserv-ingest `_ +is also provided in this documentation portal. + +Also note that a simple ingest API is provided by :ref:`http-frontend` for integsting and managing user tables. diff --git a/doc/user/http-frontend-ingest.rst b/doc/user/http-frontend-ingest.rst index ccee1d4c4..1255f9944 100644 --- a/doc/user/http-frontend-ingest.rst +++ b/doc/user/http-frontend-ingest.rst @@ -88,46 +88,9 @@ Where: The prefix is reserved for naming internal tables to be placed into user databases by Qserv. ``binary_encoding`` : *string* = ``hex`` - The optional format for encoding the binary data into JSON, where the following options for - the values of the parameter are allowed: + The optional binary encoding of the binary data in the table. For further details see: - - ``hex`` - for serializing each byte into the hexadecimal format of 2 ASCII characters per each byte - of the binary data, where the encoded characters will be in a range of ``0 .. F``. In this case, - the encoded value will be packaged into the JSON string. - - ``b64`` - for serializing bytes into a string using the ``Base64`` algorithm with padding (to ensure 4-byte alignment). - - ``array`` - for serializing bytes into the JSON array of numbers in a range of ``0 .. 255``. - - Here is an example of the same sequence of 4-bytes encoded into the hexadecimal format: - - .. code-block:: - - 0A11FFD2 - - The array representation of the same binary sequence would look like this: - - .. code-block:: json - - [10,17,255,210] - - MySQL types (regardless of the case) that include the following keywords are treated as binary: - - .. code-block:: sql - - BIT - BINARY - BLOB - - For example, these are the binary types: - - .. code-block:: sql - - BIT(1) - BINARY(8) - VARBINARY(16) - TINYBLOB - BLOB - MEDIUMBLOB - LONGBLOB + - :ref:`ingest-general-binary-encoding` ``schema`` : *array* The required schema definition. Each row of the array defined a column: diff --git a/doc/user/http-frontend-query.rst b/doc/user/http-frontend-query.rst index 284ff752b..f05d0d3db 100644 --- a/doc/user/http-frontend-query.rst +++ b/doc/user/http-frontend-query.rst @@ -40,26 +40,9 @@ Where: The optional name of the default database for queries where no such name was provided explicitly. ``binary_encoding`` : *string* = ``hex`` - The optional format for encoding the binary data into JSON: - - - ``hex`` - for serializing each byte into the hexadecimal format of 2 ASCII characters per each byte of - the binary data, where the encoded characters will be in a range of ``0 .. F``. In this case, - the encoded value will be packaged into the JSON string. - - ``b64`` - for serializing bytes into a string using the Base64 algorithm with - padding (to ensure 4-byte alignment). - - ``array`` - for serializing bytes into the JSON array of numbers in a range of ``0 … 255``. - - Here is an example of the same sequence of 4-bytes encoded into the hexadecimal format: + The optional binary encoding of the binary data in the table. For further details see: - .. code-block:: - - "0A11FFD2" - - The array representation of the same binary sequence would look like this: - - .. code-block:: - - [10,17,255,210] + - :ref:`ingest-general-binary-encoding` A call to this service will block a client application until one of the following events will happen: