diff --git a/doc/sphinx/_static/headers.js b/doc/sphinx/_static/headers.js index 6e5f577cfc7cc2796e9a1612b2dc4a849c3e5b57..c797fbb23c44fdf18a0487a0eb599b8eec1ebc8f 100644 --- a/doc/sphinx/_static/headers.js +++ b/doc/sphinx/_static/headers.js @@ -11,6 +11,17 @@ $(document).ready(function () { } } ); + $("[id^='lua-object'], [id^='lua-function'], [id^='lua-data']").each( + function(i, el) { + var icon = '<i class="fa fa-link"></i>'; + var hlink = $(el).find(".headerlink"); + var hlink_id = hlink.attr("href"); + if (typeof(hlink_id) != 'undefined') { + $(hlink).remove(); + $(el).prepend($("<a />").addClass("headerlink").attr("href", hlink_id).html(icon)); + } + } + ); $(".admonition.note p.first.admonition-title").each( function(i, el) { var icon = '<i class="fa fa-comments-o"></i>'; diff --git a/doc/sphinx/_static/sphinx_design.css b/doc/sphinx/_static/sphinx_design.css index 760feb48d4d87e9f3d201709a9abc0039231f607..e670f964e688b9608797185973474209508d5b99 100644 --- a/doc/sphinx/_static/sphinx_design.css +++ b/doc/sphinx/_static/sphinx_design.css @@ -13,6 +13,7 @@ } li.toctree-l1>a { color:#168de2; + font-size:20px; margin:0; text-decoration:none; @@ -187,7 +188,8 @@ a.headerlink { .b-article h2, .b-article h3, .b-article h4, -.b-article h5 { +.b-article h5, +.b-article h6 { margin: 16px 0 16px -25px; font-weight: bold; } @@ -211,12 +213,24 @@ a.headerlink { -ms-transition: opacity 0.2s ease-in-out 0.1s; } +[id^="lua-object" ], +[id^="lua-function"], +[id^="lua-data" ] { + margin-left: -25px; +} + +[id^="lua-object" ]:hover .headerlink, +[id^="lua-function"]:hover .headerlink, +[id^="lua-data" ]:hover .headerlink { + opacity: 1; +} + h2:hover .headerlink, h3:hover .headerlink, h4:hover .headerlink, h5:hover .headerlink, h6:hover .headerlink { - opacity: 1; + opacity: 1; } table.docutils.footnote { @@ -368,3 +382,70 @@ div.b-cols_content_left .b-search-text { float: left; position: relative; } + +.b-switcher-item-url { + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.b-tab_switcher { + display:inline-block; + border:2px solid #797979; + background:#fff; + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; + font-size: 0; + padding: 0px !important; +} + +.b-tab_switcher-item { + display:inline-block; + font-size:16px; + color:#262626; + border-right:2px solid #797979; + padding: 0px !important; +} +.b-tab_switcher-item:last-child { + border: 0; +} +.b-tab_switcher-item-url { + display:inline-block; + color:#797979; + text-decoration:none; + padding:8px 19px; + text-transform:uppercase; +} +.b-tab_switcher-item-url:hover { + background:#c9c9c9; + color:#fff +} +.b-tab_switcher-item-url.p-active { + background:#797979; + color:#fff; +} +.b-tab_switcher-item:first-child .b-tab_switcher-item-url { + -webkit-border-radius: 4px 0 0 0px; + -moz-border-radius: 4px 0 0 0px; + border-radius: 4px 0 0 0px; +} +.b-tab_switcher-item:last-child .b-tab_switcher-item-url { + -webkit-border-radius: 0 4px 0px 0; + -moz-border-radius: 0 4px 0px 0; + border-radius: 0 4px 0px 0; +} + +.b-documentation-tab-content { + border: 2px solid #797979; + margin-top: -2px; + padding: 5px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.b-documentation-tab div { + height: 100%; +} diff --git a/doc/sphinx/_templates/searchbox.html b/doc/sphinx/_templates/searchbox.html index 508b4b30257d4d207f3b38c565122adc9a9aec70..d2d38c46c82994c3186b50482ff6d58b1d145b46 100644 --- a/doc/sphinx/_templates/searchbox.html +++ b/doc/sphinx/_templates/searchbox.html @@ -1,6 +1,6 @@ {%- if builder != "singlehtml" %} <form id="searchbox" role="search" class="search b-search" action="{{ pathto('search') }}" method="get"> - <input class="b-search-text" name="q" type="text"/ placeholder="Search"> + <input class="b-search-text" name="q" type="text"/ placeholder="Search the manual"> <input class="b-search-but" type="submit" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> diff --git a/doc/sphinx/book/app_c_lua_tutorial.rst b/doc/sphinx/book/app_c_lua_tutorial.rst index 80e91273d86e300d010b2396934148102996765a..b04ccdd21f28df39f084505fdfa2f939d95320e8 100644 --- a/doc/sphinx/book/app_c_lua_tutorial.rst +++ b/doc/sphinx/book/app_c_lua_tutorial.rst @@ -511,7 +511,7 @@ that are declared in line 1, because all of them are for use only within the fun LINE 3: WHY "PAIRS()". Our job is to go through all the rows and there are two ways to do it: with ``box.space.space-name:pairs()`` or with -:func:`index.iterator <box.space.space-name.index[.index-name]:pairs>`. +:func:`index.iterator <index_object.pairs>`. We preferred ``pairs()`` because it is simpler. LINE 4: WHY "PCALL". If we simply said "``lua_table = json.decode(t[2]))``", then diff --git a/doc/sphinx/book/box/box_index.rst b/doc/sphinx/book/box/box_index.rst index 899ee23d44f428c609f5a44c9aeadaf370df490f..481d5a8a36b9e250822df79926a7c57423c72ef7 100644 --- a/doc/sphinx/book/box/box_index.rst +++ b/doc/sphinx/book/box/box_index.rst @@ -10,478 +10,480 @@ API is a direct binding to corresponding methods of index objects of type .. module:: box.index -.. data:: box.space.space-name.index.index-name.unique - - true if the index is unique. - - :rtype: boolean - -.. data:: box.space.space-name.index.index-name.type - - Index type, 'TREE' or 'HASH' or 'BITSET' or 'RTREE'. - - :rtype: string - -.. data:: box.space.space-name.index.index-name.parts - - An array describing index key fields. - - :rtype: table - - .. code-block:: lua - - tarantool> box.space.tester.index.primary - --- - unique: true - parts: - 0: - type: NUM - fieldno: 1 - id: 0 - space_id: 513 - name: primary - type: TREE - ... - -.. function:: box.space.space-name.index[.index-name]:pairs(bitset-value | field-value..., iterator-type) - - This method provides iteration support within an index. Parameter type is - used to identify the semantics of iteration. Different index types support - different iterators. The remaining arguments of the function are varying - and depend on the iteration type. For example, a TREE index maintains a - strict order of keys and can return all tuples in ascending or descending - order, starting from the specified key. Other index types, however, do not - support ordering. - - To understand consistency of tuples returned by an iterator, it's essential - to know the principles of the Tarantool transaction processing subsystem. An - iterator in Tarantool does not own a consistent read view. Instead, each - procedure is granted exclusive access to all tuples and spaces until it - encounters a "context switch": by causing a write to disk, network, or by an - explicit call to :func:`fiber.yield`. When the execution flow returns - to the yielded procedure, the data set could have changed significantly. - Iteration, resumed after a yield point, does not preserve the read view, - but continues with the new content of the database. - - :param type: iteration strategy as defined in tables below - :return: this method returns an iterator closure, i.e. a function which can - be used to get the next value on each invocation - :rtype: function, tuple - - :except: Selected iteration type is not supported in the subject index type, - or supplied parameters do not match iteration type. - - Complexity Factors: Index size, Index type, Number of tuples accessed. - - .. container:: table - - **TREE iterator types** - - +---------------+-----------+---------------------------------------------+ - | Type | Arguments | Description | - +===============+===========+=============================================+ - | box.index.ALL | none | Iterate over all tuples in an index. Tuples | - | or 'ALL' | | are returned in ascending order of the key. | - +---------------+-----------+---------------------------------------------+ - | box.index.EQ | field | Equality iterator: iterate over all tuples | - | or 'EQ' | values | where field values = key values. Parts of a | - | | | multi-part key need to be separated by | - | | | commas. | - | | | | - | | | If the number of field values is less than | - | | | the number of parts of a multi-part key, | - | | | the missing field values are considered to | - | | | be matching. | - | | | | - | | | If there are multiple matches, then tuples | - | | | are returned in ascending order by key. | - +---------------+-----------+---------------------------------------------+ - | box.index.GT | field | Keys match if key values are greater than | - | or 'GT' | values | field values. If the number of field values | - | | | is less than the number of parts of a | - | | | multi-part key, the missing field values | - | | | are considered to be matching. If the field | - | | | value is ``nil``, iteration starts from the | - | | | smallest key in the index. Tuples are | - | | | returned in ascending order by key. | - +---------------+-----------+---------------------------------------------+ - | box.index.REQ | field | Reverse equality iterator. Matching is | - | or 'REQ' | values | determined in the same way as for | - | | | ``box.index.EQ``, but, if there are multiple| - | | | matches, then tuples are returned in | - | | | descending order by key, | - +---------------+-----------+---------------------------------------------+ - | box.index.GE | field | Keys match if key values are greater than | - | or 'GE' | values | or equal to field values. Tuples are | - | | | returned in ascending order by key. If the | - | | | field value is ``nil``, iteration starts | - | | | from the first key in the index. | - +---------------+-----------+---------------------------------------------+ - | box.index.LT | field | Keys match if key values are less than | - | or 'LT' | values | field values. Tuples are returned in | - | | | descending order by key. If the field value | - | | | is ``nil``, iteration starts from the last | - | | | key in the index. | - +---------------+-----------+---------------------------------------------+ - | box.index.LE | field | Keys match if key values are less than or | - | or 'LE' | values | equal to field values. Tuples are returned | - | | | in descending order by key. If the field | - | | | value is ``nil``, iteration starts from | - | | | the last key in the index. | - +---------------+-----------+---------------------------------------------+ - - **HASH iterator types** - - +---------------+-----------+---------------------------------------------+ - | Type | Arguments | Description | - +===============+===========+=============================================+ - | box.index.ALL | none | Iterate over all tuples in an index. Tuples | - | or 'ALL' | | are returned in ascending order of the key. | - +---------------+-----------+---------------------------------------------+ - | box.index.EQ | field | Equality iterator: iterate over all tuples | - | or 'EQ' | values | matching the key. Parts of a multi-part | - | | | key need to be separated by commas. | - | | | | - | | | A HASH index only supports exact match: | - | | | all parts of a key participating in the | - | | | index must be provided. | - | | | | - | | | HASH indexes are always unique. | - +---------------+-----------+---------------------------------------------+ - | box.index.GT | field | Keys match if hashed key values are greater | - | or 'GT' | values | than hashed field values. If the number of | - | | | field values is less than the number of | - | | | parts of a multi-part key, the result is an | - | | | error. Tuples are returned in ascending | - | | | order by hashed key, so the order will | - | | | appear to be random. Provided that the | - | | | space is not being updated, the 'GT' | - | | | iterator can be used to retrieve all | - | | | tuples piece by piece, by supplying the | - | | | last returned value from the previous | - | | | range as the start field value for an | - | | | iterator over the next range. | - +---------------+-----------+---------------------------------------------+ - - **BITSET iterator types** - - +----------------------------+-----------+---------------------------------------------+ - | Type | Arguments | Description | - +============================+===========+=============================================+ - | box.index.ALL | none | Iterate over all tuples in an index. Tuples | - | or 'ALL' | | are returned in ascending order of the | - | | | key's bitset, and so will appear to be | - | | | unordered. | - +----------------------------+-----------+---------------------------------------------+ - | box.index.EQ | field | Equality iterator: iterate over all tuples | - | or 'EQ' | values | matching the field values. If there are | - | | | multiple field values, they need to be | - | | | separated by commas. | - | | | | - | | | BITSET indexes are always unique. | - +----------------------------+-----------+---------------------------------------------+ - | box.index.BITS_ALL_SET | field | Keys match if all of the bits specified in | - | | values | 'bit mask' are set. | - +----------------------------+-----------+---------------------------------------------+ - | box.index.BITS_ANY_SET | field | Keys match if any of the bits specified in | - | | values | 'bit mask' is set. | - +----------------------------+-----------+---------------------------------------------+ - | box.index.BITS_ALL_NOT_SET | field | Keys match if none of the bits specified in | - | | values | 'bit mask' is set. | - +----------------------------+-----------+---------------------------------------------+ - - .. _rtree-iterator: - - **RTREE iterator types** - - +--------------------+-----------+---------------------------------------------+ - | Type | Arguments | Description | - +====================+===========+=============================================+ - | box.index.ALL | none | All keys match. Tuples are returned in | - | or 'ALL' | | ascending order of the primary key. | - +--------------------+-----------+---------------------------------------------+ - | box.index.EQ | field | Keys match if the rectangle defined by the | - | or 'EQ' | values | field values is the same as the rectangle | - | | | defined by the key -- where "key" means | - | | | "the key in the RTREE index" and | - | | | "rectangle" means "rectangle as explained | - | | | in section RTREE_. | - +--------------------+-----------+---------------------------------------------+ - | box.index.GT | field | Keys match if all points of the rectangle | - | or 'GT' | values | defined by the field values are within the | - | | | rectangle defined by the key. | - +--------------------+-----------+---------------------------------------------+ - | box.index.GE | field | Keys match if all points of the rectangle | - | or 'GE' | values | defined by the field values are within, or | - | | | at the side of, the rectangle defined by | - | | | the key. | - +--------------------+-----------+---------------------------------------------+ - | box.index.LT | field | Keys match if all points of the rectangle | - | or 'LT' | values | defined by the key are within the rectangle | - | | | defined by the field values. | - +--------------------+-----------+---------------------------------------------+ - | box.index.LE | field | Keys match if all points of the rectangle | - | or 'LE' | values | defined by the key are within, or at the | - | | | side of, the rectangle defined by the field | - | | | values. | - +--------------------+-----------+---------------------------------------------+ - | box.index.OVERLAPS | field | Keys match if all points of the rectangle | - | or 'OVERLAPS' | values | defined by the key are within, or at the | - | | | side of, the rectangle defined by the field | - | | | values. | - +--------------------+-----------+---------------------------------------------+ - | box.index.NEIGHBOR | field | Keys match if all points of the rectangle | - | or 'NEIGHBOR' | values | defined by the key are within, or at the | - | | | side of, the rectangle defined by the field | - | | | values. | - +--------------------+-----------+---------------------------------------------+ - - .. code-block:: lua - - tarantool> s = box.schema.space.create('space17') - --- - ... - tarantool> s:create_index('primary', {parts = {1, 'STR', 2, 'STR'}}) - --- - ... - tarantool> s:insert{'C', 'C'} - --- - - ['C', 'C'] - ... - tarantool> s:insert{'B', 'A'} - --- - - ['B', 'A'] - ... - tarantool> s:insert{'C', '!'} - --- - - ['C', '!'] - ... - tarantool> s:insert{'A', 'C'} - --- - - ['A', 'C'] - ... - tarantool> console = require('console'); console.delimiter('!') - --- - ... - tarantool> function example() - > for _, tuple in - > s.index.primary:pairs(nil, {iterator = box.index.ALL}) do - > print(tuple) - > end - > end! - --- - ... - tarantool> console.delimiter('')! - --- - ... - tarantool> example() - ['A', 'C'] - ['B', 'A'] - ['C', '!'] - ['C', 'C'] - --- - ... - tarantool> s:drop() - --- - ... - -.. function:: box.space.space-name[.index.index-name]:select({[field-value [, field-value ...]]}, {[option [, option ...]]}) - - This is is an alternative to box.space...select() which goes via a - particular index and can make use of additional parameters that specify the - iterator type, and the limit (that is, the maximum number of tuples to - return) and the offset (that is, which tuple to start with in the list). - - :param lua-value field-value(s): values to be matched against the index key. - :param lua-value option(s): any or all of iterator=iterator-type - limit=maximum-number-of-tuples, - offset=start-tuple-number. - - :return: the tuple or tuples that match the field values. - :rtype: tuple set as a Lua table - - .. code-block:: lua - - -- Create a space named tester. - -- Create a unique index 'primary', which won't be needed for this example. - -- Create a non-unique index 'secondary' with an index on the second field. - -- Insert three tuples, values in field[2] equal to 'X', 'Y', and 'Z'. - -- Select all tuples where the secondary index keys are greater than 'X'. - box.schema.space.create('tester') - box.space.tester:create_index('primary', {parts = {1, 'NUM' }}) - box.space.tester:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'STR'}}) - box.space.tester:insert{1,'X','Row with field[2]=X'} - box.space.tester:insert{2,'Y','Row with field[2]=Y'} - box.space.tester:insert{3,'Z','Row with field[2]=Z'} - box.space.tester.index.secondary:select({'X'}, {iterator = 'GT', limit = 1000}) - - The result will be a table of tuple and will look like this: - - .. code-block:: yaml - - --- - - - [2, 'Y', 'Row with field[2]=Y'] - - [3, 'Z', 'Row with field[2]=Z'] - ... - - .. NOTE:: - - [.index.index-name] is optional. If it is omitted, then the assumed - index is the first (primary-key) index. Therefore, for the example - above, ``box.space.tester:select({1}, {iterator = 'GT'})`` would have - returned the same two rows, via the 'primary' index. - - .. NOTE:: - - ``iterator = iterator type`` is optional. If it is omitted, then - ``iterator = 'EQ'`` is assumed. - - .. NOTE:: - - ``field-value [, field-value ...]`` is optional. If it is omitted, - then every key in the index is considered to be a match, regardless of - iterator type. Therefore, for the example above, - ``box.space.tester:select{}`` will select every tuple in the tester - space via the first (primary-key) index. - - .. NOTE:: - - ``box.space.space-name.index.index-name:select(...)[1]``. can be - replaced by ``box.space.space-name.index.index-name:get(...)``. - That is, get can be used as a convenient shorthand to get the first - tuple in the tuple set that would be returned by select. However, - if there is more than one tuple in the tuple set, then get returns - an error. - -.. function:: box.space.space-name.index.index-name:min([key-value]) +.. class:: index_object + + .. data:: unique + + true if the index is unique. + + :rtype: boolean + + .. data:: type + + Index type, 'TREE' or 'HASH' or 'BITSET' or 'RTREE'. + + :rtype: string + + .. data:: parts + + An array describing index key fields. + + :rtype: table + + .. code-block:: lua + + tarantool> box.space.tester.index.primary + --- + unique: true + parts: + 0: + type: NUM + fieldno: 1 + id: 0 + space_id: 513 + name: primary + type: TREE + ... + + .. function:: pairs(bitset-value | field-value..., iterator-type) + + This method provides iteration support within an index. Parameter type is + used to identify the semantics of iteration. Different index types support + different iterators. The remaining arguments of the function are varying + and depend on the iteration type. For example, a TREE index maintains a + strict order of keys and can return all tuples in ascending or descending + order, starting from the specified key. Other index types, however, do not + support ordering. + + To understand consistency of tuples returned by an iterator, it's essential + to know the principles of the Tarantool transaction processing subsystem. An + iterator in Tarantool does not own a consistent read view. Instead, each + procedure is granted exclusive access to all tuples and spaces until it + encounters a "context switch": by causing a write to disk, network, or by an + explicit call to :func:`fiber.yield`. When the execution flow returns + to the yielded procedure, the data set could have changed significantly. + Iteration, resumed after a yield point, does not preserve the read view, + but continues with the new content of the database. + + :param type: iteration strategy as defined in tables below + :return: this method returns an iterator closure, i.e. a function which can + be used to get the next value on each invocation + :rtype: function, tuple + + :except: Selected iteration type is not supported in the subject index type, + or supplied parameters do not match iteration type. + + Complexity Factors: Index size, Index type, Number of tuples accessed. + + .. container:: table + + **TREE iterator types** + + +---------------+-----------+---------------------------------------------+ + | Type | Arguments | Description | + +===============+===========+=============================================+ + | box.index.ALL | none | Iterate over all tuples in an index. Tuples | + | or 'ALL' | | are returned in ascending order of the key. | + +---------------+-----------+---------------------------------------------+ + | box.index.EQ | field | Equality iterator: iterate over all tuples | + | or 'EQ' | values | where field values = key values. Parts of a | + | | | multi-part key need to be separated by | + | | | commas. | + | | | | + | | | If the number of field values is less than | + | | | the number of parts of a multi-part key, | + | | | the missing field values are considered to | + | | | be matching. | + | | | | + | | | If there are multiple matches, then tuples | + | | | are returned in ascending order by key. | + +---------------+-----------+---------------------------------------------+ + | box.index.GT | field | Keys match if key values are greater than | + | or 'GT' | values | field values. If the number of field values | + | | | is less than the number of parts of a | + | | | multi-part key, the missing field values | + | | | are considered to be matching. If the field | + | | | value is ``nil``, iteration starts from the | + | | | smallest key in the index. Tuples are | + | | | returned in ascending order by key. | + +---------------+-----------+---------------------------------------------+ + | box.index.REQ | field | Reverse equality iterator. Matching is | + | or 'REQ' | values | determined in the same way as for | + | | | ``box.index.EQ``, but, if there are multiple| + | | | matches, then tuples are returned in | + | | | descending order by key, | + +---------------+-----------+---------------------------------------------+ + | box.index.GE | field | Keys match if key values are greater than | + | or 'GE' | values | or equal to field values. Tuples are | + | | | returned in ascending order by key. If the | + | | | field value is ``nil``, iteration starts | + | | | from the first key in the index. | + +---------------+-----------+---------------------------------------------+ + | box.index.LT | field | Keys match if key values are less than | + | or 'LT' | values | field values. Tuples are returned in | + | | | descending order by key. If the field value | + | | | is ``nil``, iteration starts from the last | + | | | key in the index. | + +---------------+-----------+---------------------------------------------+ + | box.index.LE | field | Keys match if key values are less than or | + | or 'LE' | values | equal to field values. Tuples are returned | + | | | in descending order by key. If the field | + | | | value is ``nil``, iteration starts from | + | | | the last key in the index. | + +---------------+-----------+---------------------------------------------+ + + **HASH iterator types** + + +---------------+-----------+---------------------------------------------+ + | Type | Arguments | Description | + +===============+===========+=============================================+ + | box.index.ALL | none | Iterate over all tuples in an index. Tuples | + | or 'ALL' | | are returned in ascending order of the key. | + +---------------+-----------+---------------------------------------------+ + | box.index.EQ | field | Equality iterator: iterate over all tuples | + | or 'EQ' | values | matching the key. Parts of a multi-part | + | | | key need to be separated by commas. | + | | | | + | | | A HASH index only supports exact match: | + | | | all parts of a key participating in the | + | | | index must be provided. | + | | | | + | | | HASH indexes are always unique. | + +---------------+-----------+---------------------------------------------+ + | box.index.GT | field | Keys match if hashed key values are greater | + | or 'GT' | values | than hashed field values. If the number of | + | | | field values is less than the number of | + | | | parts of a multi-part key, the result is an | + | | | error. Tuples are returned in ascending | + | | | order by hashed key, so the order will | + | | | appear to be random. Provided that the | + | | | space is not being updated, the 'GT' | + | | | iterator can be used to retrieve all | + | | | tuples piece by piece, by supplying the | + | | | last returned value from the previous | + | | | range as the start field value for an | + | | | iterator over the next range. | + +---------------+-----------+---------------------------------------------+ + + **BITSET iterator types** + + +----------------------------+-----------+---------------------------------------------+ + | Type | Arguments | Description | + +============================+===========+=============================================+ + | box.index.ALL | none | Iterate over all tuples in an index. Tuples | + | or 'ALL' | | are returned in ascending order of the | + | | | key's bitset, and so will appear to be | + | | | unordered. | + +----------------------------+-----------+---------------------------------------------+ + | box.index.EQ | field | Equality iterator: iterate over all tuples | + | or 'EQ' | values | matching the field values. If there are | + | | | multiple field values, they need to be | + | | | separated by commas. | + | | | | + | | | BITSET indexes are always unique. | + +----------------------------+-----------+---------------------------------------------+ + | box.index.BITS_ALL_SET | field | Keys match if all of the bits specified in | + | | values | 'bit mask' are set. | + +----------------------------+-----------+---------------------------------------------+ + | box.index.BITS_ANY_SET | field | Keys match if any of the bits specified in | + | | values | 'bit mask' is set. | + +----------------------------+-----------+---------------------------------------------+ + | box.index.BITS_ALL_NOT_SET | field | Keys match if none of the bits specified in | + | | values | 'bit mask' is set. | + +----------------------------+-----------+---------------------------------------------+ + + .. _rtree-iterator: + + **RTREE iterator types** + + +--------------------+-----------+---------------------------------------------+ + | Type | Arguments | Description | + +====================+===========+=============================================+ + | box.index.ALL | none | All keys match. Tuples are returned in | + | or 'ALL' | | ascending order of the primary key. | + +--------------------+-----------+---------------------------------------------+ + | box.index.EQ | field | Keys match if the rectangle defined by the | + | or 'EQ' | values | field values is the same as the rectangle | + | | | defined by the key -- where "key" means | + | | | "the key in the RTREE index" and | + | | | "rectangle" means "rectangle as explained | + | | | in section RTREE_. | + +--------------------+-----------+---------------------------------------------+ + | box.index.GT | field | Keys match if all points of the rectangle | + | or 'GT' | values | defined by the field values are within the | + | | | rectangle defined by the key. | + +--------------------+-----------+---------------------------------------------+ + | box.index.GE | field | Keys match if all points of the rectangle | + | or 'GE' | values | defined by the field values are within, or | + | | | at the side of, the rectangle defined by | + | | | the key. | + +--------------------+-----------+---------------------------------------------+ + | box.index.LT | field | Keys match if all points of the rectangle | + | or 'LT' | values | defined by the key are within the rectangle | + | | | defined by the field values. | + +--------------------+-----------+---------------------------------------------+ + | box.index.LE | field | Keys match if all points of the rectangle | + | or 'LE' | values | defined by the key are within, or at the | + | | | side of, the rectangle defined by the field | + | | | values. | + +--------------------+-----------+---------------------------------------------+ + | box.index.OVERLAPS | field | Keys match if all points of the rectangle | + | or 'OVERLAPS' | values | defined by the key are within, or at the | + | | | side of, the rectangle defined by the field | + | | | values. | + +--------------------+-----------+---------------------------------------------+ + | box.index.NEIGHBOR | field | Keys match if all points of the rectangle | + | or 'NEIGHBOR' | values | defined by the key are within, or at the | + | | | side of, the rectangle defined by the field | + | | | values. | + +--------------------+-----------+---------------------------------------------+ + + .. code-block:: lua + + tarantool> s = box.schema.space.create('space17') + --- + ... + tarantool> s:create_index('primary', {parts = {1, 'STR', 2, 'STR'}}) + --- + ... + tarantool> s:insert{'C', 'C'} + --- + - ['C', 'C'] + ... + tarantool> s:insert{'B', 'A'} + --- + - ['B', 'A'] + ... + tarantool> s:insert{'C', '!'} + --- + - ['C', '!'] + ... + tarantool> s:insert{'A', 'C'} + --- + - ['A', 'C'] + ... + tarantool> console = require('console'); console.delimiter('!') + --- + ... + tarantool> function example() + > for _, tuple in + > s.index.primary:pairs(nil, {iterator = box.index.ALL}) do + > print(tuple) + > end + > end! + --- + ... + tarantool> console.delimiter('')! + --- + ... + tarantool> example() + ['A', 'C'] + ['B', 'A'] + ['C', '!'] + ['C', 'C'] + --- + ... + tarantool> s:drop() + --- + ... + + .. function:: select(key, options) + + This is is an alternative to box.space...select() which goes via a + particular index and can make use of additional parameters that specify the + iterator type, and the limit (that is, the maximum number of tuples to + return) and the offset (that is, which tuple to start with in the list). + + :param lua-table or scalar key: values to be matched against the index key. + :param lua-table options: table with any or all of iterator=iterator-type + limit=maximum-number-of-tuples, + offset=start-tuple-number. + + :return: the tuple or tuples that match the field values. + :rtype: tuple set as a Lua table + + .. code-block:: lua + + -- Create a space named tester. + -- Create a unique index 'primary', which won't be needed for this example. + -- Create a non-unique index 'secondary' with an index on the second field. + -- Insert three tuples, values in field[2] equal to 'X', 'Y', and 'Z'. + -- Select all tuples where the secondary index keys are greater than 'X'. + box.schema.space.create('tester') + box.space.tester:create_index('primary', {parts = {1, 'NUM' }}) + box.space.tester:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'STR'}}) + box.space.tester:insert{1,'X','Row with field[2]=X'} + box.space.tester:insert{2,'Y','Row with field[2]=Y'} + box.space.tester:insert{3,'Z','Row with field[2]=Z'} + box.space.tester.index.secondary:select({'X'}, {iterator = 'GT', limit = 1000}) + + The result will be a table of tuple and will look like this: + + .. code-block:: yaml + + --- + - - [2, 'Y', 'Row with field[2]=Y'] + - [3, 'Z', 'Row with field[2]=Z'] + ... + + .. NOTE:: + + [.index.index-name] is optional. If it is omitted, then the assumed + index is the first (primary-key) index. Therefore, for the example + above, ``box.space.tester:select({1}, {iterator = 'GT'})`` would have + returned the same two rows, via the 'primary' index. + + .. NOTE:: + + ``iterator = iterator type`` is optional. If it is omitted, then + ``iterator = 'EQ'`` is assumed. + + .. NOTE:: + + ``field-value [, field-value ...]`` is optional. If it is omitted, + then every key in the index is considered to be a match, regardless of + iterator type. Therefore, for the example above, + ``box.space.tester:select{}`` will select every tuple in the tester + space via the first (primary-key) index. + + .. NOTE:: + + ``box.space.space-name.index.index-name:select(...)[1]``. can be + replaced by ``box.space.space-name.index.index-name:get(...)``. + That is, get can be used as a convenient shorthand to get the first + tuple in the tuple set that would be returned by select. However, + if there is more than one tuple in the tuple set, then get returns + an error. + + .. function:: min([key-value]) - Find the minimum value in the specified index. + Find the minimum value in the specified index. - :return: the tuple for the first key in the index. If optional - ``key-value`` is supplied, returns the first key which - is greater than or equal to ``key-value``. - :rtype: tuple - :except: index is not of type 'TREE'. + :return: the tuple for the first key in the index. If optional + ``key-value`` is supplied, returns the first key which + is greater than or equal to ``key-value``. + :rtype: tuple + :except: index is not of type 'TREE'. - Complexity Factors: Index size, Index type. + Complexity Factors: Index size, Index type. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.tester.index.primary:min() - --- - - ['Alpha!', 55, 'This is the first tuple!'] - ... + tarantool> box.space.tester.index.primary:min() + --- + - ['Alpha!', 55, 'This is the first tuple!'] + ... -.. function:: box.space.space-name.index.index-name:max([key-value]) + .. function:: max([key-value]) - Find the maximum value in the specified index. + Find the maximum value in the specified index. - :return: the tuple for the last key in the index. If optional ``key-value`` - is supplied, returns the last key which is less than or equal to - ``key-value``. - :rtype: tuple - :except: index is not of type 'TREE'. + :return: the tuple for the last key in the index. If optional ``key-value`` + is supplied, returns the last key which is less than or equal to + ``key-value``. + :rtype: tuple + :except: index is not of type 'TREE'. - Complexity Factors: Index size, Index type. + Complexity Factors: Index size, Index type. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.tester.index.primary:max() - --- - - ['Gamma!', 55, 'This is the third tuple!'] - ... + tarantool> box.space.tester.index.primary:max() + --- + - ['Gamma!', 55, 'This is the third tuple!'] + ... -.. function:: box.space.space-name.index.index-name:random(random-value) + .. function:: random(random-value) - Find a random value in the specified index. This method is useful when it's - important to get insight into data distribution in an index without having - to iterate over the entire data set. + Find a random value in the specified index. This method is useful when it's + important to get insight into data distribution in an index without having + to iterate over the entire data set. - :param integer random-value: an arbitrary non-negative integer. - :return: the tuple for the random key in the index. - :rtype: tuple + :param integer random-value: an arbitrary non-negative integer. + :return: the tuple for the random key in the index. + :rtype: tuple - Complexity Factors: Index size, Index type. + Complexity Factors: Index size, Index type. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.tester.index.secondary:random(1) - --- - - ['Beta!', 66, 'This is the second tuple!'] - ... + tarantool> box.space.tester.index.secondary:random(1) + --- + - ['Beta!', 66, 'This is the second tuple!'] + ... -.. function:: box.space.space-name.index.index-name:count(key-value, options) + .. function:: count(key-value, options) - Iterate over an index, counting the number of - tuples which equal the provided search criteria. + Iterate over an index, counting the number of + tuples which equal the provided search criteria. - :param lua-value key-value: the value which must match the key(s) in the - specified index. The type may be a list of - field-values, or a tuple containing only - the field-values. + :param lua-value key-value: the value which must match the key(s) in the + specified index. The type may be a list of + field-values, or a tuple containing only + the field-values. - :return: the number of matching index keys. The ``index`` function - is only applicable for the memtx storage engine. - :rtype: number + :return: the number of matching index keys. The ``index`` function + is only applicable for the memtx storage engine. + :rtype: number - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.tester.index.primary:count(999) - --- - - 0 - ... - tarantool> box.space.tester.index.primary:count('Alpha!', { iterator = 'LE' }) - --- - - 1 - ... + tarantool> box.space.tester.index.primary:count(999) + --- + - 0 + ... + tarantool> box.space.tester.index.primary:count('Alpha!', { iterator = 'LE' }) + --- + - 1 + ... -.. function:: box.space.space-name.index.index-name:alter{options} + .. function:: alter({options}) - Alter an index. + Alter an index. - :param table options: options list for create_index(). - :return: nil + :param table options: options list for create_index(). + :return: nil - :except: If index-name doesn't exist. - :except: The first index cannot be changed to {unique = false}. - :except: The alter function is only applicable for the memtx storage engine. + :except: If index-name doesn't exist. + :except: The first index cannot be changed to {unique = false}. + :except: The alter function is only applicable for the memtx storage engine. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.space55.index.primary:alter({type = 'HASH'}) - --- - ... + tarantool> box.space.space55.index.primary:alter({type = 'HASH'}) + --- + ... -.. function:: space-name.index.index-name:drop() + .. function:: drop() - Drop an index. Dropping a primary-key index has - a side effect: all tuples are deleted. + Drop an index. Dropping a primary-key index has + a side effect: all tuples are deleted. - :return: nil. - :except: If index-name doesn't exist. + :return: nil. + :except: If index-name doesn't exist. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.space55.index.primary:drop() - --- - ... + tarantool> box.space.space55.index.primary:drop() + --- + ... -.. function:: space-name.index.index-name:rename(index-name) + .. function:: rename(index-name) - Rename an index. + Rename an index. - :param string index-name: new name for index. - :return: nil - :except: If index-name doesn't exist. + :param string index-name: new name for index. + :return: nil + :except: If index-name doesn't exist. - .. code-block:: lua + .. code-block:: lua - tarantool> box.space.space55.index.primary:rename('secondary') - --- - ... + tarantool> box.space.space55.index.primary:rename('secondary') + --- + ... - Complexity Factors: Index size, Index type, Number of tuples accessed. + Complexity Factors: Index size, Index type, Number of tuples accessed. =========================================================== diff --git a/doc/sphinx/book/box/box_schema.rst b/doc/sphinx/book/box/box_schema.rst index 8b6bdebc740c5702229e799299860279e43ad8b8..ce26ff70c6a2ca73df8e2b36a4db1d2f045608c4 100644 --- a/doc/sphinx/book/box/box_schema.rst +++ b/doc/sphinx/book/box/box_schema.rst @@ -55,6 +55,6 @@ The ``box.schema`` package has one data-definition function: ``space.create()``. ... After a space is created, usually the next step is to -:func:`create an index <box.space.space-name.create_index>` for it, +:func:`create an index <space_object.create_index>` for it, and then it is available for insert, select, and all the other :mod:`box.space` functions. diff --git a/doc/sphinx/book/box/box_space.rst b/doc/sphinx/book/box/box_space.rst index 0ba777a62beb3cd2a5f01164268287431925985a..8fa06ed36d5b7c32ad9e2b8ecdaf25da632e855a 100644 --- a/doc/sphinx/book/box/box_space.rst +++ b/doc/sphinx/book/box/box_space.rst @@ -13,566 +13,586 @@ is available in file A list of all ``box.space`` functions follows, then comes a list of all ``box.space`` members. -.. function:: box.space.space-name:create_index(index-name [, {options} ]) - - Create an index. It is **mandatory** to create an index for a tuple set - before trying to insert tuples into it, or select tuples from it. The - first created index, which will be used as the primary-key index, must be - **unique**. - - :param string index-name: name of index, which should not be a number and - should not contain special characters; - :param table options: - - :return: index object - :rtype: userdata - - .. container:: table - - **Options for box.space...create_index** - - +---------------+--------------------+-----------------------------+---------------------+ - | Name | Effect | Type | Default | - +===============+====================+=============================+=====================+ - | type | type of index | string | 'TREE' | - | | | ('HASH', 'TREE', | | - | | | 'BITSET', 'RTREE') | | - | | | | | - | | | | | - | | | | | - +---------------+--------------------+-----------------------------+---------------------+ - | id | unique identifier | number | last index's id, +1 | - +---------------+--------------------+-----------------------------+---------------------+ - | unique | index is unique | boolean | true | - +---------------+--------------------+-----------------------------+---------------------+ - | if_not_exists | no error if | boolean | false | - | | duplicate name | | | - +---------------+--------------------+-----------------------------+---------------------+ - | parts | field-numbers + | ``{field_no, 'NUM'|'STR'}`` | ``{1, 'NUM'}`` | - | | types | | | - +---------------+--------------------+-----------------------------+---------------------+ - - Possible errors: too many parts. A type options other than TREE, or a - unique option other than unique, or a parts option with more than one - field component, is only applicable for the memtx storage engine. +.. class:: space_object - .. code-block:: lua + .. function:: create_index(index-name [, {options} ]) - tarantool> s = box.space.space55 - --- - ... - tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) - --- - ... + Create an index. It is **mandatory** to create an index for a tuple set + before trying to insert tuples into it, or select tuples from it. The + first created index, which will be used as the primary-key index, must be + **unique**. -.. function:: box.space.space-name:insert{field-value [, field-value ...]} + :param string index-name: name of index, which should not be a number and + should not contain special characters; + :param table options: - Insert a tuple into a space. + :return: index object + :rtype: index_object - :param userdata space-name: - :param lua-value field-value(s): fields of the new tuple. - :return: the inserted tuple - :rtype: tuple + .. container:: table - :except: If a tuple with the same unique-key value already exists, - returns ``ER_TUPLE_FOUND``. + **Options table** - .. code-block:: lua - - box.space.tester:insert{5000,'tuple number five thousand'} + +---------------+--------------------+-----------------------------+---------------------+ + | Name | Effect | Type | Default | + +===============+====================+=============================+=====================+ + | type | type of index | string | 'TREE' | + | | | ('HASH', 'TREE', | | + | | | 'BITSET', 'RTREE') | | + | | | | | + | | | | | + | | | | | + +---------------+--------------------+-----------------------------+---------------------+ + | id | unique identifier | number | last index's id, +1 | + +---------------+--------------------+-----------------------------+---------------------+ + | unique | index is unique | boolean | true | + +---------------+--------------------+-----------------------------+---------------------+ + | if_not_exists | no error if | boolean | false | + | | duplicate name | | | + +---------------+--------------------+-----------------------------+---------------------+ + | parts | field-numbers + | ``{field_no, 'NUM'|'STR'}`` | ``{1, 'NUM'}`` | + | | types | | | + +---------------+--------------------+-----------------------------+---------------------+ -.. function:: box.space.space-name:select{field-value [, field-value ...]} + Possible errors: too many parts. A type options other than TREE, or a + unique option other than unique, or a parts option with more than one + field component, is only applicable for the memtx storage engine. - Search for a tuple or a set of tuples in the given space. + .. code-block:: lua - :param userdata space-name: - :param lua-value field-value(s): values to be matched against the index - key, which may be multi-part. + tarantool> s = box.space.space55 + --- + ... + tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) + --- + ... - :return: the tuples whose primary-key fields are equal to the passed - field-values. If the number of passed field-values is less - than the number of fields in the primary key, then only the - passed field-values are compared, so ``select{1,2}`` will match - a tuple whose primary key is ``{1,2,3}``. - :rtype: tuple + .. function:: insert(tuple) - :except: No such space; wrong type. + Insert a tuple into a space. - Complexity Factors: Index size, Index type. + :param space_object space-object: + :param lua-table,box.tuple tuple: tuple to be inserted. + :return: the inserted tuple + :rtype: tuple - .. code-block:: lua + Possible errors: If a tuple with the same unique-key value already exists, + returns :errcode:`ER_TUPLE_FOUND`. - tarantool> s = box.schema.space.create('tmp', {temporary=true}) - --- - ... - tarantool> s:create_index('primary',{parts = {1,'NUM', 2, 'STR'}}) - --- - ... - tarantool> s:insert{1,'A'} - --- - - [1, 'A'] - ... - tarantool> s:insert{1,'B'} - --- - - [1, 'B'] - ... - tarantool> s:insert{1,'C'} - --- - - [1, 'C'] - ... - tarantool> s:insert{2,'D'} - --- - - [2, 'D'] - ... - tarantool> -- must equal both primary-key fields - tarantool> s:select{1,'B'} - --- - - - [1, 'B'] - ... - tarantool> -- must equal only one primary-key field - tarantool> s:select{1} - --- - - - [1, 'A'] - - [1, 'B'] - - [1, 'C'] - ... - tarantool> -- must equal 0 fields, so returns all tuples - tarantool> s:select{} - --- - - - [1, 'A'] - - [1, 'B'] - - [1, 'C'] - - [2, 'D'] - ... + .. code-block:: lua - For examples of complex ``select`` requests, where one can specify which index to - search and what condition to use (for example "greater than" instead of - "equal to") and how many tuples to return, see the later section - ``box.space.space-name[.index.index-name]:select``. + box.space.tester:insert{5000,'tuple number five thousand'} -.. function:: box.space.space-name:get{field-value [, field-value ...]} + .. function:: select(key) - Search for a tuple in the given space. + Search for a tuple or a set of tuples in the given space. - :param userdata space-name: - :param lua-value field-value(s): values to be matched against the index + :param space_object space-object: + :param lua-table,scalar key: key to be matched against the index key, which may be multi-part. - :return: the selected tuple. - :rtype: tuple - - :except: If space-name does not exist. - - Complexity Factors: Index size, Index type, - Number of indexes accessed, WAL settings. - - .. code-block:: lua - - tarantool> box.space.tester:get{1} - -.. function:: box.space.space-name:drop() - - Drop a space. - - :return: nil - :except: If space-name does not exist. - - Complexity Factors: Index size, Index type, - Number of indexes accessed, WAL settings. - - .. code-block:: lua - - tarantool> box.space.space_that_does_not_exist:drop() - -.. function:: box.space.space-name:rename(space-name) - - Rename a space. - - :param string space-name: new name for space. - - :return: nil - :except: If space-name does not exist. - - .. code-block:: lua - - tarantool> box.space.space55:rename('space56') - --- - ... - tarantool> box.space.space56:rename('space55') - --- - ... - -.. function:: box.space.space-name:replace{field-value [, field-value ...]} - box.space.space-name:put{field-value [, field-value ...]} - - Insert a tuple into a space. If a tuple with the same primary key already - exists, ``box.space...:replace()`` replaces the existing tuple with a new - one. The syntax variants ``box.space...:replace()`` and - ``box.space...:put()`` have the same effect; the latter is sometimes used - to show that the effect is the converse of ``box.space...:get()``. - - :param userdata space-name: - :param lua-value field-value(s): fields of the new tuple. - - :return: the inserted tuple. - :rtype: tuple - - :except: If a different tuple with the same unique-key - value already exists, returns ``ER_TUPLE_FOUND``. - (This would only happen if there was a secondary - index. By default secondary indexes are unique.) - - Complexity Factors: Index size, Index type, - Number of indexes accessed, WAL settings. - - .. code-block:: lua - - tarantool> box.space.tester:replace{5000, 'New value'} - -.. function:: box.space.space-name:update(key, {{operator, field_no, value}, ...}) - - Update a tuple. - - The ``update`` function supports operations on fields — assignment, - arithmetic (if the field is unsigned numeric), cutting and pasting - fragments of a field, deleting or inserting a field. Multiple - operations can be combined in a single update request, and in this - case they are performed atomically and sequentially. Each operation - requires specification of a field number. When multiple operations - are present, the field number for each operation is assumed to be - relative to the most recent state of the tuple, that is, as if all - previous operations in a multi-operation update have already been - applied. In other words, it is always safe to merge multiple update - invocations into a single invocation, with no change in semantics. - - :param userdata space-name: - :param lua-value key: primary-key field values, must be passed as a Lua - table if key is multi-part - :param table {operator, field_no, value}: a group of arguments for each - operation, indicating what the operation is, what field the - operation will apply to, and what value will be applied. For - some operations the field number can be -1, meaning the last - field in the tuple. Possible operators are: “+†for addition, - “-†for subtraction, “&†for bitwise AND, “|†for bitwise OR, - “^†for bitwise exclusive OR (XOR), “:†for string splice, “!†- for insert, “#†for delete. Thus in the instruction - ``s:update(44, {{'+',1,55},{'=',3,'x'}})`` the primary-key - value is 44, the operators are '+' and '=' meaning "add a value - to a field and then assign a value to a field", the first - affected field is field 1 and the value which will be added to - it is 55, the second affected field is field 3 and the value - which will be assigned to it is 'x'. - - :return: the updated tuple. - :rtype: tuple - - :except: it is illegal to modify a primary-key field. - - Complexity Factors: Index size, Index type, number of indexes accessed, WAL - settings. - - .. code-block:: lua - - -- Assume that the initial state of the database is ... - -- tester has one tuple set and one primary key whose type is 'NUM'. - -- There is one tuple, with field[1] = 999 and field[2] = 'A'. - - -- In the following update ... - -- The first argument is tester, that is, the affected space is tester - -- The second argument is 999, that is, the affected tuple is identified by - -- primary key value = 999 - -- The third argument is '=', that is, there is one operation, assignment - -- to a field - -- The fourth argument is 2, that is, the affected field is field[2] - -- The fifth argument is 'B', that is, field[2] contents change to 'B' - -- Therefore, after the following update, field[1] = 999 and field[2] = 'B'. - box.space.tester:update(999, {{'=', 2, 'B'}}) - - -- In the following update, the arguments are the same, except that ... - -- the key is passed as a Lua table (inside braces). This is unnecessary - -- when the primary key has only one field, but would be necessary if the - -- primary key had more than one field. - -- Therefore, after the following update, field[1] = 999 and field[2] = 'B' - -- (no change). - box.space.tester:update({999}, {{'=', 2, 'B'}}) - - -- In the following update, the arguments are the same, except that ... - -- The fourth argument is 3, that is, the affected field is field[3]. - -- It is okay that, until now, field[3] has not existed. It gets added. - -- Therefore, after the following update, field[1] = 999, field[2] = 'B', - -- field[3] = 1. - box.space.tester:update({999}, {{'=', 3, 1}}) - - -- In the following update, the arguments are the same, except that ... - -- The third argument is '+', that is, the operation is addition rather - -- than assignment. - -- Since field[3] previously contained 1, this means we're adding 1 to 1. - -- Therefore, after the following update, field[1] = 999, field[2] = 'B', - -- field[3] = 2. - box.space.tester:update({999}, {{'+', 3, 1}}) - - -- In the following update ... - -- The idea is to modify two fields at once. - -- The formats are '|' and '=', that is, there are two operations, OR and - -- assignment. - -- The fourth and fifth arguments mean that field[3] gets ORed with 1. - -- The seventh and eighth arguments mean that field[2] gets assigned 'C'. - -- Therefore, after the following update, field[1] = 999, field[2] = 'C', - -- field[3] = 3. - box.space.tester:update({999}, {{'|', 3, 1}, {'=', 2, 'C'}}) - - -- In the following update ... - -- The idea is to delete field[2], then subtract 3 from field[3], but ... - -- after the delete, there is a renumbering -- so field[3] becomes field[2] - -- before we subtract 3 from it, and that's why the seventh argument is 2 not 3. - -- Therefore, after the following update, field[1] = 999, field[2] = 0. - box.space.tester:update({999}, {{'-- ', 2, 1}, {'-', 2, 3}}) - - -- In the following update ... - -- We're making a long string so that splice will work in the next example. - -- Therefore, after the following update, field[1] = 999, field[2] = 'XYZ'. - box.space.tester:update({999}, {{'=', 2, 'XYZ'}}) - - -- In the following update ... - -- The third argument is ':', that is, this is the example of splice. - -- The fourth argument is 2 because the change will occur in field[2]. - -- The fifth argument is 2 because deletion will begin with the second byte. - -- The sixth argument is 1 because the number of bytes to delete is 1. - -- The seventh argument is '!!' because '!!' is to be added at this position. - -- Therefore, after the following update, field[1] = 999, field[2] = 'X!!Z'. - box.space.tester:update({999}, {{':', 2, 2, 1, '!!'}}) - -.. function:: box.space.space-name:delete{field-value [, field-value ...]} - - Delete a tuple identified by a primary key. - - :param userdata space-name: - :param lua-value field-value(s): values to match against keys - in the primary index. - - :return: the deleted tuple - :rtype: tuple - - Complexity Factors: Index size, Index type - - .. code-block:: lua - - tarantool> box.space.tester:delete(0) - --- - - [0, 'My first tuple'] - ... - tarantool> box.space.tester:delete(0) - --- - ... - tarantool> box.space.tester:delete('a') - --- - - error: 'Supplied key type of part 0 does not match index part type: - expected NUM' - ... -.. data:: space-name.id + :return: the tuples whose primary-key fields are equal to the passed + field-values. If the number of passed field-values is less + than the number of fields in the primary key, then only the + passed field-values are compared, so ``select{1,2}`` will match + a tuple whose primary key is ``{1,2,3}``. + :rtype: tuple + + Possible errors: No such space; wrong type. - Ordinal space number. Spaces can be referenced by either name or - number. Thus, if space 'tester' has id = 800, then - ``box.space.tester:insert{0}`` and ``box.space[800]:insert{0}`` - are equivalent requests. + Complexity Factors: Index size, Index type. - :rtype: number + .. code-block:: lua -.. data:: space-name.enabled + tarantool> s = box.schema.space.create('tmp', {temporary=true}) + --- + ... + tarantool> s:create_index('primary',{parts = {1,'NUM', 2, 'STR'}}) + --- + ... + tarantool> s:insert{1,'A'} + --- + - [1, 'A'] + ... + tarantool> s:insert{1,'B'} + --- + - [1, 'B'] + ... + tarantool> s:insert{1,'C'} + --- + - [1, 'C'] + ... + tarantool> s:insert{2,'D'} + --- + - [2, 'D'] + ... + tarantool> -- must equal both primary-key fields + tarantool> s:select{1,'B'} + --- + - - [1, 'B'] + ... + tarantool> -- must equal only one primary-key field + tarantool> s:select{1} + --- + - - [1, 'A'] + - [1, 'B'] + - [1, 'C'] + ... + tarantool> -- must equal 0 fields, so returns all tuples + tarantool> s:select{} + --- + - - [1, 'A'] + - [1, 'B'] + - [1, 'C'] + - [2, 'D'] + ... - Whether or not this space is enabled. - The value is false if there is no index. + For examples of complex ``select`` requests, where one can specify which index to + search and what condition to use (for example "greater than" instead of + "equal to") and how many tuples to return, see the later section + ``box.space.space-name[.index.index-name]:select``. - :rtype: boolean + .. function:: get(key) -.. data:: space-name.field_count + Search for a tuple in the given space. - The required field count for all tuples in this space. The field_count - can be set initially with - ``box.schema.space.create... field_count = new-field-count-value ...``. - The default value is 0, which means there is no required field count. + :param space_object space-object: + :param lua-table,scalar key: key to be matched against the index + key, which may be multi-part. + :return: the selected tuple. + :rtype: tuple + + Possible errors: If space-name does not exist. + + Complexity Factors: Index size, Index type, + Number of indexes accessed, WAL settings. + + .. code-block:: lua + + tarantool> box.space.tester:get{1} + + .. function:: drop() + + Drop a space. + + :param space_object space-object: + + :return: nil + + Possible errors: If space-name does not exist. - :rtype: number + Complexity Factors: Index size, Index type, + Number of indexes accessed, WAL settings. -.. data:: space-name.index[] + .. code-block:: lua + + tarantool> box.space.space_that_does_not_exist:drop() + + .. function:: rename(space-name) + + Rename a space. + + :param space_object space-object: + :param string space-name: new name for space. - A container for all defined indexes. An index is a Lua object of type - :mod:`box.index` with methods to search tuples and iterate over them in - predefined order. + :return: nil - :rtype: table + Possible errors: ``space-name`` does not exist. + + .. code-block:: lua + + tarantool> box.space.space55:rename('space56') + --- + ... + tarantool> box.space.space56:rename('space55') + --- + ... + + .. function:: replace(tuple) + put(tuple) + + Insert a tuple into a space. If a tuple with the same primary key already + exists, ``box.space...:replace()`` replaces the existing tuple with a new + one. The syntax variants ``box.space...:replace()`` and + ``box.space...:put()`` have the same effect; the latter is sometimes used + to show that the effect is the converse of ``box.space...:get()``. + + :param space_object space-object: + :param lua-table,box.tuple tuple: tuple to be inserted. + + :return: the inserted tuple. + :rtype: tuple + + Possible errors: If a different tuple with the same unique-key + value already exists, returns :errcode:`ER_TUPLE_FOUND`. (This + would only happen if there was a secondary index. By default + secondary indexes are unique) + + Complexity Factors: Index size, Index type, + Number of indexes accessed, WAL settings. - .. code-block: lua + .. code-block:: lua - tarantool> box.space.tester.id - --- - - 512 - ... - tarantool> box.space.tester.field_count - --- - - 0 - ... - tarantool> box.space.tester.index.primary.type - --- - - TREE - ... + tarantool> box.space.tester:replace{5000, 'New value'} -.. function:: box.space.space-name:len() + .. function:: update(key, {{operator, field_no, value}, ...}) - .. NOTE:: + Update a tuple. - The ``len()`` function is only applicable for the memtx storage engine. + The ``update`` function supports operations on fields — assignment, + arithmetic (if the field is unsigned numeric), cutting and pasting + fragments of a field, deleting or inserting a field. Multiple + operations can be combined in a single update request, and in this + case they are performed atomically and sequentially. Each operation + requires specification of a field number. When multiple operations + are present, the field number for each operation is assumed to be + relative to the most recent state of the tuple, that is, as if all + previous operations in a multi-operation update have already been + applied. In other words, it is always safe to merge multiple update + invocations into a single invocation, with no change in semantics. - :return: Number of tuples in the space. + Possible operators are: - .. code-block:: lua + * '+' for addition + * '-' for substraction + * '&' for bitwise AND + * '|' for bitwise OR + * '^' for butwise :abbr:`XOR(exclusive OR)` + * ':' for string splice + * '!' for insert + * '#' for delete - tarantool> box.space.tester:len() - --- - - 2 - ... + :param space_object space-object: + :param lua-value key: primary-key field values, must be passed as a Lua + table if key is multi-part + :param table {operator, field_no, value}: a group of arguments for each + operation, indicating what the operation is, what field the + operation will apply to, and what value will be applied. For + some operations the field number can be -1, meaning the last + field in the tuple. Thus in the instruction -.. function:: box.space.space-name:truncate() + :return: the updated tuple. + :rtype: tuple + + Possible errors: it is illegal to modify a primary-key field. + + Complexity Factors: Index size, Index type, number of indexes accessed, WAL + settings. + + .. code-block:: lua + + s:update(44, {{'+',1,55},{'=',3,'x'}}) + + the primary-key value is 44, the operators are '+' and '=' meaning + "add a value to a field and then assign a value to a field", the first + affected field is field 1 and the value which will be added to it is + 55, the second affected field is field 3 and the value which will be + assigned to it is 'x'. + + .. code-block:: lua + + -- Assume that the initial state of the database is ... + -- tester has one tuple set and one primary key whose type is 'NUM'. + -- There is one tuple, with field[1] = 999 and field[2] = 'A'. + + -- In the following update ... + -- The first argument is tester, that is, the affected space is tester + -- The second argument is 999, that is, the affected tuple is identified by + -- primary key value = 999 + -- The third argument is '=', that is, there is one operation, assignment + -- to a field + -- The fourth argument is 2, that is, the affected field is field[2] + -- The fifth argument is 'B', that is, field[2] contents change to 'B' + -- Therefore, after the following update, field[1] = 999 and field[2] = 'B'. + box.space.tester:update(999, {{'=', 2, 'B'}}) + + -- In the following update, the arguments are the same, except that ... + -- the key is passed as a Lua table (inside braces). This is unnecessary + -- when the primary key has only one field, but would be necessary if the + -- primary key had more than one field. + -- Therefore, after the following update, field[1] = 999 and field[2] = 'B' + -- (no change). + box.space.tester:update({999}, {{'=', 2, 'B'}}) + + -- In the following update, the arguments are the same, except that ... + -- The fourth argument is 3, that is, the affected field is field[3]. + -- It is okay that, until now, field[3] has not existed. It gets added. + -- Therefore, after the following update, field[1] = 999, field[2] = 'B', + -- field[3] = 1. + box.space.tester:update({999}, {{'=', 3, 1}}) + + -- In the following update, the arguments are the same, except that ... + -- The third argument is '+', that is, the operation is addition rather + -- than assignment. + -- Since field[3] previously contained 1, this means we're adding 1 to 1. + -- Therefore, after the following update, field[1] = 999, field[2] = 'B', + -- field[3] = 2. + box.space.tester:update({999}, {{'+', 3, 1}}) + + -- In the following update ... + -- The idea is to modify two fields at once. + -- The formats are '|' and '=', that is, there are two operations, OR and + -- assignment. + -- The fourth and fifth arguments mean that field[3] gets ORed with 1. + -- The seventh and eighth arguments mean that field[2] gets assigned 'C'. + -- Therefore, after the following update, field[1] = 999, field[2] = 'C', + -- field[3] = 3. + box.space.tester:update({999}, {{'|', 3, 1}, {'=', 2, 'C'}}) + + -- In the following update ... + -- The idea is to delete field[2], then subtract 3 from field[3], but ... + -- after the delete, there is a renumbering -- so field[3] becomes field[2] + -- before we subtract 3 from it, and that's why the seventh argument is 2 not 3. + -- Therefore, after the following update, field[1] = 999, field[2] = 0. + box.space.tester:update({999}, {{'-- ', 2, 1}, {'-', 2, 3}}) + + -- In the following update ... + -- We're making a long string so that splice will work in the next example. + -- Therefore, after the following update, field[1] = 999, field[2] = 'XYZ'. + box.space.tester:update({999}, {{'=', 2, 'XYZ'}}) + + -- In the following update ... + -- The third argument is ':', that is, this is the example of splice. + -- The fourth argument is 2 because the change will occur in field[2]. + -- The fifth argument is 2 because deletion will begin with the second byte. + -- The sixth argument is 1 because the number of bytes to delete is 1. + -- The seventh argument is '!!' because '!!' is to be added at this position. + -- Therefore, after the following update, field[1] = 999, field[2] = 'X!!Z'. + box.space.tester:update({999}, {{':', 2, 2, 1, '!!'}}) + + .. function:: delete(key) - Deletes all tuples. + Delete a tuple identified by a primary key. + + :param space_object space-object: + :param lua-table,scalar key: key to be matched against the index + key, which may be multi-part. + + :return: the deleted tuple + :rtype: tuple - Complexity Factors: Index size, Index type, Number of tuples accessed. + Complexity Factors: Index size, Index type - :return: nil + .. code-block:: lua + + tarantool> box.space.tester:delete(0) + --- + - [0, 'My first tuple'] + ... + tarantool> box.space.tester:delete(0) + --- + ... + tarantool> box.space.tester:delete('a') + --- + - error: 'Supplied key type of part 0 does not match index part type: + expected NUM' + ... + + .. data:: id + + Ordinal space number. Spaces can be referenced by either name or + number. Thus, if space 'tester' has id = 800, then + ``box.space.tester:insert{0}`` and ``box.space[800]:insert{0}`` + are equivalent requests. + + :rtype: number + + .. data:: enabled + + Whether or not this space is enabled. + The value is false if there is no index. + + :rtype: boolean + + .. data:: field_count + + The required field count for all tuples in this space. The field_count + can be set initially with + ``box.schema.space.create... field_count = new-field-count-value ...``. + The default value is 0, which means there is no required field count. + + :rtype: number + + .. data:: index + + A container for all defined indexes. An index is a Lua object of type + :mod:`box.index` with methods to search tuples and iterate over them in + predefined order. + + :rtype: table - .. code-block:: lua + .. code-block: lua + + tarantool> box.space.tester.id + --- + - 512 + ... + tarantool> box.space.tester.field_count + --- + - 0 + ... + tarantool> box.space.tester.index.primary.type + --- + - TREE + ... + + .. function:: len() + + .. NOTE:: + + The ``len()`` function is only applicable for the memtx storage engine. + + :return: Number of tuples in the space. + + .. code-block:: lua - tarantool> box.space.tester:truncate() - --- - ... - tarantool> box.space.tester:len() - --- - - 0 - ... + tarantool> box.space.tester:len() + --- + - 2 + ... -.. function:: box.space.space-name:inc{field-value [, field-value ...]} + .. function:: truncate() - Increments a counter in a tuple whose primary key matches the - ``field-value(s)``. The field following the primary-key fields - will be the counter. If there is no tuple matching the - ``field-value(s)``, a new one is inserted with initial counter - value set to 1. + Deletes all tuples. - :param userdata space-name: - :param lua-value field-value(s): values which must match the primary key. - :return: the new counter value - :rtype: number + Complexity Factors: Index size, Index type, Number of tuples accessed. - Complexity Factors: Index size, Index type, WAL settings. + :return: nil - .. code-block:: lua + .. code-block:: lua - tarantool> s = box.schema.space.create('forty_second_space') - --- - ... - tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) - --- - ... - tarantool> box.space.forty_second_space:inc{1,'a'} - --- - - 1 - ... - tarantool> box.space.forty_second_space:inc{1,'a'} - --- - - 2 - ... + tarantool> box.space.tester:truncate() + --- + ... + tarantool> box.space.tester:len() + --- + - 0 + ... -.. function:: box.space.space-name:dec{field-value [, field-value ...]} + .. function:: inc(key) - Decrements a counter in a tuple whose primary key matches the - ``field-value(s)``. The field following the primary-key fields - will be the counter. If there is no tuple matching the - ``field-value(s)``, a new one is not inserted. If the counter value drops - to zero, the tuple is deleted. + Increments a counter in a tuple whose primary key matches the + ``key``. The field following the primary-key fields + will be the counter. If there is no tuple matching the + ``field-value(s)``, a new one is inserted with initial counter + value set to 1. - :param userdata space-name: - :param lua-value field-value(s): values which must match the primary key. - :return: the new counter value - :rtype: number + :param space_object space-object: + :param lua-table,scalar key: key to be matched against the index + key, which may be multi-part. + :return: the new counter value + :rtype: number - Complexity Factors: Index size, Index type, WAL settings. + Complexity Factors: Index size, Index type, WAL settings. - .. code-block:: lua + .. code-block:: lua - tarantool> s = box.schema.space.create('space19') - --- - ... - tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) - --- - ... - tarantool> box.space.space19:insert{1,'a',1000} - --- - - [1, 'a', 1000] - ... - tarantool> box.space.space19:dec{1,'a'} - --- - - 999 - ... - tarantool> box.space.space19:dec{1,'a'} - --- - - 998 - ... - -.. function:: box.space.space-name:auto_increment{field-value [, field-value ...]} - - Insert a new tuple using an auto-increment primary key. The space specified - by space-name must have a NUM primary key index of type TREE. The - primary-key field will be incremented before the insert. - - :param userdata space-name: - :param lua-value field-value(s): values for the tuple's fields, - other than the primary-key field. - - :return: the inserted tuple. - :rtype: tuple - - Complexity Factors: Index size, Index type, - Number of indexes accessed, WAL settings. - - :except: index has wrong type or primary-key indexed field is not a number. - - .. code-block:: lua - - tarantool> box.space.tester:auto_increment{'Fld#1', 'Fld#2'} - --- - - [1, 'Fld#1', 'Fld#2'] - ... - tarantool> box.space.tester:auto_increment{'Fld#3'} - --- - - [2, 'Fld#3'] - ... - -.. function:: box.space.space-name:pairs() - - A helper function to prepare for iterating over all tuples in a space. - - :return: function which can be used in a for/end loop. Within the loop, a value is returned for each iteration. - :rtype: function, tuple - - .. code-block:: lua - - tarantool> s = box.schema.space.create('space33') - --- - ... - tarantool> -- index 'X' has default parts {1,'NUM'} - tarantool> s:create_index('X', {}) - --- - ... - tarantool> s:insert{0,'Hello my '}; s:insert{1,'Lua world'} - --- - ... - tarantool> tmp = ''; for k, v in s:pairs() do tmp = tmp .. v[2] end - --- - ... - tarantool> tmp - --- - - Hello my Lua world - ... + tarantool> s = box.schema.space.create('forty_second_space') + --- + ... + tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) + --- + ... + tarantool> box.space.forty_second_space:inc{1,'a'} + --- + - 1 + ... + tarantool> box.space.forty_second_space:inc{1,'a'} + --- + - 2 + ... + + .. function:: dec(key) + + Decrements a counter in a tuple whose primary key matches the + ``field-value(s)``. The field following the primary-key fields + will be the counter. If there is no tuple matching the + ``field-value(s)``, a new one is not inserted. If the counter value drops + to zero, the tuple is deleted. + + :param space_object space-object: + :param lua-table,scalar key: key to be matched against the index + key, which may be multi-part. + :return: the new counter value + :rtype: number + + Complexity Factors: Index size, Index type, WAL settings. + + .. code-block:: lua + + tarantool> s = box.schema.space.create('space19') + --- + ... + tarantool> s:create_index('primary', {unique = true, parts = {1, 'NUM', 2, 'STR'}}) + --- + ... + tarantool> box.space.space19:insert{1,'a',1000} + --- + - [1, 'a', 1000] + ... + tarantool> box.space.space19:dec{1,'a'} + --- + - 999 + ... + tarantool> box.space.space19:dec{1,'a'} + --- + - 998 + ... + + .. function:: auto_increment(tuple) + + Insert a new tuple using an auto-increment primary key. The space specified + by space-name must have a NUM primary key index of type TREE. The + primary-key field will be incremented before the insert. + + :param space_object space-object: + :param lua-table,box.tuple tuple: tuple's fields, other than the primary-key field. + + :return: the inserted tuple. + :rtype: tuple + + Complexity Factors: Index size, Index type, + Number of indexes accessed, WAL settings. + + Possible errors: index has wrong type or primary-key indexed field is not a number. + + .. code-block:: lua + + tarantool> box.space.tester:auto_increment{'Fld#1', 'Fld#2'} + --- + - [1, 'Fld#1', 'Fld#2'] + ... + tarantool> box.space.tester:auto_increment{'Fld#3'} + --- + - [2, 'Fld#3'] + ... + + .. function:: pairs() + + A helper function to prepare for iterating over all tuples in a space. + + :return: function which can be used in a for/end loop. Within the loop, a value is returned for each iteration. + :rtype: function, tuple + + .. code-block:: lua + + tarantool> s = box.schema.space.create('space33') + --- + ... + tarantool> -- index 'X' has default parts {1,'NUM'} + tarantool> s:create_index('X', {}) + --- + ... + tarantool> s:insert{0,'Hello my '}; s:insert{1,'Lua world'} + --- + ... + tarantool> tmp = ''; for k, v in s:pairs() do tmp = tmp .. v[2] end + --- + ... + tarantool> tmp + --- + - Hello my Lua world + ... .. data:: _schema diff --git a/doc/sphinx/book/replication/index.rst b/doc/sphinx/book/replication/index.rst index 05ed77f15668937d408dceea4cda7cf2b079c8bd..4d28892092bed7112c396cbbf7b483858f86d976 100644 --- a/doc/sphinx/book/replication/index.rst +++ b/doc/sphinx/book/replication/index.rst @@ -95,7 +95,7 @@ the old master went down, they would have to be re-applied manually. ===================================================================== - Instructions for quick startup of a new two-server simple cluster + Quick startup of a new two-server simple cluster ===================================================================== Step 1. Start the first server thus: @@ -212,17 +212,68 @@ a cluster and adding a replica. Start two shells. Put them side by side on the screen. -.. container:: table-wide - - +----------------------+---------------------+ - | Terminal #1 | Terminal #2 | - +======================+=====================+ - | | | - | .. code-block:: lua | .. code-block:: lua | - | | | - | $ | $ | - | | | - +----------------------+---------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-1 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-1-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-1-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-1-content + + .. container:: b-documentation_tab + :name: terminal-1-1 + + .. code-block:: lua + + $ + + .. container:: b-documentation_tab + :name: terminal-1-2 + + .. code-block:: lua + + $ + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-1 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-1 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-1-1').height(), $('#terminal-1-2').height()); + $('#catalog-1-content').height(maxHeight + 10); + $('#terminal-1-1').height(maxHeight); + $('#terminal-1-2').height(maxHeight); + $('#terminal-1-1').show(); + $('#terminal-1-2').hide(); + }); + })(); + </script> On the first shell, which we'll call Terminal #1, execute these commands: @@ -241,16 +292,64 @@ On the first shell, which we'll call Terminal #1, execute these commands: The result is that a new cluster is set up, and the UUID is displayed. Now the screen looks like this: (except that UUID values are always different): - -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 1-1.rst | .. include:: 1-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-2 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-2-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-2-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-2-content + + .. container:: b-documentation_tab + :name: terminal-2-1 + + .. include:: 1-1.rst + + .. container:: b-documentation_tab + :name: terminal-2-2 + + .. include:: 1-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-2 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-2 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-2-1').height(), $('#terminal-2-2').height()); + $('#catalog-2-content').height(maxHeight + 10); + $('#terminal-2-1').height(maxHeight); + $('#terminal-2-2').height(maxHeight); + $('#terminal-2-1').show(); + $('#terminal-2-2').hide(); + }); + })(); + </script> On the second shell, which we'll call Terminal #2, execute these commands: @@ -271,16 +370,64 @@ replication is starting. Also on Terminal#2 the _cluster UUID value is displayed, and it is the same as the _cluster UUID value that was displayed on Terminal #1, because both servers are in the same cluster. - -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 2-1.rst | .. include:: 2-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-3 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-3-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-3-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-3-content + + .. container:: b-documentation_tab + :name: terminal-3-1 + + .. include:: 2-1.rst + + .. container:: b-documentation_tab + :name: terminal-3-2 + + .. include:: 2-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-3 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-3 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-3-1').height(), $('#terminal-3-2').height()); + $('#catalog-3-content').height(maxHeight + 10); + $('#terminal-3-1').height(maxHeight); + $('#terminal-3-2').height(maxHeight); + $('#terminal-3-1').show(); + $('#terminal-3-2').hide(); + }); + })(); + </script> On Terminal #1, execute these requests: @@ -292,15 +439,64 @@ On Terminal #1, execute these requests: Now the screen looks like this: -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 3-1.rst | .. include:: 3-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-4 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-4-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-4-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-4-content + + .. container:: b-documentation_tab + :name: terminal-4-1 + + .. include:: 3-1.rst + + .. container:: b-documentation_tab + :name: terminal-4-2 + + .. include:: 3-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-4 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-4 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-4-1').height(), $('#terminal-4-2').height()); + $('#catalog-4-content').height(maxHeight + 10); + $('#terminal-4-1').height(maxHeight); + $('#terminal-4-2').height(maxHeight); + $('#terminal-4-1').show(); + $('#terminal-4-2').hide(); + }); + })(); + </script> The creation and insertion were successful on Terminal #1. Nothing has happened on Terminal #2. @@ -315,15 +511,64 @@ On Terminal #2, execute these requests: Now the screen looks like this: -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 4-1.rst | .. include:: 4-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-5 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-5-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-5-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-5-content + + .. container:: b-documentation_tab + :name: terminal-5-1 + + .. include:: 4-1.rst + + .. container:: b-documentation_tab + :name: terminal-5-2 + + .. include:: 4-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-5 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-5 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-5-1').height(), $('#terminal-5-2').height()); + $('#catalog-5-content').height(maxHeight + 10); + $('#terminal-5-1').height(maxHeight); + $('#terminal-5-2').height(maxHeight); + $('#terminal-5-1').show(); + $('#terminal-5-2').hide(); + }); + })(); + </script> The selection and insertion were successful on Terminal #2. Nothing has happened on Terminal #1. @@ -340,15 +585,64 @@ Now Tarantool #1 is stopped. Messages appear on Terminal #2 announcing that fact The "ls -l" commands show that both servers have made snapshots, which have the same size because they both contain the same tuples. -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 5-1.rst | .. include:: 5-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-6 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-6-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-6-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-6-content + + .. container:: b-documentation_tab + :name: terminal-6-1 + + .. include:: 5-1.rst + + .. container:: b-documentation_tab + :name: terminal-6-2 + + .. include:: 5-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-6 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-6 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-6-1').height(), $('#terminal-6-2').height()); + $('#catalog-6-content').height(maxHeight + 10); + $('#terminal-6-1').height(maxHeight); + $('#terminal-6-2').height(maxHeight); + $('#terminal-6-1').show(); + $('#terminal-6-2').hide(); + }); + })(); + </script> On Terminal #2, ignore the repeated messages saying "failed to connect", and execute these requests: @@ -361,15 +655,64 @@ and execute these requests: Now the screen looks like this (ignoring the repeated messages saying "failed to connect"): -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 6-1.rst | .. include:: 6-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-7 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-7-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-7-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-7-content + + .. container:: b-documentation_tab + :name: terminal-7-1 + + .. include:: 6-1.rst + + .. container:: b-documentation_tab + :name: terminal-7-2 + + .. include:: 6-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-7 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-7 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-7-1').height(), $('#terminal-7-2').height()); + $('#catalog-7-content').height(maxHeight + 10); + $('#terminal-7-1').height(maxHeight); + $('#terminal-7-2').height(maxHeight); + $('#terminal-7-1').show(); + $('#terminal-7-2').hide(); + }); + })(); + </script> Terminal #2 has done a select and an insert, even though Terminal #1 is down. @@ -384,15 +727,64 @@ On Terminal #1 execute these commands: Now the screen looks like this (ignoring the repeated messages on terminal #2 saying "failed to connect"): -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 7-1.rst | .. include:: 7-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-8 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-8-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-8-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-8-content + + .. container:: b-documentation_tab + :name: terminal-8-1 + + .. include:: 7-1.rst + + .. container:: b-documentation_tab + :name: terminal-8-2 + + .. include:: 7-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-8 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-8 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-8-1').height(), $('#terminal-8-2').height()); + $('#catalog-8-content').height(maxHeight + 10); + $('#terminal-8-1').height(maxHeight); + $('#terminal-8-2').height(maxHeight); + $('#terminal-8-1').show(); + $('#terminal-8-2').hide(); + }); + })(); + </script> The master has reconnected to the cluster, and has NOT found what the replica wrote while the master was away. That is not a surprise -- the replica has not @@ -407,15 +799,64 @@ On Terminal #1, say: The screen now looks like this: -.. container:: table-wide - - +----------------------------------+----------------------------------+ - | Terminal #1 | Terminal #2 | - +==================================+==================================+ - | | | - | .. include:: 8-1.rst | .. include:: 8-2.rst | - | | | - +----------------------------------+----------------------------------+ +.. container:: b-block-wrapper_doc + + .. container:: b-doc_catalog + :name: catalog-9 + + .. raw:: html + + <ul class="b-tab_switcher"> + <li class="b-tab_switcher-item"> + <a href="#terminal-9-1" class="b-tab_switcher-item-url p-active">Terminal #1</a> + </li> + <li class="b-tab_switcher-item"> + <a href="#terminal-9-2" class="b-tab_switcher-item-url">Terminal #2</a> + </li> + </ul> + + .. container:: b-documentation_tab_content + :name: catalog-9-content + + .. container:: b-documentation_tab + :name: terminal-9-1 + + .. include:: 8-1.rst + + .. container:: b-documentation_tab + :name: terminal-9-2 + + .. include:: 8-2.rst + + .. raw:: html + + <script> + (function(){ + var dOn = $(document); + dOn.on({ + click: function(event) { + event.preventDefault(); + link = $(this).children('a'); + target = link.attr('href'); + if (!(link.hasClass('p-active'))) { + active = $('#catalog-9 .b-tab_switcher-item-url.p-active'); + $(active.attr('href')).hide(); + active.removeClass('p-active'); + link.addClass('p-active'); + $(link.attr('href')).show(); + } + } + }, '#catalog-9 .b-tab_switcher-item'); + dOn.ready(function(event) { + maxHeight = Math.max($('#terminal-9-1').height(), $('#terminal-9-2').height()); + $('#catalog-9-content').height(maxHeight + 10); + $('#terminal-9-1').height(maxHeight); + $('#terminal-9-2').height(maxHeight); + $('#terminal-9-1').show(); + $('#terminal-9-2').hide(); + }); + })(); + </script> This shows that the two servers are once again in synch, and that each server sees what the other server wrote. diff --git a/doc/user/configuration-reference.xml b/doc/user/configuration-reference.xml deleted file mode 100644 index 11ae16e312d78a994cfd9252cb02c8c0318df15c..0000000000000000000000000000000000000000 --- a/doc/user/configuration-reference.xml +++ /dev/null @@ -1,766 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xi="http://www.w3.org/2001/XInclude" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="configuration-reference"> - -<title>Configuration reference</title> -<blockquote><para> - This chapter provides a reference of options which - can be set on the command line or in an initialization file. -</para></blockquote> - -<para> -Tarantool is started by entering the command: - -<programlisting><prompt>$ </prompt><userinput>tarantool</userinput></programlisting> -or -<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>options</replaceable></userinput></programlisting> -or -<programlisting><prompt>$ </prompt><userinput>tarantool <replaceable>Lua-initialization-file</replaceable> [<replaceable>arguments</replaceable>]</userinput></programlisting> - -</para> - -<section xml:id="command-line-options"> -<title>Command options</title> - <para> - - </para> - <itemizedlist> - <listitem xml:id="help-option"> - <para><option>--help</option>, <option>-h</option></para> - <para>Print an annotated list of all available options and exit.</para> - </listitem> - - <listitem xml:id="version-option"> - <para><option>--version</option>, <option>-V</option></para> - <para>Print product name and version, for example: - <programlisting><prompt>$ </prompt> <userinput>./tarantool --version</userinput> -Tarantool 1.6.3-439-g7e1011b -Target: Linux-x86_64-Debug -... - </programlisting> - In this example: - <simplelist> - <member> - <quote>Tarantool</quote> is the name - of the reusable asynchronous networking programming framework. - </member> - <member> - The 3-number version follows the standard - <literal><major>-<minor>-<patch></literal> - scheme, in which <literal><major></literal> number - is changed only rarely, <literal><minor></literal> - is incremented for each new milestone and - indicates possible incompatible changes, - and <literal><patch></literal> stands for the number of - bug fix releases made after the start of the - milestone. For non-released versions only, there may be a - commit number and commit SHA1 - to indicate how much this particular build has diverged - from the last release. - </member> - <member> - <quote>Target</quote> is the platform tarantool was built on. - Some platform-specific details may follow this line. - </member> - </simplelist> - </para> - <note><para> - Tarantool uses <link - xlink:href="http://www.kernel.org/pub/software/scm/git/docs/git-describe.html">git describe</link> to produce its version id, and - this id can be used at any time to check out the - corresponding source from our <link - xlink:href="http://github.com/tarantool/tarantool.git">git repository</link>. - </para></note> - </listitem> - - </itemizedlist> - -</section> - - -<section xml:id="URI" xreflabel="URI"> - <title>URI</title> - <para> -Some configuration parameters and some functions -depend on a URI, or "Universal Resource Identifier". -The URI string format is similar to the -<link -xlink:href="http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax">generic syntax for a URI schema</link>. -So it may contain (in order) a user name for login, a password, -a host name or host IP address, and a port number. -Only the port number is always mandatory. The password -is mandatory if the user name is specified, -unless the user name is 'guest'. -So, formally, the URI syntax is -<code>[host:]port</code> -or <code>[username:password@]host:port</code>. -If host is omitted, then 'localhost' is assumed. -If username:password is omitted, then 'guest' is assumed. -Some examples: - <informaltable> - <tgroup cols="2" align="left" colsep="1" rowsep="0"> - <thead> - <row><entry>URI fragment</entry><entry>Example</entry></row> - </thead> - <tbody> - <row><entry>port</entry><entry> 3301</entry></row> - <row><entry>host:port</entry><entry> 127.0.0.1:3301</entry></row> - <row><entry>username:password@host:port</entry><entry> guest:sesame@mail.ru:3301</entry></row> - </tbody> - </tgroup> - </informaltable> -In certain circumstances a Unix socket may be used where a URI is required. -</para> -</section> - - -<section xml:id="initialization-file" xreflabel="initialization file"> -<title>Initialization file</title> -<para> -If the command to start Tarantool includes <option><replaceable>lua-initialization-file</replaceable></option>, -then Tarantool begins by invoking the Lua program in the file, -which by convention may have the name <filename>"script.lua"</filename>. - -The Lua program may get further arguments from the command line -or may use operating-system functions, such as getenv(). -The Lua program almost always begins by invoking <code>box.cfg()</code>, -if the database server will be used or if ports need to be opened. -For example, suppose <filename>script.lua</filename> contains the lines<programlisting>#!/usr/bin/env tarantool -box.cfg{ - listen = os.getenv("LISTEN_URI"), - slab_alloc_arena = 0.1, - pid_file = "tarantool.pid", - rows_per_wal = 50 -} -print('Starting ',arg[1])</programlisting> -and suppose the environment variable LISTEN_URI contains 3301, -and suppose the command line is <code>~/tarantool/src/tarantool script.lua ARG</code>. -Then the screen might look like this:<programlisting> -<prompt>$</prompt> <userinput>export LISTEN_URI=3301</userinput> -<prompt>$</prompt> <userinput>~/tarantool/src/tarantool script.lua ARG</userinput> -... main/101/script.lua C> version 1.6.3-439-g7e1011b -... main/101/script.lua C> log level 5 -... main/101/script.lua I> mapping 107374184 bytes for a shared arena... -... main/101/script.lua I> recovery start -... main/101/script.lua I> recovering from `./00000000000000000000.snap' -... main/101/script.lua I> primary: bound to 0.0.0.0:3301 -... main/102/leave_local_hot_standby I> ready to accept requests -Starting ARG -... main C> entering the event loop</programlisting> -</para> -</section> - -<section xml:id="configuration-parameters" xreflabel="configuration parameters"> -<title>Configuration parameters</title> -<para> - Configuration parameters have the form - <code>box.cfg{<replaceable> key = value [, key = value ...]</replaceable>}</code>. - Since box.cfg may contain many configuration parameters - and since some of the parameters (such as directory addresses) - are semi-permanent, it's best to keep box.cfg in a Lua file. - Typically this Lua file is the initialization file - which is specified on the tarantool command line. - </para> - <para> - Most configuration parameters are for allocating resources, - opening ports, and specifying database behavior. - All parameters are optional. - A few parameters are dynamic, that is, they can be changed - at runtime by calling box.cfg{} a second time. - </para> - <para> - To see all the non-null parameters, say <code>box.cfg</code> (no parentheses). - To see a particular parameter, for example the listen address, say <code>box.cfg.listen</code>. - </para> - <para> - The following tables describe all parameters for basic operation, - for storage, for binary logging and snapshots, for replication, - for networking, and for logging. - </para> - - <table frame='all' pgwide='1'> - <title>Basic parameters</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>username</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>UNIX user name to switch to after start.</entry> - </row> - - <row> - <entry xml:id="work_dir" xreflabel="work_dir">work_dir</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>A directory where database working files will be stored. - The server switches to work_dir with chdir(2) after - start. Can be relative to the current directory. - If not specified, defaults to the current directory.</entry> - </row> - - <row> - <entry xml:id="wal_dir" xreflabel="wal_dir">wal_dir</entry> - <entry>string</entry> - <entry>"."</entry> - <entry>no</entry> - <entry>A directory where write-ahead log (.xlog) files are stored. - Can be relative to work_dir. Most commonly used so - that snapshot files and write-ahead log files - can be stored on separate disks. - If not specified, defaults to work_dir.</entry> - </row> - - <row> - <entry xml:id="snap_dir" xreflabel="snap_dir">snap_dir</entry> - <entry>string</entry> - <entry>"."</entry> - <entry>no</entry> - <entry>A directory where snapshot (.snap) files will be stored. Can be - relative to work_dir. If not specified, defaults to - work_dir. See also <olink targetptr="wal_dir"/>.</entry> - </row> - - <row> - <entry xml:id="sophia_dir" xreflabel="sophia_dir">sophia_dir</entry> - <entry>string</entry> - <entry>"sophia"</entry> - <entry>no</entry> - <entry>A directory where sophia files will be stored. Can be - relative to work_dir. If not specified, defaults to - work_dir/sophia.</entry> - </row> - - <row> - <entry xml:id="core-dump" xreflabel="core-dump">coredump</entry> - <entry>boolean</entry> - <entry>false</entry> - <entry>no</entry> - <entry>Deprecated. Do not use.</entry> - </row> - <row> - <entry xml:id="primary_port" xreflabel="primary_port">listen</entry> - <entry>integer or string</entry> - <entry>null</entry> - <entry>yes</entry> - <entry>The read/write data port number or <link linkend="URI">URI</link> (Universal Resource Identifier) string. - Has no default value, so <emphasis - role="strong">must be specified</emphasis> - if connections will occur from remote clients - that do not use "admin address" (the administrative host and port). - Note: a replica also binds to this port, and accepts - connections, but these connections can only serve - reads until the replica becomes a master. - A typical value is 3301. - The listen parameter may also be set for <olink targetptr="local_hot_standby">local hot standby</olink>.</entry> - </row> - - <row> - <entry>pid_file</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>Store the process id in this file. Can be - relative to work_dir. A typical value is "tarantool.pid".</entry> - </row> - - <row> - <entry xml:id="custom_proc_title" - xreflabel="custom_proc_title"> - custom_proc_title - </entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry> - <para>Inject the given string into <olink - targetptr="proctitle">server process title</olink> - (what's shown in the COMMAND column for <command>ps</command> - and <command>top</command> commands). For example, - ordinarily <command>ps</command> shows the Tarantool server process thus: - </para><programlisting><prompt>$</prompt> <userinput>ps -ef | grep tarantool</userinput> -1000 22364 2778 0 09:14 pts/0 00:00:00 tarantool: running -1000 22394 22364 0 09:14 pts/0 00:00:00 tarantool: spawner -tarantool: primary pri: 3301 adm: 3313</programlisting> - <para>But if the configuration parameters include custom_proc_title='sessions' then - the output looks like:</para> -<programlisting><prompt>$</prompt> <userinput>ps -ef | grep tarantool</userinput> -1000 22364 2778 0 09:14 pts/0 00:00:00 tarantool: running@sessions -1000 22394 22364 0 09:14 pts/0 00:00:00 tarantool: spawner@sessions -tarantool: primary pri: 3301 adm: 3313</programlisting> - </entry> - </row> - - <row> - <entry>background</entry> - <entry>boolean</entry> - <entry>false</entry> - <entry>no</entry> - <entry>Run the server as a background task. - The logger and pid_file parameters must be non-null for this to work.</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Configuring the storage</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>slab_alloc_arena</entry> - <entry>float</entry> - <entry>1.0</entry> - <entry>no</entry> - <entry> - <anchor xml:id="slab_alloc_arena" xreflabel="slab_alloc_arena"/> - How much memory Tarantool - allocates to actually - store tuples, <emphasis role="strong">in - gigabytes</emphasis>. When the limit is reached, INSERT - or UPDATE requests begin failing with error - <olink targetptr="ER_MEMORY_ISSUE"/>. - While the server does not go - beyond the defined limit to allocate tuples, there is - additional memory used to store indexes and connection - information. Depending on actual configuration and - workload, Tarantool can consume up to 20% more than the - limit set here.</entry> - </row> - - <row> - <entry>slab_alloc_minimal</entry> - <entry>integer</entry> - <entry>64</entry> - <entry>no</entry> - <entry>Size of the smallest allocation unit. It can be - tuned down if most of the tuples are very small.</entry> - </row> - - <row> - <entry>slab_alloc_factor</entry> - <entry>float</entry> - <entry>2.0</entry> - <entry>no</entry> - <entry>Use slab_alloc_factor as the multiplier for - computing the sizes of memory chunks that tuples are - stored in. A lower value may result in less wasted - memory depending on the total amount of memory available - and the distribution of item sizes.</entry> - </row> - - <row> - <entry>sophia</entry> - <entry>table</entry> - <entry>(see the note)</entry> - <entry>no</entry> - <entry>The default sophia configuration can be changed with - sophia={page_size=<replaceable>number</replaceable>, threads=<replaceable>number</replaceable>, - node_size=<replaceable>number</replaceable>, memory_limit=<replaceable>number</replaceable> }. - This method may change in the future.</entry> - </row> - - </tbody> - </tgroup> - </table> - - - <table xml:id="snapshot-daemon" frame='all' pgwide='1'> - <title>Snapshot daemon</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>snapshot_period</entry> - <entry>float</entry> - <entry>0</entry> - <entry>yes</entry> - <entry> - The interval between actions by the snapshot daemon, in seconds. - The snapshot daemon is a fiber which is constantly running. - If snapshot_period is set to a value greater than zero, - then the snapshot daemon - will call <olink targetptr="box.snapshot"/> every snapshot_period seconds, creating - a new snapshot file each time. - For example, <code>box.cfg{snapshot_period=3600}</code> - will cause the snapshot daemon to create a new database - snapshot once per hour. - </entry> - </row> - - <row> - <entry>snapshot_count</entry> - <entry>integer</entry> - <entry>6</entry> - <entry>yes</entry> - <entry> - <para> - The maximum number of snapshots that the snapshot daemon maintains. - For example, <code>box.cfg{snapshot_period=3600, snapshot_count=10}</code> - will cause the snapshot daemon - to create a new snapshot each hour until it has created - ten snapshots. After that, it will remove the oldest - snapshot (and any associated write-ahead-log files) after creating - a new one. If snapshot_count equals zero, then the snapshot - daemon does not remove old snapshots. - </para> - </entry> - </row> - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Binary logging and snapshots</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>panic_on_snap_error</entry> - <entry>boolean</entry> - <entry>true</entry> - <entry>no</entry> - <entry>If there is an error while reading the snapshot file (at - server start), abort.</entry> - </row> - - <row> - <entry>panic_on_wal_error</entry> - <entry>boolean</entry> - <entry>false</entry> - <entry>no</entry> - <entry>If there is an error while reading a write-ahead - log file (at server start), abort.</entry> - </row> - - <row> - <entry xml:id="rows_per_wal" xreflabel="rows_per_wal">rows_per_wal</entry> - <entry>integer</entry> - <entry>500000</entry> - <entry>no</entry> - <entry>How many log records to store in a single - write-ahead log file. When this limit is reached, Tarantool - creates another WAL file named - <filename><first-lsn-in-wal>.xlog</filename> - This can be useful for simple rsync-based backups. - </entry> - </row> - - <row> - <entry>snap_io_rate_limit</entry> - <entry>float</entry> - <entry>null</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>Reduce the throttling effect of <olink - targetptr="box.snapshot"/> on INSERT/UPDATE/DELETE - performance by setting a limit on - how many megabytes per second it can write to disk. - The same can be achieved by splitting <olink - targetptr="wal_dir"/> and <olink targetptr="snap_dir"/> - locations and moving snapshots to a separate disk.</entry> - </row> - - <row> - <entry xml:id="wal_mode" xreflabel="wal_mode">wal_mode</entry> - <entry>string</entry> - <entry>"write"</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>Specify fiber-WAL-disk synchronization mode as: - <emphasis>none:</emphasis> write-ahead log is not maintained; <emphasis>write:</emphasis> fibers wait for their data to - be written to the write-ahead log (no fsync(2)); <emphasis>fsync</emphasis>: - fibers wait for their data, fsync(2) follows each write(2); - </entry> - </row> - - <row> - <entry xml:id="wal_dir_rescan_delay" xreflabel="wal_dir_rescan_delay">wal_dir_rescan_delay</entry> - <entry>float</entry> - <entry>0.1</entry> - <entry>no</entry> - <entry>Number of seconds between periodic scans of the - write-ahead-log file directory, when checking for - changes to write-ahead-log files for the sake of - replication or local hot standby.</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Replication</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry xml:id="replication_source" - xreflabel="replication_source">replication_source</entry> - <entry>string</entry> - <entry>null</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>If replication_source is not an empty string, the - server is considered to be a Tarantool replica. - The replica server will try to connect to the master - which replication_source specifies with a <link linkend="URI">URI</link> (Universal Resource Identifier), - for example 'konstantin:secret_password@tarantool.org:3301'. - The default user name is 'guest'. - A replica server does not accept data-change requests - on the <olink targetptr="primary_port">listen</olink> port. - The replication_source parameter is - dynamic, that is, to enter master mode, simply set - replication_source to an empty string and issue - "box.cfg{replication_source=new-value}".</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Networking</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry>io_collect_interval</entry> - <entry>float</entry> - <entry>null</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>The server will sleep for io_collect_interval seconds - between iterations of the event loop. Can be - used to reduce CPU load in deployments in which the - number of client connections is large, but requests are - not so frequent (for example, each connection issues - just a handful of requests per second). </entry> - </row> - - <row> - <entry>readahead</entry> - <entry>integer</entry> - <entry>16320</entry> - <entry>yes</entry> - <entry>The size of the read-ahead buffer associated with a - client connection. The larger the buffer, the more - memory an active connection consumes and the more requests - can be read from the operating system buffer in a single - system call. The rule of thumb is to make sure the buffer - can contain at least a few dozen requests. Therefore, if - a typical tuple in a request is large, e.g. a few - kilobytes or even megabytes, the read-ahead buffer size should - be increased. If batched request processing is not - used, it's prudent to leave this setting at its - default.</entry> - </row> - - </tbody> - </tgroup> - </table> - - <table frame='all' pgwide='1'> - <title>Logging</title> - <tgroup cols='5' colsep='1' rowsep='1'> - <colspec colnum="1" colname="col1" colwidth="2*"/> - <colspec colnum="5" colname="col4" colwidth="6*"/> - - <thead> - <row> - <entry>Name</entry> - <entry>Type</entry> - <entry>Default</entry> - <entry>Dynamic?</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - - <row> - <entry xml:id="log_level" xreflabel="log_level">log_level</entry> - <entry>integer</entry> - <entry>5</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>How verbose the logging is. There are six log - verbosity classes: 1 -- SYSERROR, 2 -- ERROR, 3 -- CRITICAL, 4 -- - WARNING, 5 -- INFO, 6 -- DEBUG. By setting log_level, - one can enable logging of all classes below or equal - to the given level. Tarantool prints its logs to the - standard error stream by default, but this can be - changed with the "logger" configuration parameter. - </entry> - </row> - - <row> - <entry xml:id="logger" xreflabel="logger">logger</entry> - <entry>string</entry> - <entry>null</entry> - <entry>no</entry> - <entry>By default, the log is sent to the standard - error stream (<filename>stderr</filename>). If logger - is specified, the log is sent to the file named in the string. - Example setting: logger = 'tarantool.log' - (this will open tarantool.log for output on the - server's default directory). - </entry> - </row> - - <row> - <entry>logger_nonblock</entry> - <entry>boolean</entry> - <entry>true</entry> - <entry>no</entry> - <entry>If logger_nonblock equals true, Tarantool does not - block on the log file descriptor when it's not - ready for write, and drops the message instead. If - log_level is high, and a lot of messages go to the log - file, setting logger_nonblock to true may improve logging - performance at the cost of some log messages getting - lost.</entry> - </row> - - <row> - <entry>too_long_threshold</entry> - <entry>float</entry> - <entry>0.5</entry> - <entry><emphasis role="strong">yes</emphasis></entry> - <entry>If processing a request takes longer than the - given value (in seconds), warn about it in the log. - Has effect only if log_level is less than or equal to 4 - (WARNING).</entry> - </row> - - </tbody> - </tgroup> - </table> - -</section> - -<section xml:id="local_hot_standby" xreflabel="local_hot_standby"> -<title>Local hot standby</title> - - <para> - Local hot standby is a feature which provides a simple form of failover without replication. - To initiate it, start a second instance of the Tarantool server on the same computer with - the same <code>box.cfg</code> configuration settings -- including the same directories and - same non-null URIs. - A warning should appear with a message like - "W> primary: [URI] is already in use, will retry binding after [n] seconds". - This is fine. - It means that the second instance is ready to take over if the first instance goes down. - </para> - <para> - The expectation is that there will be two - instances of the server using the same configuration. - The first one to start will be the "primary" instance. - The second one to start will be the "standby" instance. - The standby instance will initialize and will try to connect on listen - address and admin address, but will fail because the - primary instance has already taken them. - So the standby instance goes into a loop, reading the write - ahead log which the primary instance is writing (so the - two instances are always in synch), and trying to connect on the - ports. If the primary instance goes down for any reason, - the ports will become free so the standby instance will - succeed in connecting, and will become the primary instance. - Thus there is no noticeable downtime if the primary instance goes down. - </para> - <para> - If this local_hot_standby feature is being used, then replication_source should be an - empty string and wal_mode should not be equal to "none". - </para> - -</section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/user/connectors.xml b/doc/user/connectors.xml deleted file mode 100644 index 578ed4a6cbf86467dd208e38f673a99fdd64be40..0000000000000000000000000000000000000000 --- a/doc/user/connectors.xml +++ /dev/null @@ -1,324 +0,0 @@ -<!DOCTYPE book [ -<!ENTITY % tnt SYSTEM "../tnt.ent"> -%tnt; -]> -<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="connectors"> - -<title>Connectors</title> -<blockquote><para> - This chapter documents APIs for various programming languages. -</para></blockquote> - -<section xml:id="protocol"> - <title>Protocol</title> - <para>Tarantool protocol was designed with a focus on asynchronous - I/O and easy integration with proxies. Each client - request starts with a variable-length binary header, containing - request id, request type, server id, log sequence number, and - so on. - </para> - - <para> - The mandatory length, present in request header simplifies - client or proxy I/O. A response to a request is sent to the - client as soon as it is ready. It always carries in its header - the same type and id as in the request. The id makes it - possible to match a request to a response, even if the latter - arrived out of order. - </para> - - <para>Unless implementing a client driver, one needn't - concern oneself with the complications of the binary - protocol. <olink targetptr="connectors">Language-specific - drivers</olink> provide a friendly way to store domain - language data structures in Tarantool. - A complete description of the binary protocol - is maintained in annotated Backus-Naur - form in the source tree: please see - <link xlink:href="http://tarantool.org/doc/box-protocol.html"><filename>doc/box-protocol.html</filename></link>. - </para> -</section> - -<section xml:id="connector-packet-example"> -<title>Packet example</title> -<para> -The Tarantool API exists so that a client program can send a request packet -to the server, and receive a response. Here is an example of a what the client - would send for <command>box.space[513]:insert{'A', 'BB'}</command>. The BNF description of the components -is in file <link xlink:href="http://tarantool.org/doc/box-protocol.html" xlink:title="A complete BNF of Tarantool client/server protocol">doc/box-protocol.html</link>. - -</para> - <informaltable frame='topbot'> - <tgroup cols='5' align='left' colsep='1' rowsep='1'> - <colspec colname='c1'/> - <colspec colname='c2'/> - <colspec colname='c3'/> - <colspec colname='c4'/> - <colspec colname='c5'/> - <thead> - <row> - <entry>Component</entry> - <entry>Byte#0</entry> - <entry>Byte#1</entry> - <entry>Byte#2</entry> - <entry>Byte#3</entry> - </row> - </thead> - <tbody> - <row> - <entry>code for insert</entry> - <entry>2</entry> - </row> - <row> - <entry>rest of header</entry> - <entry>...</entry> - <entry>...</entry> - <entry>...</entry> - <entry>...</entry> - </row> - <row> - <entry>2-digit number: space id</entry> - <entry>cd</entry> - <entry>02</entry> - <entry>01</entry> - </row> - <row> - <entry>code for tuple</entry> - <entry>21</entry> - </row> - <row> - <entry>1-digit number: field count = 2</entry> - <entry>92</entry> - </row> - <row> - <entry>1-character string: field[1]</entry> - <entry>a1</entry> - <entry>41</entry> - </row> - <row> - <entry>2-character string: field[2]</entry> - <entry>a2</entry> - <entry>42</entry> - <entry>42</entry> - </row> - </tbody> - </tgroup> - </informaltable> -<para> -Now, one could send that packet to the tarantool server, -and interpret the response (doc/box-protocol.html has a description -of the packet format for responses as well as requests). -But it would be easier, and less error-prone, if one could -invoke a routine that formats the packet according to typed -parameters. Something like <code>response=tarantool_routine("insert",513,"A","B");</code>. -And that is why APIs exist for drivers for Perl, Python, PHP, and so on. -</para> - </section> - - <section xml:id="connector-server"> - <title>Setting up the server for connector examples</title> - <para> - This chapter has examples that show how to connect to the Tarantool - server via the Perl, PHP, and Python connectors. - The examples contain hard code that will work if and only if - the server (tarantool) is running on localhost (127.0.0.1) and is listening on port 3301 - (<code>box.cfg.listen='3301'</code>) and space 'examples' has id = 999 - (<code>box.space.tester.id = 999</code>), and - space 'examples' has a primary-key index for a numeric field - (<code>box.space[999].index[0].parts[1].type = "NUM"</code>) - and user 'guest' has privileges for reading and writing. - </para> - <para> - It is easy to meet all the conditions by starting the - server and executing this script:<programlisting> -box.cfg{listen=3301} -box.schema.space.create('examples',{id=999}) -box.space.examples:create_index('primary', {type = 'hash', parts = {1, 'NUM'}}) -box.schema.user.grant('guest','read,write','space','examples') -box.schema.user.grant('guest','read','space','_space') -</programlisting> - </para> - </section> - - <section xml:id="connector-java"> - <title>Java</title> - <para> - Please see <link xlink:href="http://dgreenru.github.io/tarantool-java/"><filename>http://dgreenru.github.io/tarantool-java/</filename></link>. - </para> - </section> - - <section xml:id="connector-go"> - <title>Go</title> - <para> - Please see <link xlink:href="https://github.com/mialinx/go-tarantool-1.6"><filename>https://github.com/mialinx/go-tarantool-1.6</filename></link>. - </para> - </section> - - <section xml:id="connector-perl"> - <title>Perl</title> - <para> - The most commonly used Perl driver is <link xlink:href='http://search.cpan.org/~unera/DR-Tarantool/'>DR::Tarantool</link>. - It is not supplied as part of the Tarantool repository; it must be installed separately. - The most common way to install it is with <link xlink:href='https://en.wikipedia.org/wiki/Cpan'>CPAN, the Comprehensive Perl Archive Network</link>. - DR::Tarantool requires other modules which should be installed first. - For example, on Ubuntu, the installation could look like this:<programlisting> -sudo cpan install AnyEvent -sudo cpan install Devel::GlobalDestruction -sudo cpan install Coro -sudo cpan install Test::Pod -sudo cpan install Test::Spelling -sudo cpan install PAR::Dist -sudo cpan install List::MoreUtils -sudo cpan install DR::Tarantool</programlisting> - </para> - <para> - Here is a complete Perl program that inserts [99999,'BB'] into space[999] via the Perl API. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run, paste the code into a file named example.pl and say <code>perl example.pl</code>. - The program will connect using an application-specific definition of the space. - The program will open a socket connection - with the tarantool server at localhost:3301, then send an INSERT request, - then — if all is well — end without displaying any messages. - If tarantool is not running on localhost with listen address = 3301, the program will print - <quote>Connection refused</quote>. - </para> - <para> - <programlisting language="perl"> -#!/usr/bin/perl -use DR::Tarantool ':constant', 'tarantool'; -use DR::Tarantool ':all'; -use DR::Tarantool::MsgPack::SyncClient; - -my $tnt = DR::Tarantool::MsgPack::SyncClient->connect( - host => '127.0.0.1', # look for tarantool on localhost - port => 3301, # assume tarantool listen address = default - user => 'guest', # username. one could also say 'password=>...' - - spaces => { - 999 => { # definition of space[999] ... - name => 'examples', # space[999] name = 'examples' - default_type => 'STR', # space[999] field type is 'STR' if undefined - fields => [ { # definition of space[512].fields ... - name => 'field1', type => 'NUM' } ], # space[999].field[1] name='field1',type='NUM' - indexes => { # definition of space[999] indexes ... - 0 => { - name => 'primary', fields => [ 'field1' ] } } } } ); - -$tnt->insert('examples' => [ 99999, 'BB' ]);</programlisting> - </para> - <para> - The example program only shows one command and does not show all that's necessary for - good practice. For that, please see - <link xlink:href='http://search.cpan.org/~unera/DR-Tarantool/'>DR::Tarantool CPAN repository</link>. - </para> - </section> - - <section xml:id="connector-php"> - <title>PHP</title> - - <para> - The PHP driver is <link xlink:href='https://github.com/tarantool/tarantool-php'>tarantool-php</link>. - It is not supplied as part of the Tarantool repository; it must be installed separately. - It can be installed with git. - It requires other modules which should be installed first. - For example, on Ubuntu, the installation could look like this: - <programlisting> -sudo apt-get install php5-cli -sudo apt-get install php5-dev -sudo apt-get install php-pear -cd ~ -git clone https://github.com/tarantool/tarantool-php.git -cd tarantool-php -phpize -./configure -make -#make install is optional</programlisting> - </para> - <para> - At this point there is a file named <filename>~/tarantool-php/modules/tarantool.so</filename>. - PHP will only find it if the PHP initialization file <filename>php.ini</filename> contains a line like - <code>extension=./tarantool.so</code>. - So copy <filename>tarantool.so</filename> to the working directory and tell PHP where - to find the <filename>php.ini</filename> file that contains that line ... - <programlisting> -cd ~ -cp ./tarantool-php/modules/tarantool.so . -export PHP_INI_SCAN_DIR=~/tarantool-php/test/shared</programlisting> - </para> - <para> - Here is a complete PHP program that inserts [99999,'BB'] into a space named 'examples' via the PHP API. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run, paste the code into a file named example.php and say <code>php example.php</code>. - The program will open a socket connection - with the tarantool server at localhost:3301, then send an INSERT request, - then — if all is well — print "Insert succeeded". - If the tuple already exists, the program will print <quote>Duplicate key exists in unique index 0</quote>. - </para> - <para> - <programlisting> -<?php -$tarantool = new Tarantool("localhost", 3301); -try { - $tarantool->insert("examples", array(99999, "BB")); - print "Insert succeeded\n"; - } -catch (Exception $e) { - echo "Exception: ", $e->getMessage(), "\n"; - } -?></programlisting> - </para> - <para> - After running the example, it is good practice to delete the file ./tarantool.so, - since it is only compatible with PHP and its existence could confuse non-PHP applications. - </para> - <para> - The example program only shows one command and does not show all that's necessary for - good practice. For that, please see - <link - xlink:href="https://github.com/tarantool/tarantool-php/"><filename>tarantool-php</filename></link> project at GitHub. - </para> - </section> - - <section xml:id="connector-python"> - <title>Python</title> - <para> - Here is a complete Python program that inserts [99999,'Value','Value'] into space <code>examples</code> via the high-level Python API. - </para> -<programlisting language="python"> -#!/usr/bin/python -from tarantool import Connection - -c = Connection("127.0.0.1", 3301) -result = c.insert("examples",(99999,'Value', 'Value')) -print result -</programlisting> - <para> - To prepare, paste the code into a file named example.py and install tarantool-python with either - <userinput><code>pip install tarantool\>0.4</code></userinput> to install in <filename>/usr</filename> (requires root privilege) - or - <userinput><code>pip install tarantool\>0.4 --user</code></userinput> to install in <filename>~</filename> i.e. user's default directory. - Before trying to run, check that the server is listening and that <code>examples</code> exists, - as described <link linkend="connector-server">earlier</link>. - To run the program, say <code>python example.py</code>. - The program will connect to the server, will send the request, and will not throw an exception if all went well. - If the tuple already exists, the program will throw DatabaseException(“Duplicate key exists in unique indexâ€). - </para> - <para> - The example program only shows one request and does not show all that's necessary for - good practice. For that, see - <link xlink:href="http://github.com/tarantool/tarantool-python"><filename>http://github.com/tarantool/tarantool-python</filename></link>. - For an example of a Python API for <link xlink:href="https://github.com/tarantool/queue">Queue managers on Tarantool</link>, see - <link xlink:href="https://github.com/tarantool/tarantool-queue-python"><filename>https://github.com/tarantool/tarantool-queue-python</filename></link>. - </para> - </section> - -</chapter> - -<!-- -vim: tw=66 syntax=docbk -vim: spell spelllang=en_us ---> diff --git a/doc/www/content/js/old_tabs.js b/doc/www/content/js/old_tabs.js deleted file mode 100644 index 7f8891a8fb11ebf57c44f40cc141c724af1952d1..0000000000000000000000000000000000000000 --- a/doc/www/content/js/old_tabs.js +++ /dev/null @@ -1,187 +0,0 @@ -(function(){ -var dOn = $(document); - -dOn.on({ - click: function(){ - if (!($(this).hasClass('b-button_on'))){ - $('.b-button_on').removeClass('b-button_on'); - $(this).addClass('b-button_on'); - - switch ($(this).html()) { - case 'A_Read' : { - $('#picture2').renderChart('/ycsb/A_READ_latency.json'); - break; - } - case 'A_Update' : { - $('#picture2').renderChart('/ycsb/A_UPDATE_latency.json'); - break; - } - case 'B_Read' : { - $('#picture2').renderChart('/ycsb/B_READ_latency.json'); - break; - } - case 'B_Update' : { - $('#picture2').renderChart('/ycsb/B_UPDATE_latency.json'); - break; - } - case 'C_Read' : { - $('#picture2').renderChart('/ycsb/C_READ_latency.json'); - break; - } - case 'D_Insert' : { - $('#picture2').renderChart('/ycsb/D_INSERT_latency.json'); - break; - } - case 'D_Read' : { - $('#picture2').renderChart('/ycsb/D_READ_latency.json'); - break; - } - case 'E_Insert' : { - $('#picture2').renderChart('/ycsb/E_INSERT_latency.json'); - break; - } - case 'E_Scan' : { - $('#picture2').renderChart('/ycsb/E_SCAN_latency.json'); - break; - } - case 'F_Read' : { - $('#picture2').renderChart('/ycsb/F_READ_latency.json'); - break; - } - case 'F_Read-Modify-Write' : { - $('#picture2').renderChart('/ycsb/F_READ-MODIFY-WRITE_latency.json'); - break; - } - case 'F_Update' : { - $('#picture2').renderChart('/ycsb/F_UPDATE_latency.json'); - break; - } - case 'LOAD_Insert' : { - $('#picture2').renderChart('/ycsb/LOAD_INSERT_latency.json'); - break; - } - } - - } - } -}, '.b-button'); - -dOn.on({ - click: function(){ - if (!($(this).hasClass('b-tabs__li_on'))){ - $('.b-tabs__li_on').removeClass('b-tabs__li_on'); - $(this).addClass('b-tabs__li_on'); - - $('.b-button').remove(); - var head = $('.b-tabs__header'), ul = $('.b-tabs__buttons'), li, desc = $('.b-tabs__description'); - - switch ($(this).html()) { - case 'A' : { - head.html('Workload A') - $('#picture1').renderChart('/ycsb/A_throughput.json'); - $('#picture2').renderChart('/ycsb/A_READ_latency.json'); - - li = $('<li class="b-button b-button_on">A_Read</li>'); - ul.append(li); - li = $('<li class="b-button">A_Update</li>'); - ul.append(li); - - desc.html('50/50 update/read ratio'); - - break; - } - case 'B' : { - head.html('Workload B') - $('#picture1').renderChart('/ycsb/B_throughput.json'); - $('#picture2').renderChart('/ycsb/B_READ_latency.json'); - - li = $('<li class="b-button b-button_on">B_Read</li>'); - ul.append(li); - li = $('<li class="b-button">B_Update</li>'); - ul.append(li); - - desc.html('5/95 update/read ratio'); - - break; - } - case 'C' : { - head.html('Workload C') - $('#picture1').renderChart('/ycsb/C_throughput.json'); - $('#picture2').renderChart('/ycsb/C_READ_latency.json'); - - li = $('<li class="b-button b-button_on">C_Read</li>'); - ul.append(li); - - desc.html('100% read-only'); - - break; - } - case 'D' : { - head.html('Workload D') - $('#picture1').renderChart('/ycsb/D_throughput.json'); - $('#picture2').renderChart('/ycsb/D_READ_latency.json'); - - li = $('<li class="b-button b-button_on">D_Read</li>'); - ul.append(li); - li = $('<li class="b-button">D_Insert</li>'); - ul.append(li); - - desc.html('5/95 insert/read ratio, the read load is skewed towards the end of the key range'); - - break; - } - case 'E' : { - head.html('Workload E') - $('#picture1').renderChart('/ycsb/E_throughput.json'); - $('#picture2').renderChart('/ycsb/E_INSERT_latency.json'); - - li = $('<li class="b-button b-button_on">E_Insert</li>'); - ul.append(li); - li = $('<li class="b-button">E_Scan</li>'); - ul.append(li); - - desc.html('5/95 ratio of insert/reads over a range of 10 records'); - - break; - } - case 'F' : { - head.html('Workload F') - $('#picture1').renderChart('/ycsb/F_throughput.json'); - $('#picture2').renderChart('/ycsb/F_READ_latency.json'); - - li = $('<li class="b-button b-button_on">F_Read</li>'); - ul.append(li); - li = $('<li class="b-button">F_Read-Modify-Write</li>'); - ul.append(li); - li = $('<li class="b-button">F_Update</li>'); - ul.append(li); - - desc.html('95% read/modify/write, 5% read'); - - break; - } - case 'LOAD' : { - head.html('Insert only') - $('#picture1').renderChart('/ycsb/LOAD_throughput.json'); - $('#picture2').renderChart('/ycsb/LOAD_INSERT_latency.json'); - - li = $('<li class="b-button b-button_on">L_Insert</li>'); - ul.append(li); - - desc.html(''); - - break; - } - } - } - } -}, '.b-tabs__li'); -})(); - -(function(){ -var dOn = $(document); -dOn.ready(function() { - $('#picture1').renderChart('/ycsb/A_throughput.json'); - $('#picture2').renderChart('/ycsb/A_READ_latency.json'); -}); -})(); diff --git a/doc/www/content/newsite/benchmark.yml b/doc/www/content/newsite/benchmark.yml index e8df8c0b64717e98a35057ef08dece11b76cb677..ecc7e23f3068ad6935158be7be36561d5f14e4d6 100644 --- a/doc/www/content/newsite/benchmark.yml +++ b/doc/www/content/newsite/benchmark.yml @@ -40,10 +40,10 @@ blocks : Tarantool support is available `here <https://github.com/bigbes92/YCSB>`_. Since YCSB was developed to compare cloud key/value servers, it - provides a very narrow view benchmarking kit is more - appropriate. This is why Yahoo! Cloud secondary keys - or overhead of locking (which Tarantool doesn't have) - is not tested at all. + provides a very narrow view at performance of a tested + server. For example, performance of secondary keys or + overhead of locking (which Tarantool doesn't have) is + not tested at all. .. |copy| unicode:: U+000A9 diff --git a/doc/www/content/newsite/documentation.yml b/doc/www/content/newsite/documentation.yml deleted file mode 100644 index 739f503d27d4751ac0b1c6eae7f5d181a0b9b425..0000000000000000000000000000000000000000 --- a/doc/www/content/newsite/documentation.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -title : "Tarantool - Documentation" -slug : "documentation" -save_as : "documentation.html" -template: "documentation" -blocks : - sections: - - name: "Introduction" - list: - - name: "What is Tarantool?" - link: "doc/introduction.html#what-is-tarantool" - - name: "An overview of the architecture" - link: "doc/introduction.html#an-overview-of-the-architecture" - - name: "Key features" - link: "doc/introduction.html#key-features" - - name: "How stable is the software?" - link: "doc/introduction.html#how-stable-is-the-software" - - name: "User Guide" - list: - - name: "Multi page HTML" - link: "doc/user_guide/" - - name: "Single page HTML" - link: "doc/user_guide.html" - - name: "FAQ" - link: "doc/faq.html" - - name: "Developer section" - list: - - name: "Developer Guide" - link: "doc/dev_guide.html" - - name: "IProto Protocol" - link: "doc/box-protocol.html" - -... diff --git a/doc/www/content/ycsb/1.py b/doc/www/content/ycsb/1.py deleted file mode 100755 index 8cfe4ea923aba8dbf28d77e9fa3b524d9528363e..0000000000000000000000000000000000000000 --- a/doc/www/content/ycsb/1.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -import os -import glob -import json - -a = glob.glob("*.json") - -for f in a: - open(f + ".out", 'w').write(json.dumps(json.loads(open(f, 'r').read()), sort_keys=True, indent=4)) diff --git a/doc/www/content/ycsb/A_READ_latency.json b/doc/www/content/ycsb/A_READ_latency.json index a99eb9336acce1c96fa49027c990eb40f01c680c..ae8cef9a8b2241c620e317999d408567e5a4db71 100644 --- a/doc/www/content/ycsb/A_READ_latency.json +++ b/doc/www/content/ycsb/A_READ_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 238.3 + "y": 238.56 }, { "x": 16, - "y": 322.78 + "y": 321.57 }, { "x": 32, - "y": 422.29 + "y": 407.0 }, { "x": 64, - "y": 823.54 + "y": 786.32 }, { "x": 128, - "y": 1674.64 + "y": 1701.38 }, { "x": 256, - "y": 3453.41 + "y": 3296.77 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 177.53 + "y": 173.25 }, { "x": 16, - "y": 212.79 + "y": 223.19 }, { "x": 32, - "y": 384.8 + "y": 327.81 }, { "x": 64, - "y": 781.84 + "y": 691.3 }, { "x": 128, - "y": 1557.11 + "y": 1431.62 }, { "x": 256, - "y": 3152.47 + "y": 2877.7 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 196.98 + "y": 175.08 }, { "x": 16, - "y": 255.04 + "y": 222.31 }, { "x": 32, - "y": 526.46 + "y": 346.42 }, { "x": 64, - "y": 1041.25 + "y": 714.42 }, { "x": 128, - "y": 2083.02 + "y": 1421.44 }, { "x": 256, - "y": 4115.76 + "y": 2877.45 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/A_UPDATE_latency.json b/doc/www/content/ycsb/A_UPDATE_latency.json index ec2bab41beac1db395765a27e9abdb198e189a79..d0528bb8b75f799cae2d6c67d50c767d0a2796a7 100644 --- a/doc/www/content/ycsb/A_UPDATE_latency.json +++ b/doc/www/content/ycsb/A_UPDATE_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 217.73 + "y": 217.45 }, { "x": 16, - "y": 300.25 + "y": 298.58 }, { "x": 32, - "y": 402.81 + "y": 386.43 }, { "x": 64, - "y": 808.84 + "y": 771.9 }, { "x": 128, - "y": 1653.34 + "y": 1680.56 }, { "x": 256, - "y": 3424.24 + "y": 3267.28 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 184.09 + "y": 178.18 }, { "x": 16, - "y": 222.08 + "y": 230.49 }, { "x": 32, - "y": 387.34 + "y": 329.9 }, { "x": 64, - "y": 783.16 + "y": 691.71 }, { "x": 128, - "y": 1558.04 + "y": 1431.35 }, { "x": 256, - "y": 3152.19 + "y": 2876.22 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 201.19 + "y": 180.19 }, { "x": 16, - "y": 260.99 + "y": 229.62 }, { "x": 32, - "y": 527.1 + "y": 348.42 }, { "x": 64, - "y": 1041.35 + "y": 714.79 }, { "x": 128, - "y": 2082.11 + "y": 1421.39 }, { "x": 256, - "y": 4114.76 + "y": 2876.09 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/A_throughput.json b/doc/www/content/ycsb/A_throughput.json index 0d7563a9cacc8ccd1358812b1b534668b79527c7..43c879e37b5ea6fee0868dbbaa2ad2ddf4e3396c 100644 --- a/doc/www/content/ycsb/A_throughput.json +++ b/doc/www/content/ycsb/A_throughput.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 31562.23 + "y": 31616.63 }, { "x": 16, - "y": 48114.504 + "y": 48164.624 }, { "x": 32, - "y": 74829.546 + "y": 77671.66 }, { "x": 64, - "y": 76531.577 + "y": 80181.142 }, { "x": 128, - "y": 75436.465 + "y": 74239.826 }, { "x": 256, - "y": 73227.805 + "y": 76748.628 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 40138.01 + "y": 41198.855 }, { "x": 16, - "y": 69150.347 + "y": 66591.308 }, { "x": 32, - "y": 80856.866 + "y": 94335.042 }, { "x": 64, - "y": 80825.48 + "y": 91319.348 }, { "x": 128, - "y": 81415.534 + "y": 88474.373 }, { "x": 256, - "y": 80197.603 + "y": 87626.284 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 36628.178 + "y": 41482.074 }, { "x": 16, - "y": 58990.98 + "y": 66567.06 }, { "x": 32, - "y": 59768.109 + "y": 89820.126 }, { "x": 64, - "y": 60935.21 + "y": 88425.776 }, { "x": 128, - "y": 61050.897 + "y": 89046.299 }, { "x": 256, - "y": 61660.282 + "y": 87689.532 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/B_READ_latency.json b/doc/www/content/ycsb/B_READ_latency.json index 69ec3de179659ee9d297c4ff31179d132267f71f..1408d5f3463b561f07850aa23bc3a8e12f266d73 100644 --- a/doc/www/content/ycsb/B_READ_latency.json +++ b/doc/www/content/ycsb/B_READ_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 234.07 + "y": 251.7 }, { "x": 16, - "y": 332.82 + "y": 333.41 }, { "x": 32, - "y": 434.14 + "y": 436.93 }, { "x": 64, - "y": 827.22 + "y": 849.47 }, { "x": 128, - "y": 1691.27 + "y": 1701.41 }, { "x": 256, - "y": 3276.43 + "y": 3429.75 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 202.35 + "y": 186.74 }, { "x": 16, - "y": 259.18 + "y": 237.12 }, { "x": 32, - "y": 347.49 + "y": 281.9 }, { "x": 64, - "y": 706.49 + "y": 525.57 }, { "x": 128, - "y": 1438.33 + "y": 1073.18 }, { "x": 256, - "y": 2904.98 + "y": 2140.08 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 215.67 + "y": 197.49 }, { "x": 16, - "y": 268.06 + "y": 258.31 }, { "x": 32, - "y": 506.92 + "y": 351.26 }, { "x": 64, - "y": 999.01 + "y": 698.75 }, { "x": 128, - "y": 1995.78 + "y": 1398.72 }, { "x": 256, - "y": 4036.14 + "y": 2842.95 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/B_UPDATE_latency.json b/doc/www/content/ycsb/B_UPDATE_latency.json index 8ec339eb66585e2eda62d8b505e799103c9e4668..4e6b219ec6963eddccc863e6d20290b019d623e8 100644 --- a/doc/www/content/ycsb/B_UPDATE_latency.json +++ b/doc/www/content/ycsb/B_UPDATE_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 229.62 + "y": 247.97 }, { "x": 16, - "y": 324.93 + "y": 325.26 }, { "x": 32, - "y": 423.11 + "y": 425.87 }, { "x": 64, - "y": 820.99 + "y": 843.5 }, { "x": 128, - "y": 1681.57 + "y": 1691.5 }, { "x": 256, - "y": 3260.8 + "y": 3414.33 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 204.72 + "y": 185.36 }, { "x": 16, - "y": 261.95 + "y": 239.46 }, { "x": 32, - "y": 346.79 + "y": 284.44 }, { "x": 64, - "y": 703.47 + "y": 523.05 }, { "x": 128, - "y": 1435.14 + "y": 1070.05 }, { "x": 256, - "y": 2901.57 + "y": 2136.53 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 216.46 + "y": 196.99 }, { "x": 16, - "y": 269.8 + "y": 260.05 }, { "x": 32, - "y": 502.79 + "y": 350.16 }, { "x": 64, - "y": 995.77 + "y": 694.78 }, { "x": 128, - "y": 1992.37 + "y": 1395.54 }, { "x": 256, - "y": 4033.11 + "y": 2839.55 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/B_throughput.json b/doc/www/content/ycsb/B_throughput.json index f5b180bcae9d8c095749c4b5687b11e36d83edf8..517c80bc15df3e269dabf7eee6accb8f171d809b 100644 --- a/doc/www/content/ycsb/B_throughput.json +++ b/doc/www/content/ycsb/B_throughput.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 28485.608 + "y": 28377.237 }, { "x": 16, - "y": 44253.794 + "y": 44401.604 }, { "x": 32, - "y": 70902.442 + "y": 70977.722 }, { "x": 64, - "y": 75737.47 + "y": 73819.817 }, { "x": 128, - "y": 74245.59 + "y": 73776.249 }, { "x": 256, - "y": 76628.854 + "y": 73478.511 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 34893.927 + "y": 37514.65 }, { "x": 16, - "y": 57192.82 + "y": 62605.613 }, { "x": 32, - "y": 89315.362 + "y": 108612.579 }, { "x": 64, - "y": 89415.76 + "y": 119310.168 }, { "x": 128, - "y": 88026.826 + "y": 117183.867 }, { "x": 256, - "y": 86866.271 + "y": 116794.729 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 33145.744 + "y": 36015.58 }, { "x": 16, - "y": 55755.676 + "y": 57811.373 }, { "x": 32, - "y": 62043.479 + "y": 88502.1 }, { "x": 64, - "y": 63502.111 + "y": 90438.228 }, { "x": 128, - "y": 63688.278 + "y": 90389.708 }, { "x": 256, - "y": 62882.635 + "y": 88585.185 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/C_READ_latency.json b/doc/www/content/ycsb/C_READ_latency.json index 9fe01b366945a090d10c2de9ee3256bea2116855..c32657caeba90528e59c4d208ee54ee57633998a 100644 --- a/doc/www/content/ycsb/C_READ_latency.json +++ b/doc/www/content/ycsb/C_READ_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 237.65 + "y": 235.26 }, { "x": 16, - "y": 326.34 + "y": 326.4 }, { "x": 32, - "y": 427.78 + "y": 429.12 }, { "x": 64, - "y": 721.95 + "y": 762.74 }, { "x": 128, - "y": 1549.93 + "y": 1554.06 }, { "x": 256, - "y": 3038.2 + "y": 3077.94 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 264.62 + "y": 207.76 }, { "x": 16, - "y": 342.02 + "y": 291.43 }, { "x": 32, - "y": 508.55 + "y": 389.65 }, { "x": 64, - "y": 1015.86 + "y": 662.14 }, { "x": 128, - "y": 2041.95 + "y": 1201.79 }, { "x": 256, - "y": 4137.54 + "y": 2347.59 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 262.65 + "y": 230.83 }, { "x": 16, - "y": 341.1 + "y": 307.77 }, { "x": 32, - "y": 513.74 + "y": 389.51 }, { "x": 64, - "y": 1028.74 + "y": 684.74 }, { "x": 128, - "y": 2056.74 + "y": 1363.18 }, { "x": 256, - "y": 4153.88 + "y": 2750.21 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/C_throughput.json b/doc/www/content/ycsb/C_throughput.json index a4b0e1baf8b9212ff6f97a64fb092320224367d7..8cb7f9f4fe588b4abc5ea10514ca07190a076ece 100644 --- a/doc/www/content/ycsb/C_throughput.json +++ b/doc/www/content/ycsb/C_throughput.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 29119.583 + "y": 27843.342 }, { "x": 16, - "y": 45503.99 + "y": 45460.125 }, { "x": 32, - "y": 72268.639 + "y": 71988.614 }, { "x": 64, - "y": 86938.763 + "y": 82428.213 }, { "x": 128, - "y": 81024.126 + "y": 80868.366 }, { "x": 256, - "y": 82035.127 + "y": 81323.473 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 26085.671 + "y": 32443.698 }, { "x": 16, - "y": 43450.932 + "y": 50471.791 }, { "x": 32, - "y": 61286.668 + "y": 79508.113 }, { "x": 64, - "y": 62427.818 + "y": 89683.067 }, { "x": 128, - "y": 62266.579 + "y": 97592.776 }, { "x": 256, - "y": 61389.134 + "y": 98615.937 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 26830.928 + "y": 28821.365 }, { "x": 16, - "y": 43539.712 + "y": 47790.788 }, { "x": 32, - "y": 60796.056 + "y": 79282.154 }, { "x": 64, - "y": 61628.435 + "y": 92164.012 }, { "x": 128, - "y": 61818.459 + "y": 92751.024 }, { "x": 256, - "y": 61134.947 + "y": 91425.074 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/D_INSERT_latency.json b/doc/www/content/ycsb/D_INSERT_latency.json index c6104b490a9f622bebc846cd749d34aeecfba58c..87751ff1d6be2ab337c24236b0becd7896b1d6d8 100644 --- a/doc/www/content/ycsb/D_INSERT_latency.json +++ b/doc/www/content/ycsb/D_INSERT_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 506.78 + "y": 515.11 }, { "x": 16, - "y": 692.44 + "y": 697.82 }, { "x": 32, - "y": 874.74 + "y": 885.49 }, { "x": 64, - "y": 1628.55 + "y": 1642.56 }, { "x": 128, - "y": 3290.35 + "y": 3344.88 }, { "x": 256, - "y": 6598.28 + "y": 6563.97 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 309.23 + "y": 300.75 }, { "x": 16, - "y": 379.22 + "y": 363.55 }, { "x": 32, - "y": 445.48 + "y": 449.73 }, { "x": 64, - "y": 725.08 + "y": 710.01 }, { "x": 128, - "y": 1408.9 + "y": 1249.62 }, { "x": 256, - "y": 2811.35 + "y": 2410.87 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 326.17 + "y": 301.08 }, { "x": 16, - "y": 404.81 + "y": 382.13 }, { "x": 32, - "y": 548.83 + "y": 463.92 }, { "x": 64, - "y": 1013.01 + "y": 701.5 }, { "x": 128, - "y": 1997.72 + "y": 1360.56 }, { "x": 256, - "y": 4044.73 + "y": 2787.05 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/D_READ_latency.json b/doc/www/content/ycsb/D_READ_latency.json index 0af42b33900cda8b553f9d6c0bdd3c7643562c98..b9ecedd9d6575fdebe926e835821d264e097a2d3 100644 --- a/doc/www/content/ycsb/D_READ_latency.json +++ b/doc/www/content/ycsb/D_READ_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 234.29 + "y": 239.06 }, { "x": 16, - "y": 333.11 + "y": 336.21 }, { "x": 32, - "y": 425.34 + "y": 430.47 }, { "x": 64, - "y": 786.06 + "y": 794.71 }, { "x": 128, - "y": 1598.31 + "y": 1623.38 }, { "x": 256, - "y": 3259.53 + "y": 3244.48 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 239.51 + "y": 225.17 }, { "x": 16, - "y": 308.28 + "y": 293.7 }, { "x": 32, - "y": 383.94 + "y": 389.23 }, { "x": 64, - "y": 704.85 + "y": 659.72 }, { "x": 128, - "y": 1399.2 + "y": 1200.99 }, { "x": 256, - "y": 2805.02 + "y": 2356.8 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 262.22 + "y": 228.37 }, { "x": 16, - "y": 341.01 + "y": 312.93 }, { "x": 32, - "y": 494.61 + "y": 403.93 }, { "x": 64, - "y": 998.86 + "y": 676.18 }, { "x": 128, - "y": 1987.73 + "y": 1349.59 }, { "x": 256, - "y": 4039.56 + "y": 2774.49 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/D_throughput.json b/doc/www/content/ycsb/D_throughput.json index d6b148dd9ccba88fa30d306427b950e8d14237ff..f0239d714fbdb3ad6203d5303daf29df85d9a620 100644 --- a/doc/www/content/ycsb/D_throughput.json +++ b/doc/www/content/ycsb/D_throughput.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 27651.545 + "y": 27198.606 }, { "x": 16, - "y": 42334.148 + "y": 42223.887 }, { "x": 32, - "y": 69058.03 + "y": 68327.403 }, { "x": 64, - "y": 75974.498 + "y": 75135.152 }, { "x": 128, - "y": 74659.092 + "y": 73590.408 }, { "x": 256, - "y": 73506.81 + "y": 73978.39 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 28808.773 + "y": 29905.066 }, { "x": 16, - "y": 47085.67 + "y": 49494.828 }, { "x": 32, - "y": 79941.384 + "y": 78919.769 }, { "x": 64, - "y": 89276.877 + "y": 90182.796 }, { "x": 128, - "y": 90329.51 + "y": 97636.591 }, { "x": 256, - "y": 89717.039 + "y": 98765.799 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 26632.372 + "y": 29023.419 }, { "x": 16, - "y": 42997.674 + "y": 46679.054 }, { "x": 32, - "y": 62493.662 + "y": 75973.644 }, { "x": 64, - "y": 63408.932 + "y": 93025.514 }, { "x": 128, - "y": 63939.276 + "y": 93688.949 }, { "x": 256, - "y": 62785.577 + "y": 90518.76 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/E_INSERT_latency.json b/doc/www/content/ycsb/E_INSERT_latency.json index 2dd8010334942743260684ba3ea4aaab56c5774b..e65959630e4da6f80c3402932eedc741bc3e74d1 100644 --- a/doc/www/content/ycsb/E_INSERT_latency.json +++ b/doc/www/content/ycsb/E_INSERT_latency.json @@ -6,63 +6,65 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 619.47 + "y": 597.75 }, { "x": 16, - "y": 780.09 + "y": 785.29 }, { "x": 32, - "y": 1003.09 + "y": 1005.3 }, { "x": 64, - "y": 1870.34 + "y": 1893.66 }, { "x": 128, - "y": 3756.31 + "y": 3655.0 }, { "x": 256, - "y": 6354.63 + "y": 7133.25 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 311.51 + "y": 271.73 }, { "x": 16, - "y": 305.95 + "y": 284.38 }, { "x": 32, - "y": 317.73 + "y": 294.93 }, { "x": 64, - "y": 322.43 + "y": 296.21 }, { "x": 128, - "y": 324.71 + "y": 311.41 }, { "x": 256, - "y": 353.2 + "y": 352.28 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" } ], @@ -88,4 +90,4 @@ "text": "Latency(usec)" } } -} +} \ No newline at end of file diff --git a/doc/www/content/ycsb/E_SCAN_latency.json b/doc/www/content/ycsb/E_SCAN_latency.json index 24c7c677eceffe8d80276e4fbd426bae6e523cf9..fa65ecd28470cbe7e4f32ceed996748e5f97b94c 100644 --- a/doc/www/content/ycsb/E_SCAN_latency.json +++ b/doc/www/content/ycsb/E_SCAN_latency.json @@ -6,34 +6,66 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 12647.3 + "y": 12604.61 }, { "x": 16, - "y": 17509.19 + "y": 17581.77 }, { "x": 32, - "y": 23218.92 + "y": 23121.94 }, { "x": 64, - "y": 43893.15 + "y": 44215.36 }, { "x": 128, - "y": 90066.49 + "y": 87342.63 }, { "x": 256, - "y": 156887.52 + "y": 176624.64 } ], "name": "Redis 2.8.19", "type": "line" + }, + { + "color": "#2f7ed8", + "data": [ + { + "x": 8, + "y": 858.28 + }, + { + "x": 16, + "y": 1818.22 + }, + { + "x": 32, + "y": 3752.74 + }, + { + "x": 64, + "y": 7428.16 + }, + { + "x": 128, + "y": 15037.42 + }, + { + "x": 256, + "y": 31995.84 + } + ], + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", + "type": "line" } ], "subtitle": { @@ -58,4 +90,4 @@ "text": "Latency(usec)" } } -} +} \ No newline at end of file diff --git a/doc/www/content/ycsb/E_throughput.json b/doc/www/content/ycsb/E_throughput.json index a9f13414029e94978379c61a1a58150ed6edb2bc..78efa21b760a70a30a454e28acd7167690c4874c 100644 --- a/doc/www/content/ycsb/E_throughput.json +++ b/doc/www/content/ycsb/E_throughput.json @@ -6,63 +6,65 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 580.348 + "y": 569.539 }, { "x": 16, - "y": 895.467 + "y": 893.546 }, { "x": 32, - "y": 1409.266 + "y": 1421.844 }, { "x": 64, - "y": 1501.626 + "y": 1491.228 }, { "x": 128, - "y": 1465.921 + "y": 1512.563 }, { "x": 256, - "y": 1462.514 + "y": 1493.221 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 8345.315 + "y": 9299.282 }, { "x": 16, - "y": 8649.963 + "y": 8976.991 }, { "x": 32, - "y": 8585.98 + "y": 8780.54 }, { "x": 64, - "y": 8432.671 + "y": 8871.066 }, { "x": 128, - "y": 8460.972 + "y": 8740.354 }, { "x": 256, - "y": 7924.404 + "y": 8195.7 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" } ], @@ -88,4 +90,4 @@ "text": "RPS" } } -} +} \ No newline at end of file diff --git a/doc/www/content/ycsb/F_READ-MODIFY-WRITE_latency.json b/doc/www/content/ycsb/F_READ-MODIFY-WRITE_latency.json index 710034be20f73f45a47925724f68a3062bea339e..29a89411c84fb3a7f9ac4fd5e6a17a98f983127f 100644 --- a/doc/www/content/ycsb/F_READ-MODIFY-WRITE_latency.json +++ b/doc/www/content/ycsb/F_READ-MODIFY-WRITE_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 459.03 + "y": 463.27 }, { "x": 16, - "y": 638.04 + "y": 646.42 }, { "x": 32, - "y": 803.07 + "y": 847.48 }, { "x": 64, - "y": 1616.46 + "y": 1675.71 }, { "x": 128, - "y": 3401.07 + "y": 3452.37 }, { "x": 256, - "y": 6862.11 + "y": 6854.32 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 395.41 + "y": 330.44 }, { "x": 16, - "y": 503.29 + "y": 426.8 }, { "x": 32, - "y": 998.46 + "y": 548.74 }, { "x": 64, - "y": 1972.22 + "y": 1089.92 }, { "x": 128, - "y": 3956.45 + "y": 2193.52 }, { "x": 256, - "y": 8078.09 + "y": 4500.88 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 398.2 + "y": 359.62 }, { "x": 16, - "y": 492.26 + "y": 456.5 }, { "x": 32, - "y": 1006.59 + "y": 668.11 }, { "x": 64, - "y": 2010.05 + "y": 1378.99 }, { "x": 128, - "y": 4008.02 + "y": 2737.57 }, { "x": 256, - "y": 8093.19 + "y": 5557.44 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/F_READ_latency.json b/doc/www/content/ycsb/F_READ_latency.json index 3dea857070c1f0f6af8f9c3e9a016c2f0aca953f..1d42ef57f517636147a54de13e60f9d05a5289de 100644 --- a/doc/www/content/ycsb/F_READ_latency.json +++ b/doc/www/content/ycsb/F_READ_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 234.58 + "y": 238.27 }, { "x": 16, - "y": 321.65 + "y": 326.03 }, { "x": 32, - "y": 406.11 + "y": 428.58 }, { "x": 64, - "y": 813.29 + "y": 842.29 }, { "x": 128, - "y": 1705.28 + "y": 1728.37 }, { "x": 256, - "y": 3431.76 + "y": 3424.16 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 193.35 + "y": 159.7 }, { "x": 16, - "y": 245.7 + "y": 206.56 }, { "x": 32, - "y": 494.63 + "y": 269.29 }, { "x": 64, - "y": 981.15 + "y": 539.33 }, { "x": 128, - "y": 1970.92 + "y": 1086.72 }, { "x": 256, - "y": 4030.48 + "y": 2231.25 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 194.34 + "y": 174.48 }, { "x": 16, - "y": 239.98 + "y": 221.86 }, { "x": 32, - "y": 498.63 + "y": 329.54 }, { "x": 64, - "y": 1000.1 + "y": 684.31 }, { "x": 128, - "y": 1997.12 + "y": 1360.1 }, { "x": 256, - "y": 4034.72 + "y": 2762.7 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/F_UPDATE_latency.json b/doc/www/content/ycsb/F_UPDATE_latency.json index d590d86e03e6cd097cdb447216b8a7f434655f39..7a4394f09a24b9f06040a5df5f4bea43e67829f0 100644 --- a/doc/www/content/ycsb/F_UPDATE_latency.json +++ b/doc/www/content/ycsb/F_UPDATE_latency.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 221.44 + "y": 221.68 }, { "x": 16, - "y": 312.63 + "y": 316.53 }, { "x": 32, - "y": 392.26 + "y": 414.07 }, { "x": 64, - "y": 795.46 + "y": 826.63 }, { "x": 128, - "y": 1681.44 + "y": 1708.21 }, { "x": 256, - "y": 3400.16 + "y": 3397.42 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 198.21 + "y": 166.96 }, { "x": 16, - "y": 253.66 + "y": 215.97 }, { "x": 32, - "y": 500.29 + "y": 275.58 }, { "x": 64, - "y": 986.68 + "y": 544.1 }, { "x": 128, - "y": 1976.95 + "y": 1091.6 }, { "x": 256, - "y": 4034.2 + "y": 2234.85 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 200.15 + "y": 181.14 }, { "x": 16, - "y": 248.21 + "y": 230.36 }, { "x": 32, - "y": 504.48 + "y": 334.89 }, { "x": 64, - "y": 1005.67 + "y": 689.19 }, { "x": 128, - "y": 2003.32 + "y": 1365.42 }, { "x": 256, - "y": 4040.07 + "y": 2766.05 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/content/ycsb/F_throughput.json b/doc/www/content/ycsb/F_throughput.json index 31c92d8f984bd0bd72142823f2772da3da78086a..133cf993da94ad9d34260b5b9a7d46a8649ddf3b 100644 --- a/doc/www/content/ycsb/F_throughput.json +++ b/doc/www/content/ycsb/F_throughput.json @@ -6,93 +6,96 @@ "legend": {}, "series": [ { + "color": "#0d233a", "data": [ { "x": 8, - "y": 20258.78 + "y": 20176.315 }, { "x": 16, - "y": 31493.762 + "y": 30970.398 }, { "x": 32, - "y": 51212.408 + "y": 48598.597 }, { "x": 64, - "y": 51876.851 + "y": 49943.616 }, { "x": 128, - "y": 49399.004 + "y": 48719.857 }, { "x": 256, - "y": 49151.876 + "y": 49244.651 } ], "name": "Redis 2.8.19", "type": "line" }, { + "color": "#2f7ed8", "data": [ { "x": 8, - "y": 25019.921 + "y": 29521.74 }, { "x": 16, - "y": 40993.359 + "y": 47992.147 }, { "x": 32, - "y": 42311.419 + "y": 76225.974 }, { "x": 64, - "y": 43051.195 + "y": 77599.478 }, { "x": 128, - "y": 42910.444 + "y": 77191.581 }, { "x": 256, - "y": 42003.284 + "y": 75095.998 } ], - "name": "Tarantool (TREE, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (TREE, 1.6.4-564-ge6e1429)", "type": "line" }, { + "color": "#8bbc21", "data": [ { "x": 8, - "y": 25113.338 + "y": 27194.077 }, { "x": 16, - "y": 41810.641 + "y": 44936.537 }, { "x": 32, - "y": 41984.073 + "y": 62744.686 }, { "x": 64, - "y": 42242.509 + "y": 61460.56 }, { "x": 128, - "y": 42338.889 + "y": 61952.441 }, { "x": 256, - "y": 41935.18 + "y": 60938.137 } ], - "name": "Tarantool (HASH, 1.6.4-510-g9d9f76d)", + "name": "Tarantool (HASH, 1.6.4-564-ge6e1429)", "type": "line" } ], diff --git a/doc/www/theme/static/docbook.css b/doc/www/theme/static/docbook.css deleted file mode 100644 index d2fe22e9eb230662f7f3b2c73d3ffb6d10e7577c..0000000000000000000000000000000000000000 --- a/doc/www/theme/static/docbook.css +++ /dev/null @@ -1,89 +0,0 @@ -.tntadmin { - font-family: monospace; - font-weight: bold; - text-transform: uppercase; - color: green; -} - -.lua { - font-family: monospace; - font-weight: bold; -} - -strong.hl-keyword { - color: green !important; - font-weight: bold; -} - -em.hl-comment { - color: #3366FF !important; - font-weight: normal; -} - -strong.hl-string em { - color: red !important; - font-weight: bold; -} - -body { - min-width: 768px; - max-width: 1024px; - margin: auto; -} - -.book { - margin: 2pt auto; - font-size: 100% -} - -.book h1 { - font-size: 150% -} - -pre { - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; - text-decoration: none; - outline: 0; - padding: 5px; - background-color: rgba(0,0,0,0.1); - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - box-shadow: 0 1px 3px rgba(0,0,0,0.3); -} - -div.toc dl{ - margin-top: 0px; -} - -div.itemizedlist ul li p{ - margin: 4px; -} - -div#header { - display: block; -} - -div#content { - border-top: 1px dotted black; -} - -div#headwrap { - width: 100%; -} - -div.column { - display: inline-block; -} - -div#headl { - float: left; - width: 30%; -} - -div#headr { - float: right; - width: 69%; - text-align: right -} diff --git a/doc/www/theme/static/old_global.css b/doc/www/theme/static/old_global.css deleted file mode 100644 index 781768112a00a318575533a63ef08f9e531d0b1a..0000000000000000000000000000000000000000 --- a/doc/www/theme/static/old_global.css +++ /dev/null @@ -1,355 +0,0 @@ -/* This stylesheet heavily borrows from http://necolas.github.com/normalize.css */ - -/* ============================================================================= - Base - ========================================================================== */ - -/* - * 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units - * http://clagnut.com/blog/348/#c790 - * 2. Keeps page centred in all browsers regardless of content height - * 3. Prevents iOS text size adjust after orientation change, without disabling user zoom - * www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ - */ - -html { - font-size: 100%; /* 1 */ - overflow-y: scroll; /* 2 */ - -webkit-text-size-adjust: 100%; /* 3 */ - -ms-text-size-adjust: 100%; /* 3 */ -} - -/* - * Addresses margins handled incorrectly in IE6/7 - */ - -body { - margin: 0; -} - -/* ============================================================================= - Typography - ========================================================================== */ - -/* - * Neutralise smaller font-size in 'section' and 'article' in FF4+, Chrome, S5 - */ - -h1 { - font-size: 1.5em; -} - -/* - * Addresses style set to 'bolder' in FF3+, S4/5, Chrome - */ - -b, strong { - font-weight: bold; -} - -blockquote { - margin: 1em 40px; -} - -/* - * Corrects font family set oddly in IE6, S4/5, Chrome - * en.wikipedia.org/wiki/User:Davidgothberg/Test59 - */ - -pre, code, kbd, samp { - font-family: monospace, serif; - _font-family: 'courier new', monospace; - font-size: 100%; -} - - -/* - * Improves readability of pre-formatted text in all browsers - */ - -pre { - white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; - text-decoration: none; - outline: 0; - background-color: rgba(0,0,0,0.1); - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - box-shadow: 0 1px 3px rgba(0,0,0,0.3); -} - -/* - * 1. Addresses CSS quotes not supported in IE6/7 - * 2. Addresses quote property not supported in S4 - */ - -/* 1 */ - -q { - quotes: none; -} - -/* 2 */ - -q:before, -q:after { - content: ''; - content: none; -} - -/* - * XXX - */ - -small { - font-size: 75%; -} - -/* - * Prevents sub and sup affecting line-height in all browsers - * gist.github.com/413930 - */ - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - - -/* ============================================================================= - Lists - ========================================================================== */ - -ul, ol { - margin-left: 0; - padding: 0 0 0 40px; -} - -dd { - margin: 0 0 0 40px; -} - - -/* ============================================================================= - Embedded content - ========================================================================== */ - -/* - * 1. Removes border when inside 'a' element in IE6/7/8/9, FF3 - * 2. Improves image quality when scaled in IE7 - * code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ - */ - -img { - border: 0; /* 1 */ - -ms-interpolation-mode: bicubic; /* 2 */ -} - -.ycsb { - width: 768px; -} - -/* ============================================================================= - Tables - ========================================================================== */ - -/* - * Remove most spacing between table cells - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -/* ========================================================================== - Grid - ======================================================================== */ - -.grid { - width: 768px; - overflow: hidden; - margin-left: auto; - margin-right: auto; - padding: 0 10px 0 0; - -moz-border-radius: 3px; - -webkit-border-radius: 3px; - border-radius: 3px; - clear: both; -} - -.span_1, .span_2, .span_3, .span_4, .span_5, .span_6, -.span_7, .span_8, .span_9, .span_10, .span_11, .span_12 { - float: left; - dsiplay: inline; /* IE workaround */ - margin-left: 10px; -} - -.span_1 { width: 70px; } -.span_2 { width: 150px; } -.span_3 { width: 230px; } -.span_4 { width: 303px; } -.span_5 { width: 390px; } -.span_6 { width: 470px; } -.span_7 { width: 550px; } -.span_8 { width: 630px; } -.span_9 { width: 710px; } -.span_10 { width: 790px; } -.span_11 { width: 870px; } -.span_12 { width: 950px; } - -.lpad_1 { padding-left: 80px; } -.lpad_2 { padding-left: 160px; } -.lpad_3 { padding-left: 240px; } -.lpad_4 { padding-left: 320px; } -.lpad_5 { padding-left: 400px; } -.lpad_6 { padding-left: 480px; } -.lpad_7 { padding-left: 560px; } -.lpad_8 { padding-left: 640px; } -.lpad_9 { padding-left: 720px; } -.lpad_10 { padding-left: 800px; } -.lpad_11 { padding-left: 880px; } - -.rpad_1 { padding-right: 80px; } -.rpad_2 { padding-right: 160px; } -.rpad_3 { padding-right: 240px; } -.rpad_4 { padding-right: 320px; } -.rpad_5 { padding-right: 400px; } -.rpad_6 { padding-right: 480px; } -.rpad_7 { padding-right: 560px; } -.rpad_8 { padding-right: 640px; } -.rpad_9 { padding-right: 720px; } -.rpad_10 { padding-right: 800px; } -.rpad_11 { padding-right: 880px; } - - -/* ============================================================================= - Custom styles - ========================================================================== */ - -html, body{ - width: 768px; - margin: auto; -} - -/* ============================================================================= - Styles for tabs and buttons used in benchmark*.html - ========================================================================== */ - -.b-schedule{ - height: 100%; - width: 768px; - margin:0 auto; - padding: 0; -} - -.header{ - font-size: 2em; - line-height: 1; - text-align: center; - margin: 40 auto; -} - -.b-tabs{ - height: 100%; -} -.b-tabs__list{ - padding: 0px; - list-style: none; - border: 1px solid #b2b2b2; - border-bottom: 0; - -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; - -webkit-user-select: none; - box-shadow: 0 2px 4px -3px #000; - -webkit-padding-start: 0; - background-color: #f5f5f5; - -webkit-padding-start: 0; - overflow: hidden; - margin: 0; -} -.b-tabs__li{ - float: left; - padding: 10px; - cursor: pointer; - border-right: 1px solid #b2b2b2; -} -.b-tabs__li:last-child{ - border-right: none; -} -.b-tabs__li_on, .b-tabs__li:active{ - background-color: #fafafa; - padding: 11px 9px 9px 11px; - color: #3f3f3f; -} -.b-tabs__body{ - position: relative; - padding: 20px; - height: 980px; - border: 2px solid black; -} -#picture1, #picture2{ - min-width: 400px; - margin: 0 auto; -} -.b-tabs__buttons{ - padding: 0; - right: 20px; - border: 2px solid #b2b2b2; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; - -webkit-user-select: none; - box-shadow: 0 2px 4px -3px #000; - -webkit-padding-start: 0; - background-color: #eaeaea; - outline: none; - cursor: pointer; - list-style: none; - float: right; -} -.b-button{ - float: left; - margin: 0; - padding: 3px; - border-right: 1px solid #b2b2b2; - font-size: medium; -} -.b-button:last-child{ - border: none; -} -.b-button_on, .b-button:active{ - background-color: #fafafa; - padding: 4px 2px 3px 4px; - color: #3f3f3f; -} - -h3 { - text-align:center; -} - -/* - * Disable current link in header, when we are on current page - */ - -body#tarantool.index #header #blurb h1 a.index, -body#tarantool.intro #header #blurb h3 a.intro, -body#tarantool.documentation #header #blurb h3 a.documentation, -body#tarantool.download #header #blurb h3 a.download, -body#tarantool.support #header #blurb h3 a.support { - pointer-events: none; - cursor: default; - text-decoration: none; -} diff --git a/doc/www/theme/static/old_header.css b/doc/www/theme/static/old_header.css deleted file mode 100644 index 22ad82701c83ce70185c6e4f121f5c4eedf46855..0000000000000000000000000000000000000000 --- a/doc/www/theme/static/old_header.css +++ /dev/null @@ -1,142 +0,0 @@ -#header, #content{ - background-color: #fff; -} - -#content { - padding-bottom: 5px; -} - -#blurb { - margin: 20px auto; -} - -#blurb h1 { - font-size: 2em; - line-height: 1; - text-align: center; - margin: 15px; -} - -#blurb h2 { - font-size: 1.2em; - font-weight: normal; - line-height: 1; - text-align: center; - margin: 5px; -} - -#blurb h3 { - text-align: center; - margin: 5px; -} - -/* =========================================================================== - Layout - ======================================================================== */ - -/* - * Top-level page sections: - * body > #header #content - */ - -#header, #content { - width: 100%; - margin: 0px auto; - padding: 0px; - overflow: hidden; -} - -#header { - margin-bottom: 5px; -} -/* - * http://sonspring.com/journal/clearing-floats - */ - -.clear { - clear: both; - display: block; - visibility: hidden; - width: 0; - height: 0; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -div.related li.center { - float: center; - margin-right: 5px; -} - - -/* ============================================================================= - Links - ========================================================================== */ -a { - color: #201e9e; -} - -/* - * Addresses outline displayed oddly in Chrome - */ - -a:focus { - outline: thin dotted; -} - -/* - * Improves readability when focused and also mouse hovered in all browsers - * people.opera.com/patrickl/experiments/keyboard/test - */ - -a:active { - outline: 0; -} - -a:hover { - outline: 0; - background-color: rgba(0,0,0,0.1); - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.3); - box-shadow: 0 1px 3px rgba(0,0,0,0.3); -} - -a.imglink:hover { - border : 0; - background-color: inherit; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -a:visited { - color: #3f3f3f; -} - -body { - margin-bottom: 100px; -} diff --git a/doc/www/theme/templates/documentation.html b/doc/www/theme/templates/documentation.html deleted file mode 100644 index 195d1dfc065532f34092d2d83761c204bf30a7ae..0000000000000000000000000000000000000000 --- a/doc/www/theme/templates/documentation.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "base" %} - -{% block header_scripts %} -{% endblock header_scripts %} - -{% block content %} -<section class="b-lightgray_block b-documentation_top b-clearbox"> - <div class="b-block-wrapper"> - <h2 class="b-section-title">Documentation</h2> - <!--div class="b-search"> - <input class="b-search-text" data-placeholder="Search in documentation" /> - <input class="b-search-but" type="submit" /> - </div--> - </div> -</section> - -<section class="b-block b-tcontents"> - <div class="b-block-wrapper"> - <ul class="b-tcontents-list"> - {% for item in page.blocks.sections %} - <li class="b-tcontents-list-item"> - <h2 class="b-tcontents-list-item-title">{{ item.name }}</h2> - <ul class="b-tcontents-sublist"> - {% for itemli in item.list %} - <li class="b-tcontents-sublist-item"> - <a href="{{ itemli.link }}">{{ itemli.name }}</a> - </li> - {% endfor %} - </ul> - </li> - {% endfor %} - </ul> - </div> -</section> -{% endblock content %} - -{# vim: syntax=htmldjango ts=2 sts=2 sw=2 expandtab #} diff --git a/doc/www/theme/templates/documentation_rst.html b/doc/www/theme/templates/documentation_rst.html deleted file mode 100644 index f7d4bab57b0ddac7d5922835dd10d0ce7dfcbde0..0000000000000000000000000000000000000000 --- a/doc/www/theme/templates/documentation_rst.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "base" %} - -{% block header_scripts %} -<script src="js/main.js"></script> -{% endblock header_scripts %} - -{% block content %} -<section class="b-lightgray_block b-documentation_top b-clearbox p-documentation_in"> - <div class="b-block-wrapper"> - <h2 class="b-section-title">Documentation</h2> - <!--div class="b-search"> - <input class="b-search-text" data-placeholder="Search in documentation" /> - <input class="b-search-but" type="submit" /> - </div--> - </div> -</section> - -<div class="b-cols_content b-clearbox"> - <!--div class="b-cols_content_left"> - <ul class="b-tcontents_full-list"> - <li class="b-tcontents_full-list-item p-active"> - <h2 class="b-tcontents_full-list-item-title"> - {# number #}<a href="{# link #}">{# name #}</a> - </h2> - <p class="b-tcontents_full-list-item-disc">{# text #}</p> - <ul class="b-tcontents_full-sublist"> - <li class="b-tcontents_full-sublist-item"> - {# number #}<a href="{# link #}">{# name #}</a> - </li> - </ul> - </li> - </ul> - </div--> - <div class="b-cols_content_left"> - </div> - <div class="b-cols_content_right"> - <div class="b-cols_content_right-slot"> - <article class="b-article"> - {{ page.content }} - </article> - </div> - </div> -</div> -{% endblock %} - -{# vim: syntax=htmldjango ts=2 sts=2 sw=2 expandtab #} diff --git a/doc/www/theme/templates/old_base b/doc/www/theme/templates/old_base deleted file mode 100644 index 1b814a03124e8927d5fb175328026fd0d9c9e571..0000000000000000000000000000000000000000 --- a/doc/www/theme/templates/old_base +++ /dev/null @@ -1,22 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> - <head> - <title>{{ title }}</title> - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> - <link rel="shortcut icon" href="/theme/favicon.ico" /> - {% if not documentation %} - <link rel="stylesheet" type="text/css" href="/theme/old_global.css" /> - <link rel="stylesheet" type="text/css" href="/theme/pygmentize.css" /> - {% endif %} - <link rel="stylesheet" type="text/css" href="/theme/old_header.css"> - {% include "script" ignore missing %} - </head> - <body id="tarantool" {% if page %} class ="{{ page.slug }}" {% endif %}> - <div id="content"> - {% block content %} - {% endblock content %} - </div> - </body> -</html> - -{# vim: syntax=htmldjango ts=2 sts=2 sw=2 expandtab #} diff --git a/doc/www/theme/templates/old_documentation.html b/doc/www/theme/templates/old_documentation.html deleted file mode 100644 index 7ee4830249d895f2356116bc2658080f10d00306..0000000000000000000000000000000000000000 --- a/doc/www/theme/templates/old_documentation.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "old_base" %} -{% set title = page.title %} -{% block content %} - {{ page.content }} -{% endblock content %} - -{# vim: syntax=htmldjango ts=2 sts=2 sw=2 expandtab #} diff --git a/doc/www/theme/templates/old_page.html b/doc/www/theme/templates/old_page.html deleted file mode 100644 index 2db3be222790859035b829517805b1b5fec96721..0000000000000000000000000000000000000000 --- a/doc/www/theme/templates/old_page.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "old_base" %} -{% set title = page.title %} -{% block content %} -<section id="content" class="body"> - {{ page.content }} -</section> -{% endblock %} - -{# vim: syntax=htmldjango ts=2 sts=2 sw=2 expandtab #} diff --git a/extra/dist/tarantoolctl b/extra/dist/tarantoolctl index 4275bf1c37f55f0ad63c0ffe88c9a6a23e6657b5..e79050ecba676c9bd08ee0d6ac70a46db2bdf882 100755 --- a/extra/dist/tarantoolctl +++ b/extra/dist/tarantoolctl @@ -106,9 +106,13 @@ local fiber = require 'fiber' ffi.cdef[[ int kill(int pid, int sig); ]] -local config_file = os.getenv('HOME') .. '/.config/tarantool/tarantool' +local config_file local usermode = true +if os.getenv('HOME') then + config_file = os.getenv('HOME') .. '/.config/tarantool/tarantool' +end + if not fio.stat(config_file) then usermode = false local config_list = { diff --git a/src/box/alter.cc b/src/box/alter.cc index a1785d78e3f46cda41b996e24328c347d585a108..5916372715391ae3a2094b920f1bd6ca28d4f207 100644 --- a/src/box/alter.cc +++ b/src/box/alter.cc @@ -1212,10 +1212,13 @@ user_def_create_from_tuple(struct user_def *user, struct tuple *tuple) */ if (tuple_field_count(tuple) > AUTH_MECH_LIST) { const char *auth_data = tuple_field(tuple, AUTH_MECH_LIST); - if (user->type == SC_ROLE && strlen(auth_data)) { - tnt_raise(ClientError, ER_CREATE_ROLE, user->name, - "authentication data can not be set for " - "a role"); + if (strlen(auth_data)) { + if (user->type == SC_ROLE) + tnt_raise(ClientError, ER_CREATE_ROLE, + user->name, "authentication " + "data can not be set for a role"); + if (user->uid == GUEST) + tnt_raise(ClientError, ER_GUEST_USER_PASSWORD); } user_def_fill_auth_data(user, auth_data); } diff --git a/src/box/errcode.h b/src/box/errcode.h index 29b950a262883db4f38062bba966fec2e13c8cfc..d8b679d2605cf1413e82ef3a63a61d0736498883 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -54,8 +54,8 @@ struct errcode_record { /* 0 */_(ER_UNKNOWN, 2, "Unknown error") \ /* 1 */_(ER_ILLEGAL_PARAMS, 2, "Illegal parameters, %s") \ /* 2 */_(ER_MEMORY_ISSUE, 1, "Failed to allocate %u bytes in %s for %s") \ - /* 3 */_(ER_TUPLE_FOUND, 2, "Duplicate key exists in unique index '%s'") \ - /* 4 */_(ER_TUPLE_NOT_FOUND, 2, "Tuple doesn't exist in index '%s'") \ + /* 3 */_(ER_TUPLE_FOUND, 2, "Duplicate key exists in unique index '%s' in space '%s'") \ + /* 4 */_(ER_TUPLE_NOT_FOUND, 2, "Tuple doesn't exist in index '%s' in space '%s'") \ /* 5 */_(ER_UNSUPPORTED, 2, "%s does not support %s") \ /* 6 */_(ER_NONMASTER, 2, "Can't modify data on a replication slave. My master is: %s") \ /* 7 */_(ER_READONLY, 2, "Can't modify data because this server in read-only mode.") \ @@ -145,8 +145,9 @@ struct errcode_record { /* 91 */_(ER_PRIV_NOT_GRANTED, 2, "User '%s' does not have %s access on %s '%s'") \ /* 92 */_(ER_ROLE_NOT_GRANTED, 2, "User '%s' does not have role '%s'") \ /* 93 */_(ER_MISSING_SNAPSHOT, 2, "Can't find snapshot") \ - /* 94 */_(ER_CANT_UPDATE_PRIMARY_KEY, 2, "Attempt to modify a tuple field which is part of index %s") \ + /* 94 */_(ER_CANT_UPDATE_PRIMARY_KEY, 2, "Attempt to modify a tuple field which is part of index '%s' in space '%s'") \ /* 95 */_(ER_UPDATE_INTEGER_OVERFLOW, 2, "Integer overflow when performing '%c' operation on field %u") \ + /* 96 */_(ER_GUEST_USER_PASSWORD, 2, "Setting password for guest user has no effect") \ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc index cc92cf7b75fbfe8de9d24636bd4a1fdb4ef12c24..c05f22006838961263074fe97a57f55738c09271 100644 --- a/src/box/lua/call.cc +++ b/src/box/lua/call.cc @@ -478,7 +478,7 @@ SetuidGuard::SetuidGuard(const char *name, uint32_t name_len, * No special check for ADMIN user is necessary * since ADMIN has universal access. */ - if (orig_credentials->universal_access & PRIV_ALL) + if ((orig_credentials->universal_access & PRIV_ALL) == PRIV_ALL) return; access &= ~orig_credentials->universal_access; /* diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index 3299532e59837f48890a7fb56708792a7fa660d0..54b09f82a181f00b3357a2f8142fb7fbac1615bd 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1005,6 +1005,7 @@ end box.schema.func = {} box.schema.func.create = function(name, opts) opts = opts or {} + check_param_table(opts, { setuid = 'boolean', if_not_exists = 'boolean' }) local _func = box.space[box.schema.FUNC_ID] local func = _func.index.name:get{name} if func then @@ -1013,16 +1014,32 @@ box.schema.func.create = function(name, opts) end return end - check_param_table(opts, { setuid = 'boolean', if_not_exists = 'boolean' }) opts = update_param_table(opts, { setuid = false }) opts.setuid = opts.setuid and 1 or 0 _func:auto_increment{session.uid(), name, opts.setuid} end -box.schema.func.drop = function(name) +box.schema.func.drop = function(name, opts) + opts = opts or {} + check_param_table(opts, { if_exists = 'boolean' }) local _func = box.space[box.schema.FUNC_ID] local _priv = box.space[box.schema.PRIV_ID] - local fid = object_resolve('function', name) + local fid + local tuple + if type(name) == 'string' then + tuple = _func.index.name:get{name} + else + tuple = _func:get{name} + end + if tuple then + fid = tuple[1] + end + if fid == nil then + if not opts.if_exists then + box.error(box.error.NO_SUCH_FUNCTION, name) + end + return + end local privs = _priv.index.object:select{'function', fid} for k, tuple in pairs(privs) do box.schema.user.revoke(tuple[2], tuple[5], tuple[3], tuple[4]) @@ -1103,10 +1120,15 @@ box.schema.user.exists = function(name) end end -box.schema.user.drop = function(name) +box.schema.user.drop = function(name, opts) + opts = opts or {} + check_param_table(opts, { if_exists = 'boolean' }) local uid = user_or_role_resolve(name) if uid == nil then - box.error(box.error.NO_SUCH_USER, name) + if not opts.if_exists then + box.error(box.error.NO_SUCH_USER, name) + end + return end -- recursive delete of user data local _priv = box.space[box.schema.PRIV_ID] @@ -1279,10 +1301,15 @@ box.schema.role.create = function(name, opts) _user:auto_increment{session.uid(), name, 'role'} end -box.schema.role.drop = function(name) +box.schema.role.drop = function(name, opts) + opts = opts or {} + check_param_table(opts, { if_exists = 'boolean' }) local uid = user_or_role_resolve(name) if uid == nil then - box.error(box.error.NO_SUCH_ROLE, name) + if not opts.if_exists then + box.error(box.error.NO_SUCH_ROLE, name) + end + return end return box.schema.user.drop(name) end diff --git a/src/box/memtx_hash.cc b/src/box/memtx_hash.cc index 4afad8dac1681834a15daa96bbbe37a917eb2e4a..93b7c63c658fc03fe83bbe273ef84301855cf7fa 100644 --- a/src/box/memtx_hash.cc +++ b/src/box/memtx_hash.cc @@ -30,6 +30,8 @@ #include "say.h" #include "tuple.h" #include "memtx_engine.h" +#include "space.h" +#include "schema.h" /* space_cache_find() */ #include "errinj.h" #include "third_party/PMurHash.h" @@ -294,7 +296,9 @@ MemtxHash::replace(struct tuple *old_tuple, struct tuple *new_tuple, "recover of int hash_table"); } } - tnt_raise(ClientError, errcode, index_name(this)); + struct space *sp = space_cache_find(key_def->space_id); + tnt_raise(ClientError, errcode, index_name(this), + space_name(sp)); } if (dup_tuple) diff --git a/src/box/memtx_tree.cc b/src/box/memtx_tree.cc index 528c156e0829462736dc0519e4c8caba116498e3..af0a95b2970a8b9860c3427b46fa822787cf37ae 100644 --- a/src/box/memtx_tree.cc +++ b/src/box/memtx_tree.cc @@ -29,6 +29,7 @@ #include "memtx_tree.h" #include "tuple.h" #include "space.h" +#include "schema.h" /* space_cache_find() */ #include "errinj.h" #include "memory.h" #include "fiber.h" @@ -250,7 +251,9 @@ MemtxTree::replace(struct tuple *old_tuple, struct tuple *new_tuple, bps_tree_index_delete(&tree, new_tuple); if (dup_tuple) bps_tree_index_insert(&tree, dup_tuple, 0); - tnt_raise(ClientError, errcode, index_name(this)); + struct space *sp = space_cache_find(key_def->space_id); + tnt_raise(ClientError, errcode, index_name(this), + space_name(sp)); } if (dup_tuple) return dup_tuple; diff --git a/src/box/sophia_index.cc b/src/box/sophia_index.cc index e7b47577c10c105d0e5f24447167cdd7996f5ca3..5bb10b2de896b5f00a7eb39b179366742d872b27 100644 --- a/src/box/sophia_index.cc +++ b/src/box/sophia_index.cc @@ -272,7 +272,10 @@ SophiaIndex::replace(struct tuple *old_tuple, struct tuple *new_tuple, error = 1; tuple_unref(dup_tuple); if (error) { - tnt_raise(ClientError, ER_TUPLE_FOUND, index_name(this)); + struct space *sp = + space_cache_find(key_def->space_id); + tnt_raise(ClientError, ER_TUPLE_FOUND, + index_name(this), space_name(sp)); } } } diff --git a/src/box/space.cc b/src/box/space.cc index 85777d1eb394860e670bc675c04382f96dd52391..261c455041bc68b150fe167cd33c362366e4f71e 100644 --- a/src/box/space.cc +++ b/src/box/space.cc @@ -202,7 +202,7 @@ space_check_update(struct space *space, Index *index = space->index[0]; if (tuple_compare(old_tuple, new_tuple, index->key_def)) tnt_raise(ClientError, ER_CANT_UPDATE_PRIMARY_KEY, - index_name(index)); + index_name(index), space_name(space)); } /* vim: set fm=marker */ diff --git a/src/coeio.cc b/src/coeio.cc index 36efb2b3191f8293df5dfdd8e25e54054e2e8b70..e265d62096f414db3486f3b0aceefdcecdfdf5f5 100644 --- a/src/coeio.cc +++ b/src/coeio.cc @@ -151,19 +151,19 @@ static int coeio_on_complete(eio_req *req) { /* - * Don't touch the task if the request is cancelled: - * the task is allocated on the caller's stack and - * may be already gone. Don't wakeup the caller - * if the task is cancelled: in this case the caller - * is already woken up, avoid double wake-up. + * If the request is cancelled, libeio doesn't + * invoke finish callback. Indeed, it can't do + * anything since its execution context has + * already been gone. */ - if (! EIO_CANCELLED(req)) { - struct coeio_task *task = (struct coeio_task *) req->data; - task->result = req->result; - task->errorno = req->errorno; - task->complete = 1; - fiber_wakeup(task->fiber); - } + assert(!EIO_CANCELLED(req)); + + struct coeio_task *task = (struct coeio_task *) req->data; + task->result = req->result; + task->errorno = req->errorno; + task->complete = 1; + fiber_wakeup(task->fiber); + return 0; } diff --git a/src/lua/fio.lua b/src/lua/fio.lua index 9f6b10d92fa7efefd86f443c2c1862829b144aa0..ee6d46bae1155914e2834bf7bdf0a89f6218815b 100644 --- a/src/lua/fio.lua +++ b/src/lua/fio.lua @@ -210,7 +210,7 @@ fio.dirname = function(path) return nil end path = tostring(path) - path = ffi.new('char[?]', #path, path) + path = ffi.new('char[?]', #path + 1, path) return ffi.string(ffi.C.dirname(path)) end diff --git a/src/util.cc b/src/util.cc index 0e2165f650e39cdb0492e1180e2f25b298b6ba1d..574f6c5b7aac97db14ec6b44041c0778c3c0c3db 100644 --- a/src/util.cc +++ b/src/util.cc @@ -364,7 +364,7 @@ abspath(const char *filename) if (filename[0] == '/') return strdup(filename); - char *abspath = (char *) malloc(PATH_MAX); + char *abspath = (char *) malloc(PATH_MAX + 1); if (abspath == NULL) return NULL; diff --git a/test/app/json.result b/test/app/json.result index fa5ebb50583ffbf7b8ceb2253bf35654a2c4aef1..1443f601815a6e535bdf7db203855b7e66129a4b 100644 --- a/test/app/json.result +++ b/test/app/json.result @@ -1,6 +1,6 @@ TAP version 13 # json -1..8 +1..9 # unsigned 1..56 ok - encode/decode for 0 @@ -184,4 +184,10 @@ ok - table ok - udata hook priority # ucdata: end ok - ucdata + # misc + 1..2 + ok - .NULL is cdata + ok - .NULL == nil + # misc: end +ok - misc # json: end diff --git a/test/app/json.test.lua b/test/app/json.test.lua index 07ade39f47efe940ff1089c661b7b628bd778173..3884b41e786dc8e52ddc46b9da126d34e51d7ae2 100755 --- a/test/app/json.test.lua +++ b/test/app/json.test.lua @@ -14,9 +14,15 @@ local function is_array(s) return string.sub(s, 1, 1) == "[" end +local function test_misc(test, s) + test:plan(2) + test:iscdata(s.NULL, 'void *', '.NULL is cdata') + test:ok(s.NULL == nil, '.NULL == nil') +end + tap.test("json", function(test) local serializer = require('json') - test:plan(8) + test:plan(9) test:test("unsigned", common.test_unsigned, serializer) test:test("signed", common.test_signed, serializer) test:test("double", common.test_double, serializer) @@ -25,4 +31,5 @@ tap.test("json", function(test) test:test("nil", common.test_nil, serializer) test:test("table", common.test_table, serializer, is_array, is_map) test:test("ucdata", common.test_ucdata, serializer) + test:test("misc", test_misc, serializer) end) diff --git a/test/big/hash.result b/test/big/hash.result index 9e3e9e7421c4cd9d3d94eb094995b1c7da3d2d79..d511bdc0773ae0a746072589a1f589b2c83829a5 100644 --- a/test/big/hash.result +++ b/test/big/hash.result @@ -538,7 +538,7 @@ hash.index['field3']:get{10} -- TupleFound (primary key) hash:insert{1, 10, 10, 10} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... hash.index['primary']:get{10} --- @@ -580,7 +580,7 @@ hash.index['field3']:get{10} -- TupleFound (key --1) hash:insert{10, 0, 10, 10} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... hash.index['primary']:get{10} --- @@ -627,7 +627,7 @@ hash.index['field1']:get{0} -- TupleFound (key --3) hash:insert{10, 10, 10, 0} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... hash.index['primary']:get{10} --- diff --git a/test/big/hash_multipart.result b/test/big/hash_multipart.result index 18545202e29dd5085c32cfe4296c86cdcc44d0fb..f70bb6a9f001d4206d73b74f0614a7d98c9e2024 100644 --- a/test/big/hash_multipart.result +++ b/test/big/hash_multipart.result @@ -46,7 +46,7 @@ hash:insert{1, 'bar', 1, '', 4} -- try to insert a row with a duplicate key hash:insert{1, 'bar', 1, '', 5} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... -- output all rows --# setopt delimiter ';' diff --git a/test/big/lua.result b/test/big/lua.result index d41273ab2ce11a7c09dc55d23094ecf96b234cbd..31b231e74366ae11caee99997d58216b3ac2425a 100644 --- a/test/big/lua.result +++ b/test/big/lua.result @@ -106,7 +106,7 @@ space:insert{'1', 'hello', 'world'} ... space:insert{'2', 'hello', 'world'} --- -- error: Duplicate key exists in unique index 'minmax' +- error: Duplicate key exists in unique index 'minmax' in space 'tweedledum' ... space:drop() --- diff --git a/test/big/tree_pk.result b/test/big/tree_pk.result index b4979a34ced6a26a68c8213425766fa33b0ea7c0..d75f06d5a05073dceee7e4759d0e868991538bef 100644 --- a/test/big/tree_pk.result +++ b/test/big/tree_pk.result @@ -364,7 +364,7 @@ s0.index['i3']:select{10} -- TupleFound (primary key) s0:insert{1, 10, 10, 10} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... s0.index['primary']:get{10} --- @@ -409,7 +409,7 @@ s0.index['i3']:select{10} -- TupleFound (key #1) s0:insert{10, 0, 10, 10} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... s0.index['primary']:get{10} --- @@ -434,7 +434,7 @@ s0.index['i1']:select{0} -- TupleFound (key #1) s0:replace{2, 0, 10, 10} --- -- error: Duplicate key exists in unique index 'i1' +- error: Duplicate key exists in unique index 'i1' in space 'tweedledum' ... s0.index['primary']:get{10} --- @@ -459,7 +459,7 @@ s0.index['i1']:select{0} -- TupleFound (key #3) s0:insert{10, 10, 10, 0} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... s0.index['primary']:get{10} --- @@ -484,7 +484,7 @@ s0.index['i3']:select{0} -- TupleFound (key #3) s0:replace{2, 10, 10, 0} --- -- error: Duplicate key exists in unique index 'i1' +- error: Duplicate key exists in unique index 'i1' in space 'tweedledum' ... s0.index['primary']:get{10} --- diff --git a/test/big/tree_pk_multipart.result b/test/big/tree_pk_multipart.result index ab094e3899251d34fc3b2ccb7c2bec6b1c72ef29..f91db4f383f898401dd8e7b6c2681f36fcd7c40d 100644 --- a/test/big/tree_pk_multipart.result +++ b/test/big/tree_pk_multipart.result @@ -269,7 +269,8 @@ space:delete{'Vincent', 'The Wolf!', 0} ... space:update({'Vincent', 'The Wolf!', 1}, {{ '=', 1, 'Updated' }, {'=', 5, 'New'}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + 'tweedledum' ... space:update({'Updated', 'The Wolf!', 1}, {{ '=', 1, 'Vincent'}, { '#', 5, 1 }}) --- diff --git a/test/box/access.result b/test/box/access.result index 28d22005a549533843e6f30ae681023780a6721e..0e984bf7c31a101d653db9ddf36b66b938c2faac 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -649,3 +649,26 @@ box.schema.func.create('dummy', { if_not_exists = true }) box.schema.func.drop('dummy') --- ... +-- gh-664 roles: accepting bad syntax for create +box.schema.user.create('user', 'blah') +--- +- error: Illegal parameters, options should be a table +... +box.schema.user.drop('user', 'blah') +--- +- error: Illegal parameters, options should be a table +... +-- gh-664 roles: accepting bad syntax for create +box.schema.func.create('func', 'blah') +--- +- error: Illegal parameters, options should be a table +... +box.schema.func.drop('blah', 'blah') +--- +- error: Illegal parameters, options should be a table +... +-- gh-758 attempt to set password for user guest +box.schema.user.passwd('guest', 'sesame') +--- +- error: Setting password for guest user has no effect +... diff --git a/test/box/access.test.lua b/test/box/access.test.lua index ec0e5193d63e13767fbf34a9920f0ea298db47ee..8d7b0d1658025df57b662b02a5746300a759783a 100644 --- a/test/box/access.test.lua +++ b/test/box/access.test.lua @@ -253,3 +253,13 @@ box.schema.user.revoke('guest', 'read,write,execute', 'universe', '', { if_exist box.schema.func.create('dummy', { if_not_exists = true }) box.schema.func.create('dummy', { if_not_exists = true }) box.schema.func.drop('dummy') + +-- gh-664 roles: accepting bad syntax for create +box.schema.user.create('user', 'blah') +box.schema.user.drop('user', 'blah') + +-- gh-664 roles: accepting bad syntax for create +box.schema.func.create('func', 'blah') +box.schema.func.drop('blah', 'blah') +-- gh-758 attempt to set password for user guest +box.schema.user.passwd('guest', 'sesame') diff --git a/test/box/access_bin.result b/test/box/access_bin.result index 850c0c0c073f1de6d099379ae04dceb040da4f0e..3dfc0a4172f2c2d39c78a7c71421093b6e27830b 100644 --- a/test/box/access_bin.result +++ b/test/box/access_bin.result @@ -285,3 +285,47 @@ box.schema.user.drop('test') test:drop() --- ... +-- +-- gh-508 - wrong check for universal access of setuid functions +-- +-- notice that guest can execute stuff, but can't read space _func +box.schema.user.grant('guest', 'execute', 'universe') +--- +... +function f1() return box.space._func:get(1)[4] end +--- +... +function f2() return box.space._func:get(2)[4] end +--- +... +box.schema.func.create('f1') +--- +... +box.schema.func.create('f2',{setuid=true}) +--- +... +c = net.new(box.cfg.listen) +--- +... +-- should return access denied +c:call('f1') +--- +- error: Read access denied for user 'guest' to space '_func' +... +-- should work (used to return access denied, because was not setuid +c:call('f2') +--- +- - [0] +... +c:close() +--- +... +box.schema.user.revoke('guest', 'execute', 'universe') +--- +... +box.schema.func.drop('f1') +--- +... +box.schema.func.drop('f2') +--- +... diff --git a/test/box/access_bin.test.lua b/test/box/access_bin.test.lua index be54595ba650025554452babe3d2b3cc544dd1ec..24019668e175e3a9f5fd4bbd9b7669303b7609b1 100644 --- a/test/box/access_bin.test.lua +++ b/test/box/access_bin.test.lua @@ -106,3 +106,21 @@ box.session.su('admin') c:close() box.schema.user.drop('test') test:drop() +-- +-- gh-508 - wrong check for universal access of setuid functions +-- +-- notice that guest can execute stuff, but can't read space _func +box.schema.user.grant('guest', 'execute', 'universe') +function f1() return box.space._func:get(1)[4] end +function f2() return box.space._func:get(2)[4] end +box.schema.func.create('f1') +box.schema.func.create('f2',{setuid=true}) +c = net.new(box.cfg.listen) +-- should return access denied +c:call('f1') +-- should work (used to return access denied, because was not setuid +c:call('f2') +c:close() +box.schema.user.revoke('guest', 'execute', 'universe') +box.schema.func.drop('f1') +box.schema.func.drop('f2') diff --git a/test/box/alter.result b/test/box/alter.result index e2a3ad5b6ee95110e41214dec2f6c6646f1e5f9a..67d91e2887797b7746b5a891a86e9fba75d7e781 100644 --- a/test/box/alter.result +++ b/test/box/alter.result @@ -13,7 +13,7 @@ ADMIN = 1 -- _space:insert{_space.id, ADMIN, 'test', 5 } --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... -- -- Bad space id @@ -27,14 +27,14 @@ _space:insert{'hello', 'world', 'test'} -- _space:insert{_space.id, ADMIN, 'test', 'world'} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... -- -- There is already a tuple for the system space -- _space:insert{_space.id, ADMIN, '_space', 'memtx', 0} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... _space:replace{_space.id, ADMIN, '_space', 'memtx', 0} --- @@ -42,7 +42,7 @@ _space:replace{_space.id, ADMIN, '_space', 'memtx', 0} ... _space:insert{_index.id, ADMIN, '_index', 'memtx', 0} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... _space:replace{_index.id, ADMIN, '_index', 'memtx', 0} --- @@ -71,11 +71,13 @@ _space:delete{_index.id} -- _space:update({_space.id}, {{'+', 1, 1}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + '_space' ... _space:update({_space.id}, {{'+', 1, 2}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + '_space' ... -- -- Create a space @@ -138,7 +140,7 @@ space:replace{0} ... _index:insert{_space.id, 0, 'primary', 'tree', 1, 1, 0, 'num'} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_index' ... _index:replace{_space.id, 0, 'primary', 'tree', 1, 1, 0, 'num'} --- @@ -146,7 +148,7 @@ _index:replace{_space.id, 0, 'primary', 'tree', 1, 1, 0, 'num'} ... _index:insert{_index.id, 0, 'primary', 'tree', 1, 2, 0, 'num', 1, 'num'} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_index' ... _index:replace{_index.id, 0, 'primary', 'tree', 1, 2, 0, 'num', 1, 'num'} --- @@ -323,7 +325,7 @@ auto = box.schema.space.create('auto_original') ... auto2 = box.schema.space.create('auto', {id = auto.id}) --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... box.schema.space.drop('auto') --- diff --git a/test/box/alter_limits.result b/test/box/alter_limits.result index 3ba3ff295fa034499f5102db496bc4c155acc12a..e38eaac1c153bb2d04112b58206e97ef89c7aa3f 100644 --- a/test/box/alter_limits.result +++ b/test/box/alter_limits.result @@ -84,7 +84,7 @@ s.id -- duplicate id box.schema.space.create('tweedledee', { id = 3000 }) --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space '_space' ... -- stupid space id box.schema.space.create('tweedledee', { id = 'tweedledee' }) @@ -681,7 +681,7 @@ index = s:create_index('third', { type = 'hash', parts = { 3, 'num' } }) ... s.index.third:rename('second') --- -- error: Duplicate key exists in unique index 'name' +- error: Duplicate key exists in unique index 'name' in space '_index' ... s.index.third.id --- @@ -762,12 +762,12 @@ s.index.primary:select{} -- a duplicate in the created index index = s:create_index('nodups', { type = 'tree', unique=true, parts = { 2, 'num'} }) --- -- error: Duplicate key exists in unique index 'nodups' +- error: Duplicate key exists in unique index 'nodups' in space 'full' ... -- change of non-unique index to unique: same effect s.index.year:alter({unique=true}) --- -- error: Duplicate key exists in unique index 'year' +- error: Duplicate key exists in unique index 'year' in space 'full' ... s.index.primary:select{} --- @@ -844,7 +844,7 @@ s:insert{2, 1} ... s.index.secondary:alter{ unique = true } --- -- error: Duplicate key exists in unique index 'secondary' +- error: Duplicate key exists in unique index 'secondary' in space 'test' ... s:delete{2} --- @@ -855,7 +855,7 @@ s.index.secondary:alter{ unique = true } ... s:insert{2, 1} --- -- error: Duplicate key exists in unique index 'secondary' +- error: Duplicate key exists in unique index 'secondary' in space 'test' ... s:insert{2, 2} --- diff --git a/test/box/call.result b/test/box/call.result index 70928be52241af11dc485180a16a0ed46ab3f95a..42b24ee3b735953b2b9bc1f55aa6479043d1a777 100644 --- a/test/box/call.result +++ b/test/box/call.result @@ -4,7 +4,10 @@ box.schema.user.create('test', { password = 'test' }) box.schema.user.grant('test', 'execute,read,write', 'universe') --- ... -function f1() return 'testing', 1, false, -1, 1.123, 1e123, nil end +exp_notation = 1e123 +--- +... +function f1() return 'testing', 1, false, -1, 1.123, math.abs(exp_notation - 1e123) < 0.1, nil end --- ... f1() @@ -14,7 +17,7 @@ f1() - false - -1 - 1.123 -- 1e+123 +- true - null ... call f1() @@ -24,7 +27,7 @@ call f1() - [False] - [-1] - [1.123] -- [1e+123] +- [True] - [None] ... f1=nil @@ -324,11 +327,12 @@ call myinsert(3, 'old', 2) --- - error: errcode: ER_TUPLE_FOUND - errmsg: Duplicate key exists in unique index 'primary' + errmsg: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... space:update({3}, {{'=', 1, 4}, {'=', 2, 'new'}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + 'tweedledum' ... space:insert(space:get{3}:update{{'=', 1, 4}, {'=', 2, 'new'}}) space:delete{3} --- diff --git a/test/box/call.test.py b/test/box/call.test.py index 7d64899a6a11d196bf2499ca89bc7f76d1b6fa36..a73fec928eff2d87d4cd003fbf9bc397af3ce10f 100644 --- a/test/box/call.test.py +++ b/test/box/call.test.py @@ -4,7 +4,9 @@ import sys admin("box.schema.user.create('test', { password = 'test' })") admin("box.schema.user.grant('test', 'execute,read,write', 'universe')") sql.authenticate('test', 'test') -admin("function f1() return 'testing', 1, false, -1, 1.123, 1e123, nil end") +# workaround for gh-770 centos 6 float representation +admin('exp_notation = 1e123') +admin("function f1() return 'testing', 1, false, -1, 1.123, math.abs(exp_notation - 1e123) < 0.1, nil end") admin("f1()") sql("call f1()") admin("f1=nil") diff --git a/test/box/fiber.result b/test/box/fiber.result index 1116fd5e651be7cc6a1726eb04ce6d0782b2b6de..d86c51ba5046a04da565fb3bb3468b6f76315a8a 100644 --- a/test/box/fiber.result +++ b/test/box/fiber.result @@ -141,7 +141,7 @@ space:insert{1953719668, 'old', 1684234849} -- test that insert produces a duplicate key error space:insert{1953719668, 'old', 1684234849} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'tweedledum' ... space:update(1953719668, {{'=', 1, 1953719668}, {'=', 2, 'new'}}) --- diff --git a/test/box/misc.result b/test/box/misc.result index 0fe4994e168993ed3443eecb01de82a0155ed1ca..8b9c75937e307c040fe36703a5bd7f15b84af4fd 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -204,6 +204,7 @@ t; - 'box.error.MODIFY_INDEX : 14' - 'box.error.PASSWORD_MISMATCH : 47' - 'box.error.NO_SUCH_ENGINE : 57' + - 'box.error.FIELD_TYPE : 23' - 'box.error.ACCESS_DENIED : 42' - 'box.error.UPDATE_INTEGER_OVERFLOW : 95' - 'box.error.LAST_DROP : 15' @@ -232,7 +233,7 @@ t; - 'box.error.ALTER_SPACE : 12' - 'box.error.ACTIVE_TRANSACTION : 79' - 'box.error.NO_CONNECTION : 77' - - 'box.error.FIELD_TYPE : 23' + - 'box.error.GUEST_USER_PASSWORD : 96' - 'box.error.INVALID_XLOG_NAME : 75' - 'box.error.INVALID_XLOG : 74' - 'box.error.REPLICA_MAX : 73' @@ -295,7 +296,7 @@ pcall(myinsert, {1, 'hello'}) pcall(myinsert, {1, 'hello'}) --- - false -- Duplicate key exists in unique index 'primary' +- Duplicate key exists in unique index 'primary' in space 'tweedledum' ... box.space.tweedledum:truncate() --- diff --git a/test/box/net.box.result b/test/box/net.box.result index 7fb11049c6be505dbbc1ec774ad1a2237639fd91..7c66df2f3502f4aea92082c00d474b99f06858a6 100644 --- a/test/box/net.box.result +++ b/test/box/net.box.result @@ -228,7 +228,7 @@ cn.space.net_box_test_space:insert{234, 1,2,3} ... cn.space.net_box_test_space:insert{234, 1,2,3} --- -- error: Duplicate key exists in unique index 'primary' +- error: Duplicate key exists in unique index 'primary' in space 'net_box_test_space' ... cn.space.net_box_test_space.insert{234, 1,2,3} --- diff --git a/test/box/role.result b/test/box/role.result index f11af5c62afda24a603a9ed907fe61c3dac45d0a..4129c5635728a1a46e1b0dc3f87de123c3e7f2db 100644 --- a/test/box/role.result +++ b/test/box/role.result @@ -816,6 +816,10 @@ box.schema.user.create('test', { if_not_exists = true}) ... box.schema.role.drop('test', { if_not_exists = true}) --- +- error: Illegal parameters, options parameter 'if_not_exists' is unexpected +... +box.schema.role.drop('test', { if_exists = true}) +--- ... box.schema.role.create('test', { if_not_exists = true}) --- @@ -825,4 +829,17 @@ box.schema.role.create('test', { if_not_exists = true}) ... box.schema.user.drop('test', { if_not_exists = true}) --- +- error: Illegal parameters, options parameter 'if_not_exists' is unexpected +... +-- gh-664 roles: accepting bad syntax for create +box.schema.role.create('role', 'role') +--- +- error: Illegal parameters, options should be a table +... +box.schema.role.drop('role', 'role') +--- +- error: Illegal parameters, options should be a table +... +box.schema.user.drop('test', { if_exists = true}) +--- ... diff --git a/test/box/role.test.lua b/test/box/role.test.lua index 6d3014edd5037b266be4809dedf0fdd9424a2b48..42e867aac186f13262ec36db3a166a809699f0ad 100644 --- a/test/box/role.test.lua +++ b/test/box/role.test.lua @@ -323,6 +323,11 @@ box.schema.user.create('guest', { if_not_exists = true}) box.schema.user.create('test', { if_not_exists = true}) box.schema.user.create('test', { if_not_exists = true}) box.schema.role.drop('test', { if_not_exists = true}) +box.schema.role.drop('test', { if_exists = true}) box.schema.role.create('test', { if_not_exists = true}) box.schema.role.create('test', { if_not_exists = true}) box.schema.user.drop('test', { if_not_exists = true}) +-- gh-664 roles: accepting bad syntax for create +box.schema.role.create('role', 'role') +box.schema.role.drop('role', 'role') +box.schema.user.drop('test', { if_exists = true}) diff --git a/test/box/update.result b/test/box/update.result index 2262ba7a72ca62a8b6ccda7dff361bc6e76a2634..aab2c05663ca6f3bf2fdd5965ae6168fc57a26df 100644 --- a/test/box/update.result +++ b/test/box/update.result @@ -11,7 +11,7 @@ s:insert{1000001, 1000002, 1000003, 1000004, 1000005} ... s:update({1000001}, {{'#', 1, 1}}) --- -- error: Attempt to modify a tuple field which is part of index pk +- error: Attempt to modify a tuple field which is part of index 'pk' in space 'tweedledum' ... s:truncate() --- @@ -142,7 +142,7 @@ s:update({1}, {{'=', 2, 'set tuple'}, {'!', 2, 'inserted tuple'}, {'#', 3, 1}}) ... s:update({1}, {{'!', 1, 3}, {'!', 1, 2}}) --- -- error: Attempt to modify a tuple field which is part of index pk +- error: Attempt to modify a tuple field which is part of index 'pk' in space 'tweedledum' ... s:truncate() --- diff --git a/test/replication/cluster.result b/test/replication/cluster.result index cd477fdb75a4ec8f1405c33c984bfae4363e2dec..466fd24f2d6ad9b4dc324cce851ca4c9042d7e89 100644 --- a/test/replication/cluster.result +++ b/test/replication/cluster.result @@ -142,7 +142,8 @@ box.info.vclock[10] ... box.space._cluster:update(10, {{'=', 1, 11}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + '_cluster' ... box.info.server.id --- diff --git a/test/replication/hot_standby.result b/test/replication/hot_standby.result index 69ba5bc477babdf195774f07b2812c7e549eb7d6..b6ccad365c19f65802c7ad5128e42a3bb272c36e 100644 --- a/test/replication/hot_standby.result +++ b/test/replication/hot_standby.result @@ -2,6 +2,12 @@ box.schema.user.grant('guest', 'replication') --- ... +box.schema.func.create('_set_pri_lsn') +--- +... +box.schema.user.grant('guest', 'execute', 'function', '_set_pri_lsn') +--- +... --# create server hot_standby with script='replication/hot_standby.lua', rpl_master=default --# create server replica with rpl_master=default, script='replication/replica.lua' --# start server hot_standby diff --git a/test/replication/hot_standby.test.lua b/test/replication/hot_standby.test.lua index e5865acc8e3bf43609af30cba1062ec9be605b67..68a5a6a4322f9e30e55071a03949bd176edd90c8 100644 --- a/test/replication/hot_standby.test.lua +++ b/test/replication/hot_standby.test.lua @@ -1,5 +1,7 @@ --# set connection default box.schema.user.grant('guest', 'replication') +box.schema.func.create('_set_pri_lsn') +box.schema.user.grant('guest', 'execute', 'function', '_set_pri_lsn') --# create server hot_standby with script='replication/hot_standby.lua', rpl_master=default --# create server replica with rpl_master=default, script='replication/replica.lua' --# start server hot_standby diff --git a/test/sophia/gh.result b/test/sophia/gh.result index cbe6fa5d15900340ae29338bb207f548c769cc54..0f91fd492e5a07289e5a33bcd9c1b70eb37ff606 100644 --- a/test/sophia/gh.result +++ b/test/sophia/gh.result @@ -153,7 +153,8 @@ s:insert{1,'X'} ... s:update({'X'}, {{'=', 2, 'Y'}}) --- -- error: Attempt to modify a tuple field which is part of index primary +- error: Attempt to modify a tuple field which is part of index 'primary' in space + 'tester' ... s:select{'X'} --- diff --git a/third_party/coro/coro.h b/third_party/coro/coro.h index 779d800b4af6ce4729a366156a58c63ac54a48e4..481a3b61684f4383f454bc5eb1b1dcb7bd1f8091 100644 --- a/third_party/coro/coro.h +++ b/third_party/coro/coro.h @@ -299,7 +299,7 @@ void coro_stack_free (struct coro_stack *stack); && !defined CORO_SJLJ && !defined CORO_LINUX \ && !defined CORO_IRIX && !defined CORO_ASM \ && !defined CORO_PTHREAD && !defined CORO_FIBER -# if defined WINDOWS && (defined __i386 || (__x86_64 || defined _M_IX86 || defined _M_AMD64) +# if defined WINDOWS && (defined __i386 || __x86_64 || defined _M_IX86 || defined _M_AMD64) # define CORO_ASM 1 # elif defined WINDOWS || defined _WIN32 # define CORO_LOSER 1 /* you don't win with windoze */ diff --git a/third_party/libeio/CVS/Entries b/third_party/libeio/CVS/Entries index b19391afe22a6fc0cc06f9cc981b172370da8a57..df3b2e43405d418ef93891b6f3c5553d3eb04ea6 100644 --- a/third_party/libeio/CVS/Entries +++ b/third_party/libeio/CVS/Entries @@ -1,14 +1,15 @@ -/Changes/1.51/Tue Aug 14 04:15:34 2012// -/LICENSE/1.1/Sat May 17 12:32:11 2008// -/Makefile.am/1.3/Fri Jun 10 12:46:20 2011// -/autogen.sh/1.4/Mon May 30 15:27:30 2011// -/configure.ac/1.10/Wed Jun 29 14:52:22 2011// -/demo.c/1.4/Mon Nov 29 12:38:32 2010// -/ecb.h/1.16/Tue Oct 9 04:53:53 2012// -/eio.3/1.1/Sun May 11 13:05:10 2008// -/eio.c/1.124/Thu Oct 11 05:01:56 2012// -/eio.h/1.52/Tue Aug 14 04:15:35 2012// -/eio.pod/1.30/Wed Jan 11 05:13:22 2012// -/libeio.m4/1.22/Tue Nov 13 20:14:57 2012// -/xthread.h/1.16/Thu Oct 11 03:20:52 2012// +/Changes/1.53/Tue Apr 7 16:19:34 2015// +/LICENSE/1.1/Tue Nov 18 10:15:55 2014// +/Makefile.am/1.4/Tue Apr 7 16:19:34 2015// +/autogen.sh/1.4/Tue Nov 18 10:15:55 2014// +/configure.ac/1.10/Tue Nov 18 10:15:55 2014// +/demo.c/1.4/Tue Nov 18 10:15:55 2014// +/ecb.h/1.23/Tue Apr 7 16:19:34 2015// +/eio.3/1.1/Tue Nov 18 10:15:55 2014// +/eio.c/1.132/Result of merge// +/eio.h/1.54/Tue Apr 7 16:19:34 2015// +/eio.pod/1.35/Tue Apr 7 16:19:34 2015// +/libeio.m4/1.22/Tue Nov 18 10:15:55 2014// +/xthread.h/1.17/Result of merge// +/etp.c/1.2/Mon Aug 18 04:26:03 2014// D diff --git a/third_party/libeio/CVS/Template b/third_party/libeio/CVS/Template deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/third_party/libeio/Changes b/third_party/libeio/Changes index 711baf5ea578942c061e17a124ad9db053c083a2..eed266e2fda0d1344fdf84942c9fc6718a644a4b 100644 --- a/third_party/libeio/Changes +++ b/third_party/libeio/Changes @@ -8,6 +8,7 @@ TODO: fadvise request TODO: fdopendir/utimensat TODO: maybe work around 3.996gb barrier in pread/pwrite as well, maybe readahead etc.? 1.0 + - for simple request api, initialise result/errorno to -1/ECANCELED. - fix a deadlock where a wakeup signal could be missed when a timeout occured at the same time. - use nonstandard but maybe-working-on-bsd fork technique. @@ -73,4 +74,5 @@ TODO: maybe work around 3.996gb barrier in pread/pwrite as well, maybe readahead - remove pread/pwrite emulation, as the only system that lacked them (cygwin) provides them for a while now. - provide pread/pwrite implementations for win32. + - implement aio_realpath for windows. diff --git a/third_party/libeio/Makefile.am b/third_party/libeio/Makefile.am index e9866c0d5e7c33d45c3239a916aaff1df1f80e48..568f824b5741be017dfdae0b3cd791fed81c5b90 100644 --- a/third_party/libeio/Makefile.am +++ b/third_party/libeio/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies VERSION_INFO = 1:0 -EXTRA_DIST = LICENSE Changes autogen.sh +EXTRA_DIST = LICENSE Changes autogen.sh etp.c #man_MANS = ev.3 diff --git a/third_party/libeio/ecb.h b/third_party/libeio/ecb.h index 81879d7014aa3d15c3d98ca81aa25349ab48002a..2348b6a243799d397e8eb070fedb4b9161880236 100644 --- a/third_party/libeio/ecb.h +++ b/third_party/libeio/ecb.h @@ -1,7 +1,7 @@ /* * libecb - http://software.schmorp.de/pkg/libecb * - * Copyright (©) 2009-2012 Marc Alexander Lehmann <libecb@schmorp.de> + * Copyright (©) 2009-2015 Marc Alexander Lehmann <libecb@schmorp.de> * Copyright (©) 2011 Emanuele Giaquinta * All rights reserved. * @@ -25,13 +25,24 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. */ #ifndef ECB_H #define ECB_H /* 16 bits major, 16 bits minor */ -#define ECB_VERSION 0x00010002 +#define ECB_VERSION 0x00010004 #ifdef _WIN32 typedef signed char int8_t; @@ -65,6 +76,15 @@ #endif #endif +/* work around x32 idiocy by defining proper macros */ +#if __amd64 || __x86_64 || _M_AMD64 || _M_X64 + #if _ILP32 + #define ECB_AMD64_X32 1 + #else + #define ECB_AMD64 1 + #endif +#endif + /* many compilers define _GNUC_ to some versions but then only implement * what their idiot authors think are the "more important" extensions, * causing enormous grief in return for some better fake benchmark numbers. @@ -72,20 +92,40 @@ * we try to detect these and simply assume they are not gcc - if they have * an issue with that they should have done it right in the first place. */ -#ifndef ECB_GCC_VERSION - #if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__ - #define ECB_GCC_VERSION(major,minor) 0 - #else - #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) - #endif +#if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__ + #define ECB_GCC_VERSION(major,minor) 0 +#else + #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +#endif + +#define ECB_CLANG_VERSION(major,minor) (__clang_major__ > (major) || (__clang_major__ == (major) && __clang_minor__ >= (minor))) + +#if __clang__ && defined __has_builtin + #define ECB_CLANG_BUILTIN(x) __has_builtin (x) +#else + #define ECB_CLANG_BUILTIN(x) 0 +#endif + +#if __clang__ && defined __has_extension + #define ECB_CLANG_EXTENSION(x) __has_extension (x) +#else + #define ECB_CLANG_EXTENSION(x) 0 #endif -#define ECB_C (__STDC__+0) /* this assumes that __STDC__ is either empty or a number */ -#define ECB_C99 (__STDC_VERSION__ >= 199901L) -#define ECB_C11 (__STDC_VERSION__ >= 201112L) #define ECB_CPP (__cplusplus+0) #define ECB_CPP11 (__cplusplus >= 201103L) +#if ECB_CPP + #define ECB_C 0 + #define ECB_STDC_VERSION 0 +#else + #define ECB_C 1 + #define ECB_STDC_VERSION __STDC_VERSION__ +#endif + +#define ECB_C99 (ECB_STDC_VERSION >= 199901L) +#define ECB_C11 (ECB_STDC_VERSION >= 201112L) + #if ECB_CPP #define ECB_EXTERN_C extern "C" #define ECB_EXTERN_C_BEG ECB_EXTERN_C { @@ -127,14 +167,18 @@ #elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \ || defined __ARM_ARCH_7M__ || defined __ARM_ARCH_7R__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory") - #elif __sparc || __sparc__ + #elif __aarch64__ + #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory") + #elif (__sparc || __sparc__) && !__sparcv8 #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory") #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore") #elif defined __s390__ || defined __s390x__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("bcr 15,0" : : : "memory") #elif defined __mips__ - #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory") + /* GNU/Linux emulates sync on mips1 architectures, so we force its use */ + /* anybody else who still uses mips1 is supposed to send in their version, with detection code. */ + #define ECB_MEMORY_FENCE __asm__ __volatile__ (".set mips2; sync; .set mips0" : : : "memory") #elif defined __alpha__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mb" : : : "memory") #elif defined __hppa__ @@ -142,6 +186,12 @@ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("") #elif defined __ia64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mf" : : : "memory") + #elif defined __m68k__ + #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory") + #elif defined __m88k__ + #define ECB_MEMORY_FENCE __asm__ __volatile__ ("tb1 0,%%r0,128" : : : "memory") + #elif defined __sh__ + #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory") #endif #endif #endif @@ -150,18 +200,23 @@ #if ECB_GCC_VERSION(4,7) /* see comment below (stdatomic.h) about the C11 memory model. */ #define ECB_MEMORY_FENCE __atomic_thread_fence (__ATOMIC_SEQ_CST) + #define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence (__ATOMIC_ACQUIRE) + #define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence (__ATOMIC_RELEASE) - /* The __has_feature syntax from clang is so misdesigned that we cannot use it - * without risking compile time errors with other compilers. We *could* - * define our own ecb_clang_has_feature, but I just can't be bothered to work - * around this shit time and again. - * #elif defined __clang && __has_feature (cxx_atomic) - * // see comment below (stdatomic.h) about the C11 memory model. - * #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST) - */ + #elif ECB_CLANG_EXTENSION(c_atomic) + /* see comment below (stdatomic.h) about the C11 memory model. */ + #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST) + #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE) + #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE) #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__ #define ECB_MEMORY_FENCE __sync_synchronize () + #elif _MSC_VER >= 1500 /* VC++ 2008 */ + /* apparently, microsoft broke all the memory barrier stuff in Visual Studio 2008... */ + #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier) + #define ECB_MEMORY_FENCE _ReadWriteBarrier (); MemoryBarrier() + #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier (); MemoryBarrier() /* according to msdn, _ReadBarrier is not a load fence */ + #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier (); MemoryBarrier() #elif _MSC_VER >= 1400 /* VC++ 2005 */ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier) #define ECB_MEMORY_FENCE _ReadWriteBarrier () @@ -191,6 +246,8 @@ /* for most usages, or gcc and clang have a bug */ /* I *currently* lean towards the latter, and inefficiently implement */ /* all three of ecb's fences as a seq_cst fence */ + /* Update, gcc-4.8 generates mfence for all c++ fences, but nothing */ + /* for all __atomic_thread_fence's except seq_cst */ #define ECB_MEMORY_FENCE atomic_thread_fence (memory_order_seq_cst) #endif #endif @@ -223,7 +280,7 @@ /*****************************************************************************/ -#if __cplusplus +#if ECB_CPP #define ecb_inline static inline #elif ECB_GCC_VERSION(2,5) #define ecb_inline static __inline__ @@ -250,23 +307,47 @@ typedef int ecb_bool; #define ecb_function_ ecb_inline -#if ECB_GCC_VERSION(3,1) - #define ecb_attribute(attrlist) __attribute__(attrlist) - #define ecb_is_constant(expr) __builtin_constant_p (expr) - #define ecb_expect(expr,value) __builtin_expect ((expr),(value)) - #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality) +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_VERSION(2,8) + #define ecb_attribute(attrlist) __attribute__ (attrlist) #else #define ecb_attribute(attrlist) +#endif + +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_constant_p) + #define ecb_is_constant(expr) __builtin_constant_p (expr) +#else + /* possible C11 impl for integral types + typedef struct ecb_is_constant_struct ecb_is_constant_struct; + #define ecb_is_constant(expr) _Generic ((1 ? (struct ecb_is_constant_struct *)0 : (void *)((expr) - (expr)), ecb_is_constant_struct *: 0, default: 1)) */ + #define ecb_is_constant(expr) 0 +#endif + +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_expect) + #define ecb_expect(expr,value) __builtin_expect ((expr),(value)) +#else #define ecb_expect(expr,value) (expr) +#endif + +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_prefetch) + #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality) +#else #define ecb_prefetch(addr,rw,locality) #endif /* no emulation for ecb_decltype */ -#if ECB_GCC_VERSION(4,5) - #define ecb_decltype(x) __decltype(x) -#elif ECB_GCC_VERSION(3,0) - #define ecb_decltype(x) __typeof(x) +#if ECB_CPP11 + // older implementations might have problems with decltype(x)::type, work around it + template<class T> struct ecb_decltype_t { typedef T type; }; + #define ecb_decltype(x) ecb_decltype_t<decltype (x)>::type +#elif ECB_GCC_VERSION(3,0) || ECB_CLANG_VERSION(2,8) + #define ecb_decltype(x) __typeof__ (x) +#endif + +#if _MSC_VER >= 1300 + #define ecb_deprecated __declspec (deprecated) +#else + #define ecb_deprecated ecb_attribute ((__deprecated__)) #endif #define ecb_noinline ecb_attribute ((__noinline__)) @@ -274,7 +355,9 @@ typedef int ecb_bool; #define ecb_const ecb_attribute ((__const__)) #define ecb_pure ecb_attribute ((__pure__)) -#if ECB_C11 +/* TODO http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx __declspec(noreturn) */ +#if ECB_C11 || __IBMC_NORETURN + /* http://pic.dhe.ibm.com/infocenter/compbg/v121v141/topic/com.ibm.xlcpp121.bg.doc/language_ref/noreturn.html */ #define ecb_noreturn _Noreturn #else #define ecb_noreturn ecb_attribute ((__noreturn__)) @@ -300,7 +383,10 @@ typedef int ecb_bool; #define ecb_unlikely(expr) ecb_expect_false (expr) /* count trailing zero bits and count # of one bits */ -#if ECB_GCC_VERSION(3,4) +#if ECB_GCC_VERSION(3,4) \ + || (ECB_CLANG_BUILTIN(__builtin_clz) && ECB_CLANG_BUILTIN(__builtin_clzll) \ + && ECB_CLANG_BUILTIN(__builtin_ctz) && ECB_CLANG_BUILTIN(__builtin_ctzll) \ + && ECB_CLANG_BUILTIN(__builtin_popcount)) /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */ #define ecb_ld32(x) (__builtin_clz (x) ^ 31) #define ecb_ld64(x) (__builtin_clzll (x) ^ 63) @@ -309,8 +395,8 @@ typedef int ecb_bool; #define ecb_popcount32(x) __builtin_popcount (x) /* no popcountll */ #else - ecb_function_ int ecb_ctz32 (uint32_t x) ecb_const; - ecb_function_ int + ecb_function_ ecb_const int ecb_ctz32 (uint32_t x); + ecb_function_ ecb_const int ecb_ctz32 (uint32_t x) { int r = 0; @@ -334,16 +420,16 @@ typedef int ecb_bool; return r; } - ecb_function_ int ecb_ctz64 (uint64_t x) ecb_const; - ecb_function_ int + ecb_function_ ecb_const int ecb_ctz64 (uint64_t x); + ecb_function_ ecb_const int ecb_ctz64 (uint64_t x) { int shift = x & 0xffffffffU ? 0 : 32; return ecb_ctz32 (x >> shift) + shift; } - ecb_function_ int ecb_popcount32 (uint32_t x) ecb_const; - ecb_function_ int + ecb_function_ ecb_const int ecb_popcount32 (uint32_t x); + ecb_function_ ecb_const int ecb_popcount32 (uint32_t x) { x -= (x >> 1) & 0x55555555; @@ -354,8 +440,8 @@ typedef int ecb_bool; return x >> 24; } - ecb_function_ int ecb_ld32 (uint32_t x) ecb_const; - ecb_function_ int ecb_ld32 (uint32_t x) + ecb_function_ ecb_const int ecb_ld32 (uint32_t x); + ecb_function_ ecb_const int ecb_ld32 (uint32_t x) { int r = 0; @@ -368,8 +454,8 @@ typedef int ecb_bool; return r; } - ecb_function_ int ecb_ld64 (uint64_t x) ecb_const; - ecb_function_ int ecb_ld64 (uint64_t x) + ecb_function_ ecb_const int ecb_ld64 (uint64_t x); + ecb_function_ ecb_const int ecb_ld64 (uint64_t x) { int r = 0; @@ -379,20 +465,20 @@ typedef int ecb_bool; } #endif -ecb_function_ ecb_bool ecb_is_pot32 (uint32_t x) ecb_const; -ecb_function_ ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); } -ecb_function_ ecb_bool ecb_is_pot64 (uint64_t x) ecb_const; -ecb_function_ ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); } +ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x); +ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); } +ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x); +ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); } -ecb_function_ uint8_t ecb_bitrev8 (uint8_t x) ecb_const; -ecb_function_ uint8_t ecb_bitrev8 (uint8_t x) +ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x); +ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x) { return ( (x * 0x0802U & 0x22110U) - | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16; + | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16; } -ecb_function_ uint16_t ecb_bitrev16 (uint16_t x) ecb_const; -ecb_function_ uint16_t ecb_bitrev16 (uint16_t x) +ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x); +ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x) { x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1); x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2); @@ -402,8 +488,8 @@ ecb_function_ uint16_t ecb_bitrev16 (uint16_t x) return x; } -ecb_function_ uint32_t ecb_bitrev32 (uint32_t x) ecb_const; -ecb_function_ uint32_t ecb_bitrev32 (uint32_t x) +ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x); +ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x) { x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1); x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2); @@ -416,71 +502,71 @@ ecb_function_ uint32_t ecb_bitrev32 (uint32_t x) /* popcount64 is only available on 64 bit cpus as gcc builtin */ /* so for this version we are lazy */ -ecb_function_ int ecb_popcount64 (uint64_t x) ecb_const; -ecb_function_ int +ecb_function_ ecb_const int ecb_popcount64 (uint64_t x); +ecb_function_ ecb_const int ecb_popcount64 (uint64_t x) { return ecb_popcount32 (x) + ecb_popcount32 (x >> 32); } -ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) ecb_const; -ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) ecb_const; -ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) ecb_const; -ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) ecb_const; -ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) ecb_const; -ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) ecb_const; -ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) ecb_const; -ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) ecb_const; - -ecb_inline uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); } -ecb_inline uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); } -ecb_inline uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); } -ecb_inline uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); } -ecb_inline uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); } -ecb_inline uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); } -ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); } -ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); } - -#if ECB_GCC_VERSION(4,3) +ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count); +ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count); +ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count); +ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count); +ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count); +ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count); +ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count); +ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count); + +ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); } +ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); } +ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); } +ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); } +ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); } +ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); } +ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); } +ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); } + +#if ECB_GCC_VERSION(4,3) || (ECB_CLANG_BUILTIN(__builtin_bswap32) && ECB_CLANG_BUILTIN(__builtin_bswap64)) #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16) #define ecb_bswap32(x) __builtin_bswap32 (x) #define ecb_bswap64(x) __builtin_bswap64 (x) #else - ecb_function_ uint16_t ecb_bswap16 (uint16_t x) ecb_const; - ecb_function_ uint16_t + ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x); + ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x) { return ecb_rotl16 (x, 8); } - ecb_function_ uint32_t ecb_bswap32 (uint32_t x) ecb_const; - ecb_function_ uint32_t + ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x); + ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x) { return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16); } - ecb_function_ uint64_t ecb_bswap64 (uint64_t x) ecb_const; - ecb_function_ uint64_t + ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x); + ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x) { return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32); } #endif -#if ECB_GCC_VERSION(4,5) +#if ECB_GCC_VERSION(4,5) || ECB_CLANG_BUILTIN(__builtin_unreachable) #define ecb_unreachable() __builtin_unreachable () #else /* this seems to work fine, but gcc always emits a warning for it :/ */ - ecb_inline void ecb_unreachable (void) ecb_noreturn; - ecb_inline void ecb_unreachable (void) { } + ecb_inline ecb_noreturn void ecb_unreachable (void); + ecb_inline ecb_noreturn void ecb_unreachable (void) { } #endif /* try to tell the compiler that some condition is definitely true */ #define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0 -ecb_inline unsigned char ecb_byteorder_helper (void) ecb_const; -ecb_inline unsigned char +ecb_inline ecb_const unsigned char ecb_byteorder_helper (void); +ecb_inline ecb_const unsigned char ecb_byteorder_helper (void) { /* the union code still generates code under pressure in gcc, */ @@ -505,10 +591,10 @@ ecb_byteorder_helper (void) #endif } -ecb_inline ecb_bool ecb_big_endian (void) ecb_const; -ecb_inline ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11; } -ecb_inline ecb_bool ecb_little_endian (void) ecb_const; -ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44; } +ecb_inline ecb_const ecb_bool ecb_big_endian (void); +ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11; } +ecb_inline ecb_const ecb_bool ecb_little_endian (void); +ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44; } #if ECB_GCC_VERSION(3,0) || ECB_C99 #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0)) @@ -516,7 +602,7 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n))) #endif -#if __cplusplus +#if ECB_CPP template<typename T> static inline T ecb_div_rd (T val, T div) { @@ -552,25 +638,66 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == || __i386 || __i386__ \ || __amd64 || __amd64__ || __x86_64 || __x86_64__ \ || __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ \ - || defined __arm__ && defined __ARM_EABI__ \ || defined __s390__ || defined __s390x__ \ || defined __mips__ \ || defined __alpha__ \ || defined __hppa__ \ || defined __ia64__ \ - || defined _M_IX86 || defined _M_AMD64 || defined _M_IA64 + || defined __m68k__ \ + || defined __m88k__ \ + || defined __sh__ \ + || defined _M_IX86 || defined _M_AMD64 || defined _M_IA64 \ + || (defined __arm__ && (defined __ARM_EABI__ || defined __EABI__ || defined __VFP_FP__ || defined _WIN32_WCE || defined __ANDROID__)) \ + || defined __aarch64__ #define ECB_STDFP 1 #include <string.h> /* for memcpy */ #else #define ECB_STDFP 0 - #include <math.h> /* for frexp*, ldexp* */ #endif #ifndef ECB_NO_LIBM + #include <math.h> /* for frexp*, ldexp*, INFINITY, NAN */ + + /* only the oldest of old doesn't have this one. solaris. */ + #ifdef INFINITY + #define ECB_INFINITY INFINITY + #else + #define ECB_INFINITY HUGE_VAL + #endif + + #ifdef NAN + #define ECB_NAN NAN + #else + #define ECB_NAN ECB_INFINITY + #endif + + #if ECB_C99 || _XOPEN_VERSION >= 600 || _POSIX_VERSION >= 200112L + #define ecb_ldexpf(x,e) ldexpf ((x), (e)) + #else + #define ecb_ldexpf(x,e) (float) ldexp ((x), (e)) + #endif + + /* converts an ieee half/binary16 to a float */ + ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x); + ecb_function_ ecb_const float + ecb_binary16_to_float (uint16_t x) + { + int e = (x >> 10) & 0x1f; + int m = x & 0x3ff; + float r; + + if (!e ) r = ecb_ldexpf (m , -24); + else if (e != 31) r = ecb_ldexpf (m + 0x400, e - 25); + else if (m ) r = ECB_NAN; + else r = ECB_INFINITY; + + return x & 0x8000 ? -r : r; + } + /* convert a float to ieee single/binary32 */ - ecb_function_ uint32_t ecb_float_to_binary32 (float x) ecb_const; - ecb_function_ uint32_t + ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x); + ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x) { uint32_t r; @@ -609,8 +736,8 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == } /* converts an ieee single/binary32 to a float */ - ecb_function_ float ecb_binary32_to_float (uint32_t x) ecb_const; - ecb_function_ float + ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x); + ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x) { float r; @@ -630,7 +757,7 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == e = 1; /* we distrust ldexpf a bit and do the 2**-24 scaling by an extra multiply */ - r = ldexpf (x * (0.5f / 0x800000U), e - 126); + r = ecb_ldexpf (x * (0.5f / 0x800000U), e - 126); r = neg ? -r : r; #endif @@ -639,8 +766,8 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == } /* convert a double to ieee double/binary64 */ - ecb_function_ uint64_t ecb_double_to_binary64 (double x) ecb_const; - ecb_function_ uint64_t + ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x); + ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x) { uint64_t r; @@ -679,8 +806,8 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == } /* converts an ieee double/binary64 to a double */ - ecb_function_ double ecb_binary64_to_double (uint64_t x) ecb_const; - ecb_function_ double + ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x); + ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x) { double r; diff --git a/third_party/libeio/eio.c b/third_party/libeio/eio.c index c5396c92e5aeb973921e82d77d0abaebd4a8af29..c83a467ded5ddb0391edd0bf22467938ac278d80 100644 --- a/third_party/libeio/eio.c +++ b/third_party/libeio/eio.c @@ -1,19 +1,19 @@ /* * libeio implementation * - * Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libeio@schmorp.de> + * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libeio@schmorp.de> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO @@ -214,9 +214,9 @@ static void eio_destroy (eio_req *req); return EIO_ERRNO (ENOENT, -1); } - /* POSIX API only */ - #define CreateHardLink(neu,old,flags) 0 - #define CreateSymbolicLink(neu,old,flags) 0 + /* POSIX API only, causing trouble for win32 apps */ + #define CreateHardLink(neu,old,flags) 0 /* not really creating hardlink, still using relative paths? */ + #define CreateSymbolicLink(neu,old,flags) 0 /* vista+ only */ struct statvfs { @@ -232,11 +232,19 @@ static void eio_destroy (eio_req *req); #include <sys/time.h> #include <sys/select.h> - #include <sys/statvfs.h> #include <unistd.h> #include <signal.h> #include <dirent.h> + #ifdef ANDROID + #include <sys/vfs.h> + #define statvfs statfs + #define fstatvfs fstatfs + #include <asm/page.h> /* supposedly limits.h does #define PAGESIZE PAGESIZE */ + #else + #include <sys/statvfs.h> + #endif + #if _POSIX_MEMLOCK || _POSIX_MEMLOCK_RANGE || _POSIX_MAPPED_FILES #include <sys/mman.h> #endif @@ -317,7 +325,7 @@ static void eio_destroy (eio_req *req); /* buffer size for various temporary buffers */ #define EIO_BUFSIZE 65536 -#define dBUF \ +#define dBUF \ char *eio_buf = malloc (EIO_BUFSIZE); \ errno = ENOMEM; \ if (!eio_buf) \ @@ -326,8 +334,6 @@ static void eio_destroy (eio_req *req); #define FUBd \ free (eio_buf) -#define EIO_TICKS ((1000000 + 1023) >> 10) - /*****************************************************************************/ struct tmpbuf @@ -375,6 +381,9 @@ struct eio_pwd #define ETP_PRI_MIN EIO_PRI_MIN #define ETP_PRI_MAX EIO_PRI_MAX +#define ETP_TYPE_QUIT -1 +#define ETP_TYPE_GROUP EIO_GROUP + struct etp_worker; #define ETP_REQ eio_req @@ -382,434 +391,9 @@ struct etp_worker; static int eio_finish (eio_req *req); #define ETP_FINISH(req) eio_finish (req) static void eio_execute (struct etp_worker *self, eio_req *req); -#define ETP_EXECUTE(wrk,req) eio_execute (wrk,req) - -/*****************************************************************************/ - -#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) - -/* calculate time difference in ~1/EIO_TICKS of a second */ -ecb_inline int -tvdiff (struct timeval *tv1, struct timeval *tv2) -{ - return (tv2->tv_sec - tv1->tv_sec ) * EIO_TICKS - + ((tv2->tv_usec - tv1->tv_usec) >> 10); -} - -static unsigned int started, idle, wanted = 4; - -static void (*want_poll_cb) (void); -static void (*done_poll_cb) (void); - -static unsigned int max_poll_time; /* reslock */ -static unsigned int max_poll_reqs; /* reslock */ - -static unsigned int nreqs; /* reqlock */ -static unsigned int nready; /* reqlock */ -static unsigned int npending; /* reqlock */ -static unsigned int max_idle = 4; /* maximum number of threads that can idle indefinitely */ -static unsigned int idle_timeout = 10; /* number of seconds after which an idle threads exit */ - -static xmutex_t wrklock; -static xmutex_t reslock; -static xmutex_t reqlock; -static xcond_t reqwait; - -typedef struct etp_worker -{ - struct tmpbuf tmpbuf; - - /* locked by wrklock */ - struct etp_worker *prev, *next; - - xthread_t tid; - -#ifdef ETP_WORKER_COMMON - ETP_WORKER_COMMON -#endif -} etp_worker; - -static etp_worker wrk_first; /* NOT etp */ - -#define ETP_WORKER_LOCK(wrk) X_LOCK (wrklock) -#define ETP_WORKER_UNLOCK(wrk) X_UNLOCK (wrklock) - -/* worker threads management */ - -static void -etp_worker_clear (etp_worker *wrk) -{ -} - -static void ecb_cold -etp_worker_free (etp_worker *wrk) -{ - free (wrk->tmpbuf.ptr); +#define ETP_EXECUTE(wrk,req) eio_execute (wrk, req) - wrk->next->prev = wrk->prev; - wrk->prev->next = wrk->next; - - free (wrk); -} - -static unsigned int -etp_nreqs (void) -{ - int retval; - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - retval = nreqs; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); - return retval; -} - -static unsigned int -etp_nready (void) -{ - unsigned int retval; - - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - retval = nready; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); - - return retval; -} - -static unsigned int -etp_npending (void) -{ - unsigned int retval; - - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - retval = npending; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); - - return retval; -} - -static unsigned int -etp_nthreads (void) -{ - unsigned int retval; - - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - retval = started; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); - - return retval; -} - -/* - * a somewhat faster data structure might be nice, but - * with 8 priorities this actually needs <20 insns - * per shift, the most expensive operation. - */ -typedef struct { - ETP_REQ *qs[ETP_NUM_PRI], *qe[ETP_NUM_PRI]; /* qstart, qend */ - int size; -} etp_reqq; - -static etp_reqq req_queue; -static etp_reqq res_queue; - -static void ecb_noinline ecb_cold -reqq_init (etp_reqq *q) -{ - int pri; - - for (pri = 0; pri < ETP_NUM_PRI; ++pri) - q->qs[pri] = q->qe[pri] = 0; - - q->size = 0; -} - -static int ecb_noinline -reqq_push (etp_reqq *q, ETP_REQ *req) -{ - int pri = req->pri; - req->next = 0; - - if (q->qe[pri]) - { - q->qe[pri]->next = req; - q->qe[pri] = req; - } - else - q->qe[pri] = q->qs[pri] = req; - - return q->size++; -} - -static ETP_REQ * ecb_noinline -reqq_shift (etp_reqq *q) -{ - int pri; - - if (!q->size) - return 0; - - --q->size; - - for (pri = ETP_NUM_PRI; pri--; ) - { - eio_req *req = q->qs[pri]; - - if (req) - { - if (!(q->qs[pri] = (eio_req *)req->next)) - q->qe[pri] = 0; - - return req; - } - } - - abort (); -} - -static int ecb_cold -etp_init (void (*want_poll)(void), void (*done_poll)(void)) -{ - X_MUTEX_CREATE (wrklock); - X_MUTEX_CREATE (reslock); - X_MUTEX_CREATE (reqlock); - X_COND_CREATE (reqwait); - - reqq_init (&req_queue); - reqq_init (&res_queue); - - wrk_first.next = - wrk_first.prev = &wrk_first; - - started = 0; - idle = 0; - nreqs = 0; - nready = 0; - npending = 0; - - want_poll_cb = want_poll; - done_poll_cb = done_poll; - - return 0; -} - -X_THREAD_PROC (etp_proc); - -static void ecb_cold -etp_start_thread (void) -{ - etp_worker *wrk = calloc (1, sizeof (etp_worker)); - - /*TODO*/ - assert (("unable to allocate worker thread data", wrk)); - - X_LOCK (wrklock); - - if (xthread_create (&wrk->tid, etp_proc, (void *)wrk)) - { - wrk->prev = &wrk_first; - wrk->next = wrk_first.next; - wrk_first.next->prev = wrk; - wrk_first.next = wrk; - ++started; - } - else - free (wrk); - - X_UNLOCK (wrklock); -} - -static void -etp_maybe_start_thread (void) -{ - if (ecb_expect_true (etp_nthreads () >= wanted)) - return; - - /* todo: maybe use idle here, but might be less exact */ - if (ecb_expect_true (0 <= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ())) - return; - - etp_start_thread (); -} - -static void ecb_cold -etp_end_thread (void) -{ - eio_req *req = calloc (1, sizeof (eio_req)); /* will be freed by worker */ - - req->type = -1; - req->pri = ETP_PRI_MAX - ETP_PRI_MIN; - - X_LOCK (reqlock); - reqq_push (&req_queue, req); - X_COND_SIGNAL (reqwait); - X_UNLOCK (reqlock); - - X_LOCK (wrklock); - --started; - X_UNLOCK (wrklock); -} - -static int -etp_poll (void) -{ - unsigned int maxreqs; - unsigned int maxtime; - struct timeval tv_start, tv_now; - - X_LOCK (reslock); - maxreqs = max_poll_reqs; - maxtime = max_poll_time; - X_UNLOCK (reslock); - - if (maxtime) - gettimeofday (&tv_start, 0); - - for (;;) - { - ETP_REQ *req; - - etp_maybe_start_thread (); - - X_LOCK (reslock); - req = reqq_shift (&res_queue); - - if (req) - { - --npending; - - if (!res_queue.size && done_poll_cb) - done_poll_cb (); - } - - X_UNLOCK (reslock); - - if (!req) - return 0; - - X_LOCK (reqlock); - --nreqs; - X_UNLOCK (reqlock); - - if (ecb_expect_false (req->type == EIO_GROUP && req->size)) - { - req->int1 = 1; /* mark request as delayed */ - continue; - } - else - { - int res = ETP_FINISH (req); - if (ecb_expect_false (res)) - return res; - } - - if (ecb_expect_false (maxreqs && !--maxreqs)) - break; - - if (maxtime) - { - gettimeofday (&tv_now, 0); - - if (tvdiff (&tv_start, &tv_now) >= maxtime) - break; - } - } - - errno = EAGAIN; - return -1; -} - -static void -etp_cancel (ETP_REQ *req) -{ - req->cancelled = 1; - - eio_grp_cancel (req); -} - -static void -etp_submit (ETP_REQ *req) -{ - req->pri -= ETP_PRI_MIN; - - if (ecb_expect_false (req->pri < ETP_PRI_MIN - ETP_PRI_MIN)) req->pri = ETP_PRI_MIN - ETP_PRI_MIN; - if (ecb_expect_false (req->pri > ETP_PRI_MAX - ETP_PRI_MIN)) req->pri = ETP_PRI_MAX - ETP_PRI_MIN; - - if (ecb_expect_false (req->type == EIO_GROUP)) - { - /* I hope this is worth it :/ */ - X_LOCK (reqlock); - ++nreqs; - X_UNLOCK (reqlock); - - X_LOCK (reslock); - - ++npending; - - if (!reqq_push (&res_queue, req) && want_poll_cb) - want_poll_cb (); - - X_UNLOCK (reslock); - } - else - { - X_LOCK (reqlock); - ++nreqs; - ++nready; - reqq_push (&req_queue, req); - X_COND_SIGNAL (reqwait); - X_UNLOCK (reqlock); - - etp_maybe_start_thread (); - } -} - -static void ecb_cold -etp_set_max_poll_time (double nseconds) -{ - if (WORDACCESS_UNSAFE) X_LOCK (reslock); - max_poll_time = nseconds * EIO_TICKS; - if (WORDACCESS_UNSAFE) X_UNLOCK (reslock); -} - -static void ecb_cold -etp_set_max_poll_reqs (unsigned int maxreqs) -{ - if (WORDACCESS_UNSAFE) X_LOCK (reslock); - max_poll_reqs = maxreqs; - if (WORDACCESS_UNSAFE) X_UNLOCK (reslock); -} - -static void ecb_cold -etp_set_max_idle (unsigned int nthreads) -{ - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - max_idle = nthreads; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); -} - -static void ecb_cold -etp_set_idle_timeout (unsigned int seconds) -{ - if (WORDACCESS_UNSAFE) X_LOCK (reqlock); - idle_timeout = seconds; - if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); -} - -static void ecb_cold -etp_set_min_parallel (unsigned int nthreads) -{ - if (wanted < nthreads) - wanted = nthreads; -} - -static void ecb_cold -etp_set_max_parallel (unsigned int nthreads) -{ - if (wanted > nthreads) - wanted = nthreads; - - while (started > wanted) - etp_end_thread (); -} +#include "etp.c" /*****************************************************************************/ @@ -886,8 +470,7 @@ eio_finish (eio_req *req) void eio_grp_cancel (eio_req *grp) { - for (grp = grp->grp_first; grp; grp = grp->grp_next) - eio_cancel (grp); + etp_grp_cancel (grp); } void @@ -1386,8 +969,8 @@ eio__lseek (eio_req *req) static int eio__realpath (struct tmpbuf *tmpbuf, eio_wd wd, const char *path) { - const char *rel = path; char *res; + const char *rel = path; char *tmp1, *tmp2; #if SYMLOOP_MAX > 32 int symlinks = SYMLOOP_MAX; @@ -1404,6 +987,23 @@ eio__realpath (struct tmpbuf *tmpbuf, eio_wd wd, const char *path) return -1; res = tmpbuf_get (tmpbuf, PATH_MAX * 3); +#ifdef _WIN32 + if (_access (rel, 4) != 0) + return -1; + + symlinks = GetFullPathName (rel, PATH_MAX * 3, res, 0); + + errno = ENAMETOOLONG; + if (symlinks >= PATH_MAX * 3) + return -1; + + errno = EIO; + if (symlinks <= 0) + return -1; + + return symlinks; + +#else tmp1 = res + PATH_MAX; tmp2 = tmp1 + PATH_MAX; @@ -1417,15 +1017,14 @@ eio__realpath (struct tmpbuf *tmpbuf, eio_wd wd, const char *path) { sprintf (tmp1, "/proc/self/fd/%d", fd); req->result = readlink (tmp1, res, PATH_MAX); - close (fd); - /* here we should probably stat the open file and the disk file, to make sure they still match */ + close (fd); if (req->result > 0) goto done; } else if (errno == ELOOP || errno == ENAMETOOLONG || errno == ENOENT || errno == ENOTDIR || errno == EIO) - return; + return -1; } #endif #endif @@ -1537,6 +1136,7 @@ eio__realpath (struct tmpbuf *tmpbuf, eio_wd wd, const char *path) *res++ = '/'; return res - (char *)tmpbuf->ptr; +#endif } static signed char @@ -2150,6 +1750,7 @@ etp_proc_init (void) #endif } +/* TODO: move somehow to etp.c */ X_THREAD_PROC (etp_proc) { ETP_REQ *req; @@ -2205,7 +1806,7 @@ X_THREAD_PROC (etp_proc) X_UNLOCK (reqlock); - if (req->type < 0) + if (req->type == ETP_TYPE_QUIT) goto quit; ETP_EXECUTE (self, req); @@ -2270,6 +1871,8 @@ eio_api_destroy (eio_req *req) return 0; \ } +#define SINGLEDOT(ptr) (0[(char *)(ptr)] == '.' && !1[(char *)(ptr)]) + static void eio_execute (etp_worker *self, eio_req *req) { @@ -2334,9 +1937,15 @@ eio_execute (etp_worker *self, eio_req *req) case EIO_OPEN: req->result = openat (dirfd, req->ptr1, req->int1, (mode_t)req->int2); break; case EIO_UNLINK: req->result = unlinkat (dirfd, req->ptr1, 0); break; - case EIO_RMDIR: req->result = unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break; + case EIO_RMDIR: /* complications arise because "." cannot be removed, so we might have to expand */ + req->result = req->wd && SINGLEDOT (req->ptr1) + ? rmdir (req->wd->str) + : unlinkat (dirfd, req->ptr1, AT_REMOVEDIR); break; case EIO_MKDIR: req->result = mkdirat (dirfd, req->ptr1, (mode_t)req->int2); break; - case EIO_RENAME: req->result = renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break; + case EIO_RENAME: /* complications arise because "." cannot be renamed, so we might have to expand */ + req->result = req->wd && SINGLEDOT (req->ptr1) + ? rename (req->wd->str, req->ptr2) + : renameat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2); break; case EIO_LINK: req->result = linkat (dirfd, req->ptr1, WD2FD ((eio_wd)req->int3), req->ptr2, 0); break; case EIO_SYMLINK: req->result = symlinkat (req->ptr1, dirfd, req->ptr2); break; case EIO_MKNOD: req->result = mknodat (dirfd, req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break; diff --git a/third_party/libeio/eio.h b/third_party/libeio/eio.h index f97f48fce655f2088986476d2daeb62dc15ef6a9..b61a8855d593ea727ce32ca2930c89b5f160fba6 100644 --- a/third_party/libeio/eio.h +++ b/third_party/libeio/eio.h @@ -256,21 +256,21 @@ struct eio_req eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */ eio_tstamp nv2; /* utime, futime: mtime */ - int type; /* EIO_xxx constant ETP */ int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */ long int2; /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, seek: whence, sync_file_range, fallocate: flags */ long int3; /* chown, fchown: gid; rename, link: working directory of new name */ int errorno; /* errno value on syscall return */ + unsigned char flags; /* private */ + + signed char type;/* EIO_xxx constant ETP */ + signed char pri; /* the priority ETP */ #if __i386 || __amd64 - unsigned char cancelled; + unsigned char cancelled; /* ETP */ #else - sig_atomic_t cancelled; + sig_atomic_t cancelled; /* ETP */ #endif - unsigned char flags; /* private */ - signed char pri; /* the priority */ - void *data; eio_cb finish; void (*destroy)(eio_req *req); /* called when request no longer needed */ @@ -278,7 +278,7 @@ struct eio_req EIO_REQ_MEMBERS - eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */ + eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private ETP */ }; /* _private_ request flags */ diff --git a/third_party/libeio/eio.pod b/third_party/libeio/eio.pod index 83a59894195cfdff24f6a78ba9ff103b01fe10f9..6afff56b637a638ad44a16e248a5d5935232646d 100644 --- a/third_party/libeio/eio.pod +++ b/third_party/libeio/eio.pod @@ -27,7 +27,7 @@ or C<readlink>. It also offers wrappers around C<sendfile> (Solaris, Linux, HP-UX and FreeBSD, with emulation on other platforms) and C<readahead> (Linux, with -emulation elsewhere>). +emulation elsewhere). The goal is to enable you to write fully non-blocking programs. For example, in a game server, you would not want to freeze for a few seconds @@ -178,7 +178,7 @@ lot by removing the idle watcher logic): ev_idle_init (&repeat_watcher, repeat); ev_async_init (&ready_watcher, ready); - ev_async_start (loop &watcher); + ev_async_start (loop, &watcher); eio_init (want_poll, 0); } @@ -292,21 +292,7 @@ Cancel the request (and all its subrequests). If the request is currently executing it might still continue to execute, and in other cases it might still take a while till the request is cancelled. -Even if cancelled, the finish callback will still be invoked - the -callbacks of all cancellable requests need to check whether the request -has been cancelled by calling C<EIO_CANCELLED (req)>: - - static int - my_eio_cb (eio_req *req) - { - if (EIO_CANCELLED (req)) - return 0; - } - -In addition, cancelled requests will I<either> have C<< req->result >> -set to C<-1> and C<errno> to C<ECANCELED>, or I<otherwise> they were -successfully executed, despite being cancelled (e.g. when they have -already been executed at the time they were cancelled). +When cancelled, the finish callback will not be invoked. C<EIO_CANCELLED> is still true for requests that have successfully executed, as long as C<eio_cancel> was called on them at some point. @@ -632,7 +618,7 @@ These requests are specific to libeio and do not correspond to any OS call. =item eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data) -Reads (C<flags == 0>) or modifies (C<flags == EIO_MT_MODIFY) the given +Reads (C<flags == 0>) or modifies (C<flags == EIO_MT_MODIFY>) the given memory area, page-wise, that is, it reads (or reads and writes back) the first octet of every page that spans the memory area. @@ -790,8 +776,6 @@ sure you I<always> set C<< grp->result >> to some sensible value. void eio_grp_limit (eio_req *grp, int limit); -=back - =head1 LOW LEVEL REQUEST API @@ -928,10 +912,8 @@ was written to use very little stackspace, but when using C<EIO_CUSTOM> requests, you might want to increase this. If this symbol is undefined (the default) then libeio will use its default -stack size (C<sizeof (void *) * 4096> currently). If it is defined, but -C<0>, then the default operating system stack size will be used. In all -other cases, the value must be an expression that evaluates to the desired -stack size. +stack size (C<sizeof (void *) * 4096> currently). In all other cases, the +value must be an expression that evaluates to the desired stack size. =back diff --git a/third_party/libeio/etp.c b/third_party/libeio/etp.c new file mode 100644 index 0000000000000000000000000000000000000000..f97eaccae2c20a89ac0554c5a310640a30e357bc --- /dev/null +++ b/third_party/libeio/etp.c @@ -0,0 +1,494 @@ +/* + * libetp implementation + * + * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libetp@schmorp.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifndef ETP_API_DECL +# define ETP_API_DECL static +#endif + +#ifndef ETP_PRI_MIN +# define ETP_PRI_MIN 0 +# define ETP_PRI_MAX 0 +#endif + +#ifndef ETP_TYPE_QUIT +# define ETP_TYPE_QUIT 0 +#endif + +#ifndef ETP_TYPE_GROUP +# define ETP_TYPE_GROUP 1 +#endif + +#define ETP_NUM_PRI (ETP_PRI_MAX - ETP_PRI_MIN + 1) + +#define ETP_TICKS ((1000000 + 1023) >> 10) + +/* calculate time difference in ~1/ETP_TICKS of a second */ +ecb_inline int +etp_tvdiff (struct timeval *tv1, struct timeval *tv2) +{ + return (tv2->tv_sec - tv1->tv_sec ) * ETP_TICKS + + ((tv2->tv_usec - tv1->tv_usec) >> 10); +} + +static unsigned int started, idle, wanted = 4; + +static void (*want_poll_cb) (void); +static void (*done_poll_cb) (void); + +static unsigned int max_poll_time; /* reslock */ +static unsigned int max_poll_reqs; /* reslock */ + +static unsigned int nreqs; /* reqlock */ +static unsigned int nready; /* reqlock */ +static unsigned int npending; /* reqlock */ +static unsigned int max_idle = 4; /* maximum number of threads that can idle indefinitely */ +static unsigned int idle_timeout = 10; /* number of seconds after which an idle threads exit */ + +static xmutex_t wrklock; +static xmutex_t reslock; +static xmutex_t reqlock; +static xcond_t reqwait; + +typedef struct etp_worker +{ + struct tmpbuf tmpbuf; + + /* locked by wrklock */ + struct etp_worker *prev, *next; + + xthread_t tid; + +#ifdef ETP_WORKER_COMMON + ETP_WORKER_COMMON +#endif +} etp_worker; + +static etp_worker wrk_first; /* NOT etp */ + +#define ETP_WORKER_LOCK(wrk) X_LOCK (wrklock) +#define ETP_WORKER_UNLOCK(wrk) X_UNLOCK (wrklock) + +/* worker threads management */ + +static void +etp_worker_clear (etp_worker *wrk) +{ +} + +static void ecb_cold +etp_worker_free (etp_worker *wrk) +{ + free (wrk->tmpbuf.ptr); + + wrk->next->prev = wrk->prev; + wrk->prev->next = wrk->next; + + free (wrk); +} + +ETP_API_DECL unsigned int +etp_nreqs (void) +{ + int retval; + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + retval = nreqs; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); + return retval; +} + +ETP_API_DECL unsigned int +etp_nready (void) +{ + unsigned int retval; + + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + retval = nready; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); + + return retval; +} + +ETP_API_DECL unsigned int +etp_npending (void) +{ + unsigned int retval; + + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + retval = npending; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); + + return retval; +} + +ETP_API_DECL unsigned int +etp_nthreads (void) +{ + unsigned int retval; + + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + retval = started; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); + + return retval; +} + +/* + * a somewhat faster data structure might be nice, but + * with 8 priorities this actually needs <20 insns + * per shift, the most expensive operation. + */ +typedef struct { + ETP_REQ *qs[ETP_NUM_PRI], *qe[ETP_NUM_PRI]; /* qstart, qend */ + int size; +} etp_reqq; + +static etp_reqq req_queue; +static etp_reqq res_queue; + +static void ecb_noinline ecb_cold +reqq_init (etp_reqq *q) +{ + int pri; + + for (pri = 0; pri < ETP_NUM_PRI; ++pri) + q->qs[pri] = q->qe[pri] = 0; + + q->size = 0; +} + +static int ecb_noinline +reqq_push (etp_reqq *q, ETP_REQ *req) +{ + int pri = req->pri; + req->next = 0; + + if (q->qe[pri]) + { + q->qe[pri]->next = req; + q->qe[pri] = req; + } + else + q->qe[pri] = q->qs[pri] = req; + + return q->size++; +} + +static ETP_REQ * ecb_noinline +reqq_shift (etp_reqq *q) +{ + int pri; + + if (!q->size) + return 0; + + --q->size; + + for (pri = ETP_NUM_PRI; pri--; ) + { + ETP_REQ *req = q->qs[pri]; + + if (req) + { + if (!(q->qs[pri] = (ETP_REQ *)req->next)) + q->qe[pri] = 0; + + return req; + } + } + + abort (); +} + +ETP_API_DECL int ecb_cold +etp_init (void (*want_poll)(void), void (*done_poll)(void)) +{ + X_MUTEX_CREATE (wrklock); + X_MUTEX_CREATE (reslock); + X_MUTEX_CREATE (reqlock); + X_COND_CREATE (reqwait); + + reqq_init (&req_queue); + reqq_init (&res_queue); + + wrk_first.next = + wrk_first.prev = &wrk_first; + + started = 0; + idle = 0; + nreqs = 0; + nready = 0; + npending = 0; + + want_poll_cb = want_poll; + done_poll_cb = done_poll; + + return 0; +} + +/* not yet in etp.c */ +X_THREAD_PROC (etp_proc); + +static void ecb_cold +etp_start_thread (void) +{ + etp_worker *wrk = calloc (1, sizeof (etp_worker)); + + /*TODO*/ + assert (("unable to allocate worker thread data", wrk)); + + X_LOCK (wrklock); + + if (xthread_create (&wrk->tid, etp_proc, (void *)wrk)) + { + wrk->prev = &wrk_first; + wrk->next = wrk_first.next; + wrk_first.next->prev = wrk; + wrk_first.next = wrk; + ++started; + } + else + free (wrk); + + X_UNLOCK (wrklock); +} + +static void +etp_maybe_start_thread (void) +{ + if (ecb_expect_true (etp_nthreads () >= wanted)) + return; + + /* todo: maybe use idle here, but might be less exact */ + if (ecb_expect_true (0 <= (int)etp_nthreads () + (int)etp_npending () - (int)etp_nreqs ())) + return; + + etp_start_thread (); +} + +static void ecb_cold +etp_end_thread (void) +{ + ETP_REQ *req = calloc (1, sizeof (ETP_REQ)); /* will be freed by worker */ + + req->type = ETP_TYPE_QUIT; + req->pri = ETP_PRI_MAX - ETP_PRI_MIN; + + X_LOCK (reqlock); + reqq_push (&req_queue, req); + X_COND_SIGNAL (reqwait); + X_UNLOCK (reqlock); + + X_LOCK (wrklock); + --started; + X_UNLOCK (wrklock); +} + +ETP_API_DECL int +etp_poll (void) +{ + unsigned int maxreqs; + unsigned int maxtime; + struct timeval tv_start, tv_now; + + X_LOCK (reslock); + maxreqs = max_poll_reqs; + maxtime = max_poll_time; + X_UNLOCK (reslock); + + if (maxtime) + gettimeofday (&tv_start, 0); + + for (;;) + { + ETP_REQ *req; + + etp_maybe_start_thread (); + + X_LOCK (reslock); + req = reqq_shift (&res_queue); + + if (req) + { + --npending; + + if (!res_queue.size && done_poll_cb) + done_poll_cb (); + } + + X_UNLOCK (reslock); + + if (!req) + return 0; + + X_LOCK (reqlock); + --nreqs; + X_UNLOCK (reqlock); + + if (ecb_expect_false (req->type == ETP_TYPE_GROUP && req->size)) + { + req->int1 = 1; /* mark request as delayed */ + continue; + } + else + { + int res = ETP_FINISH (req); + if (ecb_expect_false (res)) + return res; + } + + if (ecb_expect_false (maxreqs && !--maxreqs)) + break; + + if (maxtime) + { + gettimeofday (&tv_now, 0); + + if (etp_tvdiff (&tv_start, &tv_now) >= maxtime) + break; + } + } + + errno = EAGAIN; + return -1; +} + +ETP_API_DECL void +etp_grp_cancel (ETP_REQ *grp); + +ETP_API_DECL void +etp_cancel (ETP_REQ *req) +{ + req->cancelled = 1; + + etp_grp_cancel (req); +} + +ETP_API_DECL void +etp_grp_cancel (ETP_REQ *grp) +{ + for (grp = grp->grp_first; grp; grp = grp->grp_next) + etp_cancel (grp); +} + +ETP_API_DECL void +etp_submit (ETP_REQ *req) +{ + req->pri -= ETP_PRI_MIN; + + if (ecb_expect_false (req->pri < ETP_PRI_MIN - ETP_PRI_MIN)) req->pri = ETP_PRI_MIN - ETP_PRI_MIN; + if (ecb_expect_false (req->pri > ETP_PRI_MAX - ETP_PRI_MIN)) req->pri = ETP_PRI_MAX - ETP_PRI_MIN; + + if (ecb_expect_false (req->type == ETP_TYPE_GROUP)) + { + /* I hope this is worth it :/ */ + X_LOCK (reqlock); + ++nreqs; + X_UNLOCK (reqlock); + + X_LOCK (reslock); + + ++npending; + + if (!reqq_push (&res_queue, req) && want_poll_cb) + want_poll_cb (); + + X_UNLOCK (reslock); + } + else + { + X_LOCK (reqlock); + ++nreqs; + ++nready; + reqq_push (&req_queue, req); + X_COND_SIGNAL (reqwait); + X_UNLOCK (reqlock); + + etp_maybe_start_thread (); + } +} + +ETP_API_DECL void ecb_cold +etp_set_max_poll_time (double nseconds) +{ + if (WORDACCESS_UNSAFE) X_LOCK (reslock); + max_poll_time = nseconds * ETP_TICKS; + if (WORDACCESS_UNSAFE) X_UNLOCK (reslock); +} + +ETP_API_DECL void ecb_cold +etp_set_max_poll_reqs (unsigned int maxreqs) +{ + if (WORDACCESS_UNSAFE) X_LOCK (reslock); + max_poll_reqs = maxreqs; + if (WORDACCESS_UNSAFE) X_UNLOCK (reslock); +} + +ETP_API_DECL void ecb_cold +etp_set_max_idle (unsigned int nthreads) +{ + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + max_idle = nthreads; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); +} + +ETP_API_DECL void ecb_cold +etp_set_idle_timeout (unsigned int seconds) +{ + if (WORDACCESS_UNSAFE) X_LOCK (reqlock); + idle_timeout = seconds; + if (WORDACCESS_UNSAFE) X_UNLOCK (reqlock); +} + +ETP_API_DECL void ecb_cold +etp_set_min_parallel (unsigned int nthreads) +{ + if (wanted < nthreads) + wanted = nthreads; +} + +ETP_API_DECL void ecb_cold +etp_set_max_parallel (unsigned int nthreads) +{ + if (wanted > nthreads) + wanted = nthreads; + + while (started > wanted) + etp_end_thread (); +} + diff --git a/third_party/libeio/xthread.h b/third_party/libeio/xthread.h index 60310d59cc024d44a930b1f5cced053c18a201f9..86ae73699c410b7aa2a359351d1907421310a186 100644 --- a/third_party/libeio/xthread.h +++ b/third_party/libeio/xthread.h @@ -17,8 +17,8 @@ #ifdef _WIN32 -#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls -#define _WIN32_WINNT 0x400 +//#define NTDDI_VERSION NTDDI_WIN2K // needed to get win2000 api calls, fails with mingw +#define _WIN32_WINNT 0x400 // maybe working alternative for mingw #include <stdio.h>//D #include <fcntl.h> #include <io.h> @@ -26,6 +26,12 @@ #include <winsock2.h> #include <process.h> #include <windows.h> + +/* work around some bugs in ptw32 */ +#if defined(__MINGW32__) && defined(_TIMESPEC_DEFINED) +#define HAVE_STRUCT_TIMESPEC 1 +#endif + #include <pthread.h> #define sigset_t int #define sigfillset(a) diff --git a/third_party/lua-cjson/lua_cjson.c b/third_party/lua-cjson/lua_cjson.c index 3915127db3ca09dcdaca678d0c01771ee4329d02..88599082cffca475710fcccd0094b17f733ca99a 100644 --- a/third_party/lua-cjson/lua_cjson.c +++ b/third_party/lua-cjson/lua_cjson.c @@ -1037,6 +1037,8 @@ luaopen_json(lua_State *L) json_create_tokens(); luaL_json_default = luaL_newserializer(L, jsonlib); luaL_register_module(L, "json", NULL); + luaL_pushnull(L); + lua_setfield(L, -2, "null"); /* compatibility with cjson */ return 1; } diff --git a/third_party/proctitle.c b/third_party/proctitle.c index 92eca759c18e194448481049a1b38fa0f4e0406d..2e7009a695646ad54755362735392d02982d1d37 100644 --- a/third_party/proctitle.c +++ b/third_party/proctitle.c @@ -220,7 +220,7 @@ init_set_proc_title(int argc, char **argv) ps_buffer_fixed_size = 0; #else { - char basename_buf[PATH_MAX]; + char basename_buf[PATH_MAX+1]; /* * At least partially mimic FreeBSD, which for @@ -228,7 +228,7 @@ init_set_proc_title(int argc, char **argv) * * a.out: custom title here (a.out) */ - snprintf(basename_buf, sizeof basename_buf, "%s", argv[0]); + snprintf(basename_buf, PATH_MAX, "%s", argv[0]); snprintf(ps_buffer, ps_buffer_size, "%s: ", basename(basename_buf)); }