Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH 0/3][vshard] Add error messages
@ 2018-06-06 15:57 AKhatskevich
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 1/3] Fix test on bucket_transferring error AKhatskevich
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: AKhatskevich @ 2018-06-06 15:57 UTC (permalink / raw)
  To: tarantool-patches, v.shpilevoy

Branch: https://github.com/tarantool/vshard/tree/kh/gh-100-error-msg-wo-extra-data
Issue: https://github.com/tarantool/vshard/issues/100

*** BLURB HERE ***

AKhatskevich (3):
  Fix test on bucket_transferring error
  Refactor error reporting system
  Add error messages

 test/misc/check_uuid_on_connect.result  |   8 +-
 test/router/reroute_wrong_bucket.result |  11 +-
 test/router/router.result               |  54 +++++---
 test/router/router.test.lua             |   4 +-
 test/storage/storage.result             |   7 +-
 test/unit/error.result                  |   6 +-
 test/unit/error.test.lua                |   2 +-
 vshard/error.lua                        | 216 +++++++++++++++++++++-----------
 vshard/replicaset.lua                   |   4 +-
 vshard/router/init.lua                  |  10 +-
 vshard/storage/init.lua                 |  39 +++---
 11 files changed, 231 insertions(+), 130 deletions(-)

-- 
2.14.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] [PATCH 1/3] Fix test on bucket_transferring error
  2018-06-06 15:57 [tarantool-patches] [PATCH 0/3][vshard] Add error messages AKhatskevich
@ 2018-06-06 15:57 ` AKhatskevich
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 2/3] Refactor error reporting system AKhatskevich
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: AKhatskevich @ 2018-06-06 15:57 UTC (permalink / raw)
  To: tarantool-patches, v.shpilevoy

---
 test/router/router.result   | 12 ++++++------
 test/router/router.test.lua |  4 ++--
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/test/router/router.result b/test/router/router.result
index 101369a..5f3ceca 100644
--- a/test/router/router.result
+++ b/test/router/router.result
@@ -328,17 +328,17 @@ test_run:cmd('switch storage_2_a')
 ---
 - true
 ...
-box.space._bucket:replace({1, vshard.consts.BUCKET.SENDING})
+box.space._bucket:replace({1, vshard.consts.BUCKET.SENDING, '<replicaset_1>'})
 ---
-- [1, 'sending']
+- [1, 'sending', '<replicaset_1>']
 ...
 test_run:cmd('switch storage_1_a')
 ---
 - true
 ...
-box.space._bucket:replace({1, vshard.consts.BUCKET.RECEIVING})
+box.space._bucket:replace({1, vshard.consts.BUCKET.RECEIVING, '<replicaset_2>'})
 ---
-- [1, 'receiving']
+- [1, 'receiving', '<replicaset_2>']
 ...
 test_run:cmd('switch router_1')
 ---
@@ -353,7 +353,7 @@ vshard.router.call(1, 'read', 'echo', {123})
 util.check_error(vshard.router.call, 1, 'write', 'echo', {123})
 ---
 - null
-- {'type': 'ShardingError', 'code': 7, 'bucket_id': 1}
+- {'type': 'ShardingError', 'bucket_id': 1, 'code': 7, 'destination': '<replicaset_1>'}
 ...
 test_run:cmd('switch storage_2_a')
 ---
@@ -369,7 +369,7 @@ test_run:cmd('switch storage_1_a')
 ...
 box.space._bucket:delete({1})
 ---
-- [1, 'receiving']
+- [1, 'receiving', '<replicaset_2>']
 ...
 test_run:cmd('switch router_1')
 ---
diff --git a/test/router/router.test.lua b/test/router/router.test.lua
index 62d6730..fae8e24 100644
--- a/test/router/router.test.lua
+++ b/test/router/router.test.lua
@@ -119,9 +119,9 @@ replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
 replicaset, err = vshard.router.bucket_discovery(2); return err == nil or err
 
 test_run:cmd('switch storage_2_a')
-box.space._bucket:replace({1, vshard.consts.BUCKET.SENDING})
+box.space._bucket:replace({1, vshard.consts.BUCKET.SENDING, 'cbf06940-0790-498b-948d-042b62cf3d29'})
 test_run:cmd('switch storage_1_a')
-box.space._bucket:replace({1, vshard.consts.BUCKET.RECEIVING})
+box.space._bucket:replace({1, vshard.consts.BUCKET.RECEIVING, 'ac522f65-aa94-4134-9f64-51ee384f1a54'})
 test_run:cmd('switch router_1')
 -- Ok to read sending bucket.
 vshard.router.call(1, 'read', 'echo', {123})
-- 
2.14.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] [PATCH 2/3] Refactor error reporting system
  2018-06-06 15:57 [tarantool-patches] [PATCH 0/3][vshard] Add error messages AKhatskevich
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 1/3] Fix test on bucket_transferring error AKhatskevich
@ 2018-06-06 15:57 ` AKhatskevich
  2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 3/3] Add error messages AKhatskevich
  2018-06-07 12:22 ` [tarantool-patches] Re: [PATCH 0/3][vshard] " Vladislav Shpilevoy
  3 siblings, 1 reply; 11+ messages in thread
From: AKhatskevich @ 2018-06-06 15:57 UTC (permalink / raw)
  To: tarantool-patches, v.shpilevoy

This commit applies stricter rules on error reporting:
 * error may has only arguments specified in `args` field of
   `error_message_template`
 * arguments may be used in error message
 * arguments are saved in error object by names from `args`

Part of #100
---
 test/misc/check_uuid_on_connect.result  |   8 +-
 test/router/reroute_wrong_bucket.result |  10 +-
 test/router/router.result               |  42 ++++---
 test/storage/storage.result             |   6 +-
 test/unit/error.result                  |   6 +-
 test/unit/error.test.lua                |   2 +-
 vshard/error.lua                        | 209 +++++++++++++++++++++-----------
 vshard/replicaset.lua                   |   4 +-
 vshard/router/init.lua                  |  11 +-
 vshard/storage/init.lua                 |  17 +--
 10 files changed, 197 insertions(+), 118 deletions(-)

diff --git a/test/misc/check_uuid_on_connect.result b/test/misc/check_uuid_on_connect.result
index d54c367..2695665 100644
--- a/test/misc/check_uuid_on_connect.result
+++ b/test/misc/check_uuid_on_connect.result
@@ -182,10 +182,12 @@ test_run:switch('bad_uuid_router')
 vshard.router.bucket_discovery(1)
 ---
 - null
-- type: ShardingError
-  unreachable_uuid: ac522f65-aa94-4134-9f64-51ee384f1a54
+- bucket_id: 1
   code: 8
-  bucket_id: 1
+  unreachable_uuid: ac522f65-aa94-4134-9f64-51ee384f1a54
+  message: There is no active replicas in replicaset ac522f65-aa94-4134-9f64-51ee384f1a54
+  name: UNREACHABLE_REPLICASET
+  type: ShardingError
 ...
 -- Ok to work with correct replicasets.
 vshard.router.bucket_discovery(2).uuid
diff --git a/test/router/reroute_wrong_bucket.result b/test/router/reroute_wrong_bucket.result
index eda3bab..c7b980c 100644
--- a/test/router/reroute_wrong_bucket.result
+++ b/test/router/reroute_wrong_bucket.result
@@ -109,9 +109,11 @@ test_run:switch('router_1')
 vshard.router.call(100, 'read', 'customer_lookup', {1}, {timeout = 1})
 ---
 - null
-- type: ShardingError
-  bucket_id: 100
+- bucket_id: 100
   code: 9
+  type: ShardingError
+  name: NO_ROUTE_TO_BUCKET
+  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":100}"'
 ...
 -- Wait reconfiguration durigin timeout, if a replicaset was not
 -- found by bucket.destination from WRONG_BUCKET or
@@ -188,7 +190,9 @@ test_run:grep_log('router_1', 'please update configuration')
 ...
 err
 ---
-- {'type': 'ShardingError', 'bucket_id': 100, 'code': 1, 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54'}
+- {'bucket_id': 100, 'code': 1, 'type': 'ShardingError', 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54',
+  'message': 'WRONG_BUCKET: "{\"bucket_id\":100,\"destination\":\"ac522f65-aa94-4134-9f64-51ee384f1a54\"}"',
+  'name': 'WRONG_BUCKET'}
 ...
 --
 -- Now try again, but update configuration during call(). It must
diff --git a/test/router/router.result b/test/router/router.result
index 5f3ceca..6955b59 100644
--- a/test/router/router.result
+++ b/test/router/router.result
@@ -195,15 +195,19 @@ vshard.router.bucket_count()
 util.check_error(vshard.router.call, 1, 'read', 'echo', {123})
 ---
 - null
-- type: ShardingError
-  bucket_id: 1
+- bucket_id: 1
   code: 9
+  type: ShardingError
+  name: NO_ROUTE_TO_BUCKET
+  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":1}"'
 ...
 replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
 ---
-- type: ShardingError
-  bucket_id: 1
+- bucket_id: 1
   code: 9
+  type: ShardingError
+  name: NO_ROUTE_TO_BUCKET
+  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":1}"'
 ...
 vshard.router.bootstrap()
 ---
@@ -214,8 +218,9 @@ vshard.router.bootstrap()
 ---
 - null
 - type: ShardingError
-  code: 10
   message: Cluster is already bootstrapped
+  code: 10
+  name: NON_EMPTY
 ...
 --
 -- gh-108: negative bucket count on discovery.
@@ -312,9 +317,11 @@ util.check_error(vshard.router.call, 0, 'read', 'echo', {123})
 ...
 replicaset, err = vshard.router.bucket_discovery(0); return err == nil or err
 ---
-- type: ShardingError
-  bucket_id: 0
+- bucket_id: 0
   code: 9
+  type: ShardingError
+  name: NO_ROUTE_TO_BUCKET
+  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":0}"'
 ...
 replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
 ---
@@ -353,7 +360,9 @@ vshard.router.call(1, 'read', 'echo', {123})
 util.check_error(vshard.router.call, 1, 'write', 'echo', {123})
 ---
 - null
-- {'type': 'ShardingError', 'bucket_id': 1, 'code': 7, 'destination': '<replicaset_1>'}
+- {'bucket_id': 1, 'code': 7, 'type': 'ShardingError', 'destination': '<replicaset_1>',
+  'message': 'TRANSFER_IS_IN_PROGRESS: "{\"bucket_id\":1,\"destination\":\"<replicaset_1>\"}"',
+  'name': 'TRANSFER_IS_IN_PROGRESS'}
 ...
 test_run:cmd('switch storage_2_a')
 ---
@@ -397,10 +406,12 @@ test_run:cmd('stop server storage_2_a')
 util.check_error(vshard.router.call, 1, 'read', 'echo', {123})
 ---
 - null
-- type: ShardingError
-  unreachable_uuid: <replicaset_2>
+- bucket_id: 1
   code: 8
-  bucket_id: 1
+  unreachable_uuid: <replicaset_2>
+  message: There is no active replicas in replicaset <replicaset_2>
+  name: UNREACHABLE_REPLICASET
+  type: ShardingError
 ...
 vshard.router.buckets_info(0, 3)
 ---
@@ -420,9 +431,11 @@ test_run:cmd('start server storage_2_a')
 vshard.router.route(vshard.consts.DEFAULT_BUCKET_COUNT + 100)
 ---
 - null
-- type: ShardingError
-  bucket_id: 3100
+- bucket_id: 3100
   code: 9
+  type: ShardingError
+  name: NO_ROUTE_TO_BUCKET
+  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":3100}"'
 ...
 util.check_error(vshard.router.route, 'asdfg')
 ---
@@ -956,7 +969,8 @@ test_run:cmd("switch router_1")
 util.check_error(vshard.router.call, 1, 'write', 'echo', { 'hello world' })
 ---
 - null
-- {'type': 'ShardingError', 'code': 2, 'bucket_id': 1}
+- {'bucket_id': 1, 'code': 2, 'type': 'ShardingError', 'name': 'NON_MASTER', 'message': 'NON_MASTER:
+    "{\"bucket_id\":1}"'}
 ...
 -- Reconfigure router and test that the WRITE request does work
 vshard.router.cfg(cfg)
diff --git a/test/storage/storage.result b/test/storage/storage.result
index e93ad24..aee9477 100644
--- a/test/storage/storage.result
+++ b/test/storage/storage.result
@@ -594,9 +594,11 @@ vshard.storage.call(1, 'read', 'customer_lookup', {1})
 vshard.storage.call(100500, 'read', 'customer_lookup', {1})
 ---
 - null
-- type: ShardingError
-  bucket_id: 100500
+- bucket_id: 100500
   code: 1
+  type: ShardingError
+  name: WRONG_BUCKET
+  message: 'WRONG_BUCKET: "{\"bucket_id\":100500}"'
 ...
 --
 -- Test not existing space in bucket data.
diff --git a/test/unit/error.result b/test/unit/error.result
index a46fb0d..ed9904a 100644
--- a/test/unit/error.result
+++ b/test/unit/error.result
@@ -20,13 +20,13 @@ tostring(box_error)
 ---
 - '{"type":"ClientError","code":78,"message":"Timeout exceeded","trace":[{"file":"[C]","line":4294967295}]}'
 ...
-vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, {uuid = 'uuid', reason = 'reason'}, 'message 1 2 3')
+vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, 'uuid', 'reason')
 ---
 ...
 tostring(vshard_error)
 ---
-- '{"reason":"reason","code":11,"type":"ShardingError","uuid":"uuid","message":"message
-  1 2 3"}'
+- '{"reason":"reason","code":11,"type":"ShardingError","message":"Master of replicaset
+  uuid is unreachable: reason","uuid":"uuid","name":"UNREACHABLE_MASTER"}'
 ...
 log = require('log')
 ---
diff --git a/test/unit/error.test.lua b/test/unit/error.test.lua
index 4b5c20f..7b89f64 100644
--- a/test/unit/error.test.lua
+++ b/test/unit/error.test.lua
@@ -9,7 +9,7 @@ ok, err = pcall(box.error, box.error.TIMEOUT)
 box_error = lerror.box(err)
 tostring(box_error)
 
-vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, {uuid = 'uuid', reason = 'reason'}, 'message 1 2 3')
+vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, 'uuid', 'reason')
 tostring(vshard_error)
 
 log = require('log')
diff --git a/vshard/error.lua b/vshard/error.lua
index 8d26d11..1271d16 100644
--- a/vshard/error.lua
+++ b/vshard/error.lua
@@ -1,6 +1,111 @@
 local ffi = require('ffi')
 local json = require('json')
 
+--
+-- Error messages description.
+-- * name -- Key by which an error code can be retrieved from
+--   exprted `code` dictionary.
+-- * msg -- Error message which can cantain parameters described
+--   in `string.format` notation.
+-- * args -- Names of arguments passed while constructing an
+--   error. After constructed, an error-object contains provided
+--   arguments by the names specified in the field.
+--
+local error_message_template = {
+    [1] = {
+        name = 'WRONG_BUCKET',
+        args = {'bucket_id', 'destination'}
+    },
+    [2] = {
+        name = 'NON_MASTER',
+        args = {'bucket_id', 'destination'}
+    },
+    [3] = {
+        name = 'BUCKET_ALREADY_EXISTS',
+        args = {'bucket_id'}
+    },
+    [4] = {
+        name = 'NO_SUCH_REPLICASET',
+        args = {'replicaset_uuid'}
+    },
+    [5] = {
+        name = 'MOVE_TO_SELF',
+        args = {'replicaset_uuid', 'bucket_id'}
+    },
+    [6] = {
+         name = 'MISSING_MASTER',
+         msg = 'Master is not configured for replicaset %s',
+         args = {'replicaset_uuid'}
+    },
+    [7] = {
+        name = 'TRANSFER_IS_IN_PROGRESS',
+        args = {'bucket_id', 'destination'}
+    },
+    [8] = {
+        name = 'UNREACHABLE_REPLICASET',
+        msg = 'There is no active replicas in replicaset %s',
+        args = {'unreachable_uuid', 'bucket_id'}
+    },
+    [9] = {
+        name = 'NO_ROUTE_TO_BUCKET',
+        args = {'bucket_id', 'unreachable_uuid'}
+    },
+    [10] = {
+        name = 'NON_EMPTY',
+        msg = 'Cluster is already bootstrapped'
+    },
+    [11] = {
+        name = 'UNREACHABLE_MASTER',
+        msg = 'Master of replicaset %s is unreachable: %s',
+        args = {'uuid', 'reason'}
+    },
+    [12] = {
+        name = 'OUT_OF_SYNC',
+        msg = 'Replica is out of sync'
+    },
+    [13] = {
+        name = 'HIGH_REPLICATION_LAG',
+        msg = 'High replication lag: %f',
+        args = {'lag'}
+    },
+    [14] = {
+        name = 'UNREACHABLE_REPLICA',
+        msg = "Replica %s isn't active",
+        args = {'unreachable_uuid'}
+    },
+    [15] = {
+        name = 'LOW_REDUNDANCY',
+        msg = 'Only one replica is active'
+    },
+    [16] = {
+        name = 'INVALID_REBALANCING',
+        msg = 'Sending and receiving buckets at same time is not allowed'
+    },
+    [17] = {
+        name = 'SUBOPTIMAL_REPLICA',
+        msg = 'A current read replica in replicaset %s is not optimal'
+    },
+    [18] = {
+        name = 'UNKNOWN_BUCKETS',
+        msg = '%d buckets are not discovered',
+        arg = {'not_discovered_cnt'}
+    },
+    [19] = {
+        name = 'REPLICASET_IS_LOCKED',
+        msg = 'Replicaset is locked'
+    }
+}
+
+--
+-- User-visible error_name -> error_number dictionary.
+--
+local error_code = {}
+for code, err in pairs(error_message_template) do
+    assert(type(code) == 'number')
+    assert(error_code[err.name] == nil, "Dublicate error name")
+    error_code[err.name] = code
+end
+
 --
 -- There are 2 error types:
 -- * box_error - it is created on tarantool errors: client error,
@@ -11,19 +116,43 @@ local json = require('json')
 --   'ShardingError', one of codes below and optional
 --   message.
 --
-
 local function box_error(original_error)
     return setmetatable(original_error:unpack(), {__tostring = json.encode})
 end
 
-local function vshard_error(code, args, msg)
-    local ret = setmetatable({type = 'ShardingError', code = code,
-                              message = msg}, {__tostring = json.encode})
-    if args then
-        for k, v in pairs(args) do
-            ret[k] = v
-        end
+--
+-- Construct an vstard error.
+-- @param code Number, one of error_code constants.
+-- @param ... Arguments from `error_message_template` `arg` field.
+--        Caller have to pass at least as many arguments as
+--        `msg` field requires.
+-- @retval ShardingError object.
+--
+local function vshard_error(code, ...)
+    local format = error_message_template[code]
+    assert(format, 'Error message format not found.')
+    local args_passed_cnt = select('#', ...)
+    local args = format.args or {}
+    assert(#args >= args_passed_cnt,
+           string.format('Wrong number of arguments passed to %s error',
+                         format.name))
+    local ret = setmetatable({}, {__tostring = json.encode})
+    -- save error arguments
+    for i = 1, #args do
+        ret[args[i]] = select(i, ...)
+    end
+    local msg
+    if format.msg then
+        local ok
+        ok, msg = pcall(string.format, format.msg, ...)
+        assert(ok)
+    else
+        msg = string.format('%s: %s', format.name, json.encode(tostring(ret)))
     end
+    ret.type = 'ShardingError'
+    ret.code = code
+    ret.name = format.name
+    ret.message = msg
     return ret
 end
 
@@ -45,70 +174,6 @@ local function make_error(e)
     end
 end
 
-local error_code = {
-    WRONG_BUCKET = 1,
-    NON_MASTER = 2,
-    BUCKET_ALREADY_EXISTS = 3,
-    NO_SUCH_REPLICASET = 4,
-    MOVE_TO_SELF = 5,
-    MISSING_MASTER = 6,
-    TRANSFER_IS_IN_PROGRESS = 7,
-    UNREACHABLE_REPLICASET = 8,
-    NO_ROUTE_TO_BUCKET = 9,
-    NON_EMPTY = 10,
-    UNREACHABLE_MASTER = 11,
-    OUT_OF_SYNC = 12,
-    HIGH_REPLICATION_LAG = 13,
-    UNREACHABLE_REPLICA = 14,
-    LOW_REDUNDANCY = 15,
-    INVALID_REBALANCING = 16,
-    SUBOPTIMAL_REPLICA = 17,
-    UNKNOWN_BUCKETS = 18,
-    REPLICASET_IS_LOCKED = 19,
-}
-
-local error_message_template = {
-    [error_code.MISSING_MASTER] = {
-         name = 'MISSING_MASTER',
-         msg = 'Master is not configured for replicaset %s'
-    },
-    [error_code.UNREACHABLE_MASTER] = {
-        name = 'UNREACHABLE_MASTER',
-        msg = 'Master of replicaset %s is unreachable: %s'
-    },
-    [error_code.OUT_OF_SYNC] = {
-        name = 'OUT_OF_SYNC',
-        msg = 'Replica is out of sync'
-    },
-    [error_code.HIGH_REPLICATION_LAG] = {
-        name = 'HIGH_REPLICATION_LAG',
-        msg = 'High replication lag: %f'
-    },
-    [error_code.UNREACHABLE_REPLICA] = {
-        name = 'UNREACHABLE_REPLICA',
-        msg = "Replica %s isn't active"
-    },
-    [error_code.UNREACHABLE_REPLICASET] = {
-        name = 'UNREACHABLE_REPLICASET',
-        msg = 'There is no active replicas in replicaset %s'
-    },
-    [error_code.LOW_REDUNDANCY] = {
-        name = 'LOW_REDUNDANCY',
-        msg = 'Only one replica is active'
-    },
-    [error_code.INVALID_REBALANCING] = {
-        name = 'INVALID_REBALANCING',
-        msg = 'Sending and receiving buckets at same time is not allowed'
-    },
-    [error_code.SUBOPTIMAL_REPLICA] = {
-        name = 'SUBOPTIMAL_REPLICA',
-        msg = 'A current read replica in replicaset %s is not optimal'
-    },
-    [error_code.UNKNOWN_BUCKETS] = {
-        name = 'UNKNOWN_BUCKETS',
-        msg = '%d buckets are not discovered',
-    }
-}
 
 local function make_alert(code, ...)
     local format = error_message_template[code]
diff --git a/vshard/replicaset.lua b/vshard/replicaset.lua
index 7fcf2df..99f59aa 100644
--- a/vshard/replicaset.lua
+++ b/vshard/replicaset.lua
@@ -114,8 +114,8 @@ end
 local function replicaset_connect_master(replicaset)
     local master = replicaset.master
     if master == nil then
-        return nil, lerror.vshard(lerror.code.MASTER_IS_MISSING,
-                                  {replicaset_uuid = replicaset.uuid})
+        return nil, lerror.vshard(lerror.code.MISSING_MASTER,
+                                  replicaset.uuid)
     end
     return replicaset_connect_to_replica(replicaset, master)
 end
diff --git a/vshard/router/init.lua b/vshard/router/init.lua
index 42e9c86..95ee8b3 100644
--- a/vshard/router/init.lua
+++ b/vshard/router/init.lua
@@ -85,8 +85,7 @@ local function bucket_discovery(bucket_id)
         if last_err.type == 'ClientError' and
            last_err.code == box.error.NO_CONNECTION then
             err = lerror.vshard(lerror.code.UNREACHABLE_REPLICASET,
-                                {bucket_id = bucket_id,
-                                 unreachable_uuid = unreachable_uuid})
+                                unreachable_uuid, bucket_id)
         else
             err = lerror.make(last_err)
         end
@@ -97,9 +96,8 @@ local function bucket_discovery(bucket_id)
         -- bucket was found to be RECEIVING on one replicaset, and
         -- was not found on other replicasets (it was sent during
         -- discovery).
-        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET,
-                            {bucket_id = bucket_id,
-                             unreachable_uuid = unreachable_uuid})
+        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET, bucket_id,
+                            unreachable_uuid)
     end
 
     return nil, err
@@ -519,8 +517,7 @@ local function cluster_bootstrap()
             return nil, err
         end
         if count > 0 then
-            return nil, lerror.vshard(lerror.code.NON_EMPTY, {},
-                                      'Cluster is already bootstrapped')
+            return nil, lerror.vshard(lerror.code.NON_EMPTY)
         end
     end
     lreplicaset.calculate_etalon_balance(M.replicasets, M.total_bucket_count)
diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
index d5e7b57..2d38ff9 100644
--- a/vshard/storage/init.lua
+++ b/vshard/storage/init.lua
@@ -452,8 +452,7 @@ local function bucket_check_state(bucket_id, mode)
            mode == 'write' and bucket_is_writable(bucket))
 ::finish::
     return bucket, errcode and
-           lerror.vshard(errcode, {bucket_id = bucket_id,
-                                   destination = bucket and bucket.destination})
+           lerror.vshard(errcode, bucket_id, bucket and bucket.destination)
 end
 
 --
@@ -514,8 +513,7 @@ local function bucket_recv(bucket_id, from, data)
 
     local bucket = box.space._bucket:get({bucket_id})
     if bucket ~= nil then
-        return nil, lerror.vshard(lerror.code.BUCKET_ALREADY_EXISTS,
-                                  {bucket_id = bucket_id})
+        return nil, lerror.vshard(lerror.code.BUCKET_ALREADY_EXISTS, bucket_id)
     end
 
     box.begin()
@@ -719,14 +717,12 @@ local function bucket_send(bucket_id, destination)
     end
     local replicaset = M.replicasets[destination]
     if replicaset == nil then
-        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET,
-                                  {replicaset_uuid = destination})
+        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET, destination)
     end
 
     if destination == box.info.cluster.uuid then
-        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF,
-                                  {bucket_id = bucket_id,
-                                   replicaset_uuid = replicaset_uuid})
+        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, replicaset_uuid,
+                                  bucket_id)
     end
 
     local data = bucket_collect_internal(bucket_id)
@@ -1260,8 +1256,7 @@ end
 --
 local function rebalancer_apply_routes(routes)
     if is_this_replicaset_locked() then
-        return false, lerror.vshard(lerror.code.REPLICASET_IS_LOCKED, nil,
-                                    "Replicaset is locked");
+        return false, lerror.vshard(lerror.code.REPLICASET_IS_LOCKED);
     end
     assert(not rebalancing_is_in_progress())
     -- Can not apply routes here because of gh-946 in tarantool
-- 
2.14.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] [PATCH 3/3] Add error messages
  2018-06-06 15:57 [tarantool-patches] [PATCH 0/3][vshard] Add error messages AKhatskevich
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 1/3] Fix test on bucket_transferring error AKhatskevich
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 2/3] Refactor error reporting system AKhatskevich
@ 2018-06-06 15:57 ` AKhatskevich
  2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
  2018-06-07 12:22 ` [tarantool-patches] Re: [PATCH 0/3][vshard] " Vladislav Shpilevoy
  3 siblings, 1 reply; 11+ messages in thread
From: AKhatskevich @ 2018-06-06 15:57 UTC (permalink / raw)
  To: tarantool-patches, v.shpilevoy

Add error message to each `error_message_template`.
This change required to change arguments of some errors to make
them more informative.

Closes #100
---
 test/router/reroute_wrong_bucket.result |  7 ++++---
 test/router/router.result               | 16 +++++++++-------
 test/storage/storage.result             |  3 ++-
 vshard/error.lua                        | 15 +++++++++++----
 vshard/router/init.lua                  |  3 +--
 vshard/storage/init.lua                 | 28 ++++++++++++++++++++--------
 6 files changed, 47 insertions(+), 25 deletions(-)

diff --git a/test/router/reroute_wrong_bucket.result b/test/router/reroute_wrong_bucket.result
index c7b980c..75a1c5a 100644
--- a/test/router/reroute_wrong_bucket.result
+++ b/test/router/reroute_wrong_bucket.result
@@ -113,7 +113,7 @@ vshard.router.call(100, 'read', 'customer_lookup', {1}, {timeout = 1})
   code: 9
   type: ShardingError
   name: NO_ROUTE_TO_BUCKET
-  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":100}"'
+  message: Bucket 100 cannot be found. Is rebalancing in progress?
 ...
 -- Wait reconfiguration durigin timeout, if a replicaset was not
 -- found by bucket.destination from WRONG_BUCKET or
@@ -190,8 +190,9 @@ test_run:grep_log('router_1', 'please update configuration')
 ...
 err
 ---
-- {'bucket_id': 100, 'code': 1, 'type': 'ShardingError', 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54',
-  'message': 'WRONG_BUCKET: "{\"bucket_id\":100,\"destination\":\"ac522f65-aa94-4134-9f64-51ee384f1a54\"}"',
+- {'bucket_id': 100, 'reason': 'bucket moving to ac522f65-aa94-4134-9f64-51ee384f1a54',
+  'code': 1, 'type': 'ShardingError', 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54',
+  'message': 'Cannot perform action with bucket 100, reason: bucket moving to ac522f65-aa94-4134-9f64-51ee384f1a54',
   'name': 'WRONG_BUCKET'}
 ...
 --
diff --git a/test/router/router.result b/test/router/router.result
index 6955b59..dab71f2 100644
--- a/test/router/router.result
+++ b/test/router/router.result
@@ -199,7 +199,7 @@ util.check_error(vshard.router.call, 1, 'read', 'echo', {123})
   code: 9
   type: ShardingError
   name: NO_ROUTE_TO_BUCKET
-  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":1}"'
+  message: Bucket 1 cannot be found. Is rebalancing in progress?
 ...
 replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
 ---
@@ -207,7 +207,7 @@ replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
   code: 9
   type: ShardingError
   name: NO_ROUTE_TO_BUCKET
-  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":1}"'
+  message: Bucket 1 cannot be found. Is rebalancing in progress?
 ...
 vshard.router.bootstrap()
 ---
@@ -321,7 +321,7 @@ replicaset, err = vshard.router.bucket_discovery(0); return err == nil or err
   code: 9
   type: ShardingError
   name: NO_ROUTE_TO_BUCKET
-  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":0}"'
+  message: Bucket 0 cannot be found. Is rebalancing in progress?
 ...
 replicaset, err = vshard.router.bucket_discovery(1); return err == nil or err
 ---
@@ -361,7 +361,7 @@ util.check_error(vshard.router.call, 1, 'write', 'echo', {123})
 ---
 - null
 - {'bucket_id': 1, 'code': 7, 'type': 'ShardingError', 'destination': '<replicaset_1>',
-  'message': 'TRANSFER_IS_IN_PROGRESS: "{\"bucket_id\":1,\"destination\":\"<replicaset_1>\"}"',
+  'message': 'Bucket 1 is transferring to replicaset <replicaset_1>',
   'name': 'TRANSFER_IS_IN_PROGRESS'}
 ...
 test_run:cmd('switch storage_2_a')
@@ -435,7 +435,7 @@ vshard.router.route(vshard.consts.DEFAULT_BUCKET_COUNT + 100)
   code: 9
   type: ShardingError
   name: NO_ROUTE_TO_BUCKET
-  message: 'NO_ROUTE_TO_BUCKET: "{\"bucket_id\":3100}"'
+  message: Bucket 3100 cannot be found. Is rebalancing in progress?
 ...
 util.check_error(vshard.router.route, 'asdfg')
 ---
@@ -969,8 +969,10 @@ test_run:cmd("switch router_1")
 util.check_error(vshard.router.call, 1, 'write', 'echo', { 'hello world' })
 ---
 - null
-- {'bucket_id': 1, 'code': 2, 'type': 'ShardingError', 'name': 'NON_MASTER', 'message': 'NON_MASTER:
-    "{\"bucket_id\":1}"'}
+- {'code': 2, 'replica_uuid': '1e02ae8a-afc0-4e91-ba34-843a356b8ed7', 'type': 'ShardingError',
+  'replicaset_uuid': '<replicaset_2>', 'message': 'Replica 1e02ae8a-afc0-4e91-ba34-843a356b8ed7
+    is not a master for replicaset <replicaset_2> anymore',
+  'name': 'NON_MASTER'}
 ...
 -- Reconfigure router and test that the WRITE request does work
 vshard.router.cfg(cfg)
diff --git a/test/storage/storage.result b/test/storage/storage.result
index aee9477..1258c9b 100644
--- a/test/storage/storage.result
+++ b/test/storage/storage.result
@@ -595,10 +595,11 @@ vshard.storage.call(100500, 'read', 'customer_lookup', {1})
 ---
 - null
 - bucket_id: 100500
+  reason: Not found
   code: 1
   type: ShardingError
   name: WRONG_BUCKET
-  message: 'WRONG_BUCKET: "{\"bucket_id\":100500}"'
+  message: 'Cannot perform action with bucket 100500, reason: Not found'
 ...
 --
 -- Test not existing space in bucket data.
diff --git a/vshard/error.lua b/vshard/error.lua
index 1271d16..8785695 100644
--- a/vshard/error.lua
+++ b/vshard/error.lua
@@ -14,23 +14,28 @@ local json = require('json')
 local error_message_template = {
     [1] = {
         name = 'WRONG_BUCKET',
-        args = {'bucket_id', 'destination'}
+        msg = 'Cannot perform action with bucket %d, reason: %s',
+        args = {'bucket_id', 'reason', 'destination'}
     },
     [2] = {
         name = 'NON_MASTER',
-        args = {'bucket_id', 'destination'}
+        msg = 'Replica %s is not a master for replicaset %s anymore',
+        args = {'replica_uuid', 'replicaset_uuid'}
     },
     [3] = {
         name = 'BUCKET_ALREADY_EXISTS',
+        msg = 'Bucket %d already exists',
         args = {'bucket_id'}
     },
     [4] = {
         name = 'NO_SUCH_REPLICASET',
+        msg = 'Replicaset %s not found',
         args = {'replicaset_uuid'}
     },
     [5] = {
         name = 'MOVE_TO_SELF',
-        args = {'replicaset_uuid', 'bucket_id'}
+        msg = 'Cannot move: bucket %d is already on replicaset %s',
+        args = {'bucket_id', 'replicaset_uuid'}
     },
     [6] = {
          name = 'MISSING_MASTER',
@@ -39,6 +44,7 @@ local error_message_template = {
     },
     [7] = {
         name = 'TRANSFER_IS_IN_PROGRESS',
+        msg = 'Bucket %d is transferring to replicaset %s',
         args = {'bucket_id', 'destination'}
     },
     [8] = {
@@ -48,7 +54,8 @@ local error_message_template = {
     },
     [9] = {
         name = 'NO_ROUTE_TO_BUCKET',
-        args = {'bucket_id', 'unreachable_uuid'}
+        msg = 'Bucket %d cannot be found. Is rebalancing in progress?',
+        args = {'bucket_id'}
     },
     [10] = {
         name = 'NON_EMPTY',
diff --git a/vshard/router/init.lua b/vshard/router/init.lua
index 95ee8b3..21093e5 100644
--- a/vshard/router/init.lua
+++ b/vshard/router/init.lua
@@ -96,8 +96,7 @@ local function bucket_discovery(bucket_id)
         -- bucket was found to be RECEIVING on one replicaset, and
         -- was not found on other replicasets (it was sent during
         -- discovery).
-        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET, bucket_id,
-                            unreachable_uuid)
+        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET, bucket_id)
     end
 
     return nil, err
diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
index 2d38ff9..cd02657 100644
--- a/vshard/storage/init.lua
+++ b/vshard/storage/init.lua
@@ -428,31 +428,43 @@ local function bucket_check_state(bucket_id, mode)
     assert(mode == 'read' or mode == 'write')
     local bucket = box.space._bucket:get({bucket_id})
     local errcode = nil
+    local reason = nil
     if not bucket then
         errcode = lerror.code.WRONG_BUCKET
-        goto finish
+        reason = 'Not found'
+        goto wrong_bucket
     elseif mode == 'read' then
         if not bucket_is_readable(bucket) then
             errcode = lerror.code.WRONG_BUCKET
-            goto finish
+            reason = 'read prohibited'
+            goto wrong_bucket
         end
     elseif not bucket_is_writable(bucket) then
         if bucket_is_transfer_in_progress(bucket) then
             errcode = lerror.code.TRANSFER_IS_IN_PROGRESS
+            return bucket, errcode and
+                   lerror.vshard(errcode, bucket_id, bucket.destination)
         else
             errcode = lerror.code.WRONG_BUCKET
+            reason = 'write prohibited'
+            goto wrong_bucket
         end
-        goto finish
     elseif M.this_replicaset.master ~= M.this_replica then
         errcode = lerror.code.NON_MASTER
-        goto finish
+        return bucket, errcode and
+               lerror.vshard(errcode, M.this_replica.uuid,
+                             M.this_replicaset.uuid)
     end
     assert(not errcode)
     assert(mode == 'read' and bucket_is_readable(bucket) or
            mode == 'write' and bucket_is_writable(bucket))
-::finish::
+::wrong_bucket::
+    if bucket and bucket.destination then
+        reason = "bucket moving to " .. bucket.destination
+    end
     return bucket, errcode and
-           lerror.vshard(errcode, bucket_id, bucket and bucket.destination)
+           lerror.vshard(errcode, bucket_id, reason,
+                         bucket and bucket.destination)
 end
 
 --
@@ -721,8 +733,8 @@ local function bucket_send(bucket_id, destination)
     end
 
     if destination == box.info.cluster.uuid then
-        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, replicaset_uuid,
-                                  bucket_id)
+        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, bucket_id,
+                                  replicaset_uuid)
     end
 
     local data = bucket_collect_internal(bucket_id)
-- 
2.14.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 0/3][vshard] Add error messages
  2018-06-06 15:57 [tarantool-patches] [PATCH 0/3][vshard] Add error messages AKhatskevich
                   ` (2 preceding siblings ...)
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 3/3] Add error messages AKhatskevich
@ 2018-06-07 12:22 ` Vladislav Shpilevoy
  2018-06-07 13:16   ` Alex Khatskevich
  3 siblings, 1 reply; 11+ messages in thread
From: Vladislav Shpilevoy @ 2018-06-07 12:22 UTC (permalink / raw)
  To: tarantool-patches, AKhatskevich

Hello. Thanks for the patchset!

On 06/06/2018 18:57, AKhatskevich wrote:
> Branch: https://github.com/tarantool/vshard/tree/kh/gh-100-error-msg-wo-extra-data
> Issue: https://github.com/tarantool/vshard/issues/100
> 
> *** BLURB HERE ***

Why do I see this placeholder here? You should write here a short
description of the patchset. Please, answer on this email with the
description.

> 
> AKhatskevich (3):
>    Fix test on bucket_transferring error
>    Refactor error reporting system
>    Add error messages
> 
>   test/misc/check_uuid_on_connect.result  |   8 +-
>   test/router/reroute_wrong_bucket.result |  11 +-
>   test/router/router.result               |  54 +++++---
>   test/router/router.test.lua             |   4 +-
>   test/storage/storage.result             |   7 +-
>   test/unit/error.result                  |   6 +-
>   test/unit/error.test.lua                |   2 +-
>   vshard/error.lua                        | 216 +++++++++++++++++++++-----------
>   vshard/replicaset.lua                   |   4 +-
>   vshard/router/init.lua                  |  10 +-
>   vshard/storage/init.lua                 |  39 +++---
>   11 files changed, 231 insertions(+), 130 deletions(-)
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 2/3] Refactor error reporting system
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 2/3] Refactor error reporting system AKhatskevich
@ 2018-06-07 12:22   ` Vladislav Shpilevoy
  2018-06-07 16:13     ` Alex Khatskevich
  0 siblings, 1 reply; 11+ messages in thread
From: Vladislav Shpilevoy @ 2018-06-07 12:22 UTC (permalink / raw)
  To: tarantool-patches, AKhatskevich

Thanks for the patch! See 12 comments below.

On 06/06/2018 18:57, AKhatskevich wrote:
> This commit applies stricter rules on error reporting:
>   * error may has only arguments specified in `args` field of
>     `error_message_template`
>   * arguments may be used in error message
>   * arguments are saved in error object by names from `args`
> 
> Part of #100
> ---
>   test/misc/check_uuid_on_connect.result  |   8 +-
>   test/router/reroute_wrong_bucket.result |  10 +-
>   test/router/router.result               |  42 ++++---
>   test/storage/storage.result             |   6 +-
>   test/unit/error.result                  |   6 +-
>   test/unit/error.test.lua                |   2 +-
>   vshard/error.lua                        | 209 +++++++++++++++++++++-----------
>   vshard/replicaset.lua                   |   4 +-
>   vshard/router/init.lua                  |  11 +-
>   vshard/storage/init.lua                 |  17 +--
>   10 files changed, 197 insertions(+), 118 deletions(-)
> 
> diff --git a/vshard/error.lua b/vshard/error.lua
> index 8d26d11..1271d16 100644
> --- a/vshard/error.lua
> +++ b/vshard/error.lua
> @@ -1,6 +1,111 @@
>   local ffi = require('ffi')
>   local json = require('json')
>   
> +--
> +-- Error messages description.
> +-- * name -- Key by which an error code can be retrieved from
> +--   exprted `code` dictionary.

1. exprted -> ?

> +-- * msg -- Error message which can cantain parameters described

2. cantain -> contain. And it must contain. Not can.

> +--   in `string.format` notation.
> +-- * args -- Names of arguments passed while constructing an
> +--   error. After constructed, an error-object contains provided
> +--   arguments by the names specified in the field.
> +--
> +local error_message_template = {
> +    [1] = {
> +        name = 'WRONG_BUCKET',
> +        args = {'bucket_id', 'destination'}
> +    },
> +    [2] = {
> +        name = 'NON_MASTER',
> +        args = {'bucket_id', 'destination'}
> +    },
> +    [3] = {
> +        name = 'BUCKET_ALREADY_EXISTS',
> +        args = {'bucket_id'}
> +    },
> +    [4] = {
> +        name = 'NO_SUCH_REPLICASET',
> +        args = {'replicaset_uuid'}
> +    },
> +    [5] = {
> +        name = 'MOVE_TO_SELF',
> +        args = {'replicaset_uuid', 'bucket_id'}
> +    },
> +    [6] = {
> +         name = 'MISSING_MASTER',
> +         msg = 'Master is not configured for replicaset %s',
> +         args = {'replicaset_uuid'}
> +    },
> +    [7] = {
> +        name = 'TRANSFER_IS_IN_PROGRESS',
> +        args = {'bucket_id', 'destination'}
> +    },
> +    [8] = {
> +        name = 'UNREACHABLE_REPLICASET',
> +        msg = 'There is no active replicas in replicaset %s',
> +        args = {'unreachable_uuid', 'bucket_id'}
> +    },
> +    [9] = {
> +        name = 'NO_ROUTE_TO_BUCKET',
> +        args = {'bucket_id', 'unreachable_uuid'}

3. You have found that uuid is always nil for NO_ROUTE_TO_BUCKET.
Why do you need it in args?

> @@ -11,19 +116,43 @@ local json = require('json')
>   --   'ShardingError', one of codes below and optional
>   --   message.
>   --
> -

4. Garbage diff. And this empty line was put here deliberately.
The comment refers to both box_error and vshard_error.

>   local function box_error(original_error)
>       return setmetatable(original_error:unpack(), {__tostring = json.encode})
>   end
>   
> -local function vshard_error(code, args, msg)
> -    local ret = setmetatable({type = 'ShardingError', code = code,
> -                              message = msg}, {__tostring = json.encode})
> -    if args then
> -        for k, v in pairs(args) do
> -            ret[k] = v
> -        end
> +--
> +-- Construct an vstard error.

5. vstard -> vshard.

> +-- @param code Number, one of error_code constants.
> +-- @param ... Arguments from `error_message_template` `arg` field.

6. arg -> args. Error objects above has args attribute.

> +--        Caller have to pass at least as many arguments as
> +--        `msg` field requires.
> +-- @retval ShardingError object.
> +--
> +local function vshard_error(code, ...)
> +    local format = error_message_template[code]
> +    assert(format, 'Error message format not found.')
> +    local args_passed_cnt = select('#', ...)
> +    local args = format.args or {}
> +    assert(#args >= args_passed_cnt,
> +           string.format('Wrong number of arguments passed to %s error',
> +                         format.name))> +    local ret = setmetatable({}, {__tostring = json.encode})
> +    -- save error arguments

7. Please, start a sentence with capital letter and finish with dot.

> +    for i = 1, #args do
> +        ret[args[i]] = select(i, ...)
> +    end
> +    local msg
> +    if format.msg then
> +        local ok
> +        ok, msg = pcall(string.format, format.msg, ...)
> +        assert(ok)

8. Why? Either the pcall returns an error and you fail in the assert,
or simple unprotected string.format() fails. No difference. Just to
simple string.format().

9. You do not need local msg here.

> +    else
> +        msg = string.format('%s: %s', format.name, json.encode(tostring(ret)))

10. Why do you need encode(tostring())? Ret already has __tostring = json.encode,
so just do this:

     string.format('%s: %s', format.name, ret)

Diff is below. I did not run the tests. Please, apply and fix the tests if
needed.

@@ -141,18 +141,14 @@ local function vshard_error(code, ...)
      for i = 1, #args do
          ret[args[i]] = select(i, ...)
      end
-    local msg
      if format.msg then
-        local ok
-        ok, msg = pcall(string.format, format.msg, ...)
-        assert(ok)
+        ret.message = string.format(format.msg, ...)
      else
-        msg = string.format('%s: %s', format.name, json.encode(tostring(ret)))
+        ret.message = string.format('%s: %s', format.name, ret)
      end
      ret.type = 'ShardingError'
      ret.code = code
      ret.name = format.name
-    ret.message = msg
      return ret
  end

> diff --git a/vshard/router/init.lua b/vshard/router/init.lua
> index 42e9c86..95ee8b3 100644
> --- a/vshard/router/init.lua
> +++ b/vshard/router/init.lua
> @@ -97,9 +96,8 @@ local function bucket_discovery(bucket_id)
>           -- bucket was found to be RECEIVING on one replicaset, and
>           -- was not found on other replicasets (it was sent during
>           -- discovery).
> -        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET,
> -                            {bucket_id = bucket_id,
> -                             unreachable_uuid = unreachable_uuid})
> +        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET, bucket_id,
> +                            unreachable_uuid)

11. Unreachable uuid is always nil as we have found.

>       end
>   
>       return nil, err
> @@ -719,14 +717,12 @@ local function bucket_send(bucket_id, destination)
>       end
>       local replicaset = M.replicasets[destination]
>       if replicaset == nil then
> -        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET,
> -                                  {replicaset_uuid = destination})
> +        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET, destination)
>       end

12. NO_SUCH_REPLICASET has two arguments. And you have assert(#args >= args_passed_cnt),
that has not been failed. It means, that bucket_send has no a test on sending to
non-existing replicaset. Please,
     * add a test on bucket_send to non-existing replicaset;
     * add unit tests on error building.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 3/3] Add error messages
  2018-06-06 15:57 ` [tarantool-patches] [PATCH 3/3] Add error messages AKhatskevich
@ 2018-06-07 12:22   ` Vladislav Shpilevoy
  2018-06-07 16:12     ` Alex Khatskevich
  0 siblings, 1 reply; 11+ messages in thread
From: Vladislav Shpilevoy @ 2018-06-07 12:22 UTC (permalink / raw)
  To: tarantool-patches, AKhatskevich

Thanks for the patch! See 7 comments below.

On 06/06/2018 18:57, AKhatskevich wrote:
> Add error message to each `error_message_template`.
> This change required to change arguments of some errors to make
> them more informative.
> 
> Closes #100
> ---
>   test/router/reroute_wrong_bucket.result |  7 ++++---
>   test/router/router.result               | 16 +++++++++-------
>   test/storage/storage.result             |  3 ++-
>   vshard/error.lua                        | 15 +++++++++++----
>   vshard/router/init.lua                  |  3 +--
>   vshard/storage/init.lua                 | 28 ++++++++++++++++++++--------
>   6 files changed, 47 insertions(+), 25 deletions(-)
> 
> diff --git a/test/router/reroute_wrong_bucket.result b/test/router/reroute_wrong_bucket.result
> index c7b980c..75a1c5a 100644
> --- a/test/router/reroute_wrong_bucket.result
> +++ b/test/router/reroute_wrong_bucket.result
> @@ -190,8 +190,9 @@ test_run:grep_log('router_1', 'please update configuration')
>   ...
>   err
>   ---
> -- {'bucket_id': 100, 'code': 1, 'type': 'ShardingError', 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54',
> -  'message': 'WRONG_BUCKET: "{\"bucket_id\":100,\"destination\":\"ac522f65-aa94-4134-9f64-51ee384f1a54\"}"',
> +- {'bucket_id': 100, 'reason': 'bucket moving to ac522f65-aa94-4134-9f64-51ee384f1a54',
> +  'code': 1, 'type': 'ShardingError', 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54',
> +  'message': 'Cannot perform action with bucket 100, reason: bucket moving to ac522f65-aa94-4134-9f64-51ee384f1a54',

1. WRONG_BUCKET should not expose 'reason' as an attribute.

> diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
> index 2d38ff9..cd02657 100644
> --- a/vshard/storage/init.lua
> +++ b/vshard/storage/init.lua
> @@ -428,31 +428,43 @@ local function bucket_check_state(bucket_id, mode)
>       assert(mode == 'read' or mode == 'write')
>       local bucket = box.space._bucket:get({bucket_id})
>       local errcode = nil
> +    local reason = nil
>       if not bucket then
>           errcode = lerror.code.WRONG_BUCKET
> -        goto finish
> +        reason = 'Not found'
> +        goto wrong_bucket
>       elseif mode == 'read' then
>           if not bucket_is_readable(bucket) then
>               errcode = lerror.code.WRONG_BUCKET
> -            goto finish
> +            reason = 'read prohibited'

2. 'is prohibited'. No?

> +            goto wrong_bucket
>           end
>       elseif not bucket_is_writable(bucket) then
>           if bucket_is_transfer_in_progress(bucket) then
>               errcode = lerror.code.TRANSFER_IS_IN_PROGRESS
> +            return bucket, errcode and
> +                   lerror.vshard(errcode, bucket_id, bucket.destination)

3. How could 'errcode' be nil, if you had set it one line above?

>           else
>               errcode = lerror.code.WRONG_BUCKET
> +            reason = 'write prohibited'

4. Same as 2.

> +            goto wrong_bucket
>           end
> -        goto finish
>       elseif M.this_replicaset.master ~= M.this_replica then
>           errcode = lerror.code.NON_MASTER
> -        goto finish
> +        return bucket, errcode and
> +               lerror.vshard(errcode, M.this_replica.uuid,
> +                             M.this_replicaset.uuid)

5. Same as 3.

>       end
>       assert(not errcode)
>       assert(mode == 'read' and bucket_is_readable(bucket) or
>              mode == 'write' and bucket_is_writable(bucket))
> -::finish::
> +::wrong_bucket::

6. The code below is executed both on error and on success. But
label is named 'wrong_bucket'. It is not correct. On success
path it is guaranteed that bucket ~= nil.

7. Now msg is set for each error, but you still have checks in
vshard_error like 'if format.msg then'.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 0/3][vshard] Add error messages
  2018-06-07 12:22 ` [tarantool-patches] Re: [PATCH 0/3][vshard] " Vladislav Shpilevoy
@ 2018-06-07 13:16   ` Alex Khatskevich
  0 siblings, 0 replies; 11+ messages in thread
From: Alex Khatskevich @ 2018-06-07 13:16 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tarantool-patches


> Why do I see this placeholder here? You should write here a short
> description of the patchset. Please, answer on this email with the
> description.
The aim of this patchset is to make error messages more readable for a user.

It consists of three commits:
1. Fix test on bucket_transferring error
2. Refactor error reporting system
3. Add error messages

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 3/3] Add error messages
  2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
@ 2018-06-07 16:12     ` Alex Khatskevich
  2018-06-07 18:44       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 11+ messages in thread
From: Alex Khatskevich @ 2018-06-07 16:12 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tarantool-patches


> 1. WRONG_BUCKET should not expose 'reason' as an attribute.
Discussed verbally. Let it just be exposed and useless and undocumented.
> 2. 'is prohibited'. No?
I just wanted short error messaged.
Fixed.
> 3. How could 'errcode' be nil, if you had set it one line above?
Thanks
> 4. Same as 2.
Fixed along with
"bucket moving to " -> "bucket moving to "
> 5. Same as 3.
Fixed
>
>>       end
>>       assert(not errcode)
>>       assert(mode == 'read' and bucket_is_readable(bucket) or
>>              mode == 'write' and bucket_is_writable(bucket))
>> -::finish::
>> +::wrong_bucket::
>
> 6. The code below is executed both on error and on success. But
> label is named 'wrong_bucket'. It is not correct. On success
> path it is guaranteed that bucket ~= nil.
Renamed back to `finish`. IMHO `wrong_bucket` suited well here.
> 7. Now msg is set for each error, but you still have checks in
> vshard_error like 'if format.msg then'.
Fixed

New diff:

commit 057e640c25dfaab8ccafe3740cddaee27b2c7bc9
Author: AKhatskevich <avkhatskevich@tarantool.org>
Date:   Wed Jun 6 13:28:25 2018 +0300

     Add error messages

     Add error message to each `error_message_template`.
     This change required to change arguments of some errors to make
     them more informative.

     Closes #100

diff --git a/test/router/reroute_wrong_bucket.result 
b/test/router/reroute_wrong_bucket.result
index f8021f2..58bef8d 100644
--- a/test/router/reroute_wrong_bucket.result
+++ b/test/router/reroute_wrong_bucket.result
@@ -112,7 +112,7 @@ vshard.router.call(100, 'read', 'customer_lookup', 
{1}, {timeout = 1})
  - bucket_id: 100
    code: 9
    type: ShardingError
-  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":100}'
+  message: Bucket 100 cannot be found. Is rebalancing in progress?
    name: NO_ROUTE_TO_BUCKET
  ...
  -- Wait reconfiguration durigin timeout, if a replicaset was not
@@ -190,8 +190,10 @@ test_run:grep_log('router_1', 'please update 
configuration')
  ...
  err
  ---
-- {'bucket_id': 100, 'code': 1, 'type': 'ShardingError', 'destination': 
'ac522f65-aa94-4134-9f64-51ee384f1a54',
-  'name': 'WRONG_BUCKET', 'message': 'WRONG_BUCKET: 
{"bucket_id":100,"destination":"ac522f65-aa94-4134-9f64-51ee384f1a54"}'}
+- {'bucket_id': 100, 'reason': 'bucket is moving to 
ac522f65-aa94-4134-9f64-51ee384f1a54',
+  'code': 1, 'destination': 'ac522f65-aa94-4134-9f64-51ee384f1a54', 
'type': 'ShardingError',
+  'name': 'WRONG_BUCKET', 'message': 'Cannot perform action with bucket 
100, reason:
+    bucket is moving to ac522f65-aa94-4134-9f64-51ee384f1a54'}
  ...
  --
  -- Now try again, but update configuration during call(). It must
diff --git a/test/router/router.result b/test/router/router.result
index 5d99255..2ee1bff 100644
--- a/test/router/router.result
+++ b/test/router/router.result
@@ -198,7 +198,7 @@ util.check_error(vshard.router.call, 1, 'read', 
'echo', {123})
  - bucket_id: 1
    code: 9
    type: ShardingError
-  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":1}'
+  message: Bucket 1 cannot be found. Is rebalancing in progress?
    name: NO_ROUTE_TO_BUCKET
  ...
  replicaset, err = vshard.router.bucket_discovery(1); return err == nil 
or err
@@ -206,7 +206,7 @@ replicaset, err = vshard.router.bucket_discovery(1); 
return err == nil or err
  - bucket_id: 1
    code: 9
    type: ShardingError
-  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":1}'
+  message: Bucket 1 cannot be found. Is rebalancing in progress?
    name: NO_ROUTE_TO_BUCKET
  ...
  vshard.router.bootstrap()
@@ -320,7 +320,7 @@ replicaset, err = vshard.router.bucket_discovery(0); 
return err == nil or err
  - bucket_id: 0
    code: 9
    type: ShardingError
-  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":0}'
+  message: Bucket 0 cannot be found. Is rebalancing in progress?
    name: NO_ROUTE_TO_BUCKET
  ...
  replicaset, err = vshard.router.bucket_discovery(1); return err == nil 
or err
@@ -361,7 +361,8 @@ util.check_error(vshard.router.call, 1, 'write', 
'echo', {123})
  ---
  - null
  - {'bucket_id': 1, 'code': 7, 'type': 'ShardingError', 'destination': 
'<replicaset_1>',
-  'name': 'TRANSFER_IS_IN_PROGRESS', 'message': 
'TRANSFER_IS_IN_PROGRESS: {"bucket_id":1,"destination":"<replicaset_1>"}'}
+  'name': 'TRANSFER_IS_IN_PROGRESS', 'message': 'Bucket 1 is 
transferring to replicaset
+    <replicaset_1>'}
  ...
  test_run:cmd('switch storage_2_a')
  ---
@@ -433,7 +434,7 @@ 
vshard.router.route(vshard.consts.DEFAULT_BUCKET_COUNT + 100)
  - bucket_id: 3100
    code: 9
    type: ShardingError
-  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":3100}'
+  message: Bucket 3100 cannot be found. Is rebalancing in progress?
    name: NO_ROUTE_TO_BUCKET
  ...
  util.check_error(vshard.router.route, 'asdfg')
@@ -968,8 +969,10 @@ test_run:cmd("switch router_1")
  util.check_error(vshard.router.call, 1, 'write', 'echo', { 'hello 
world' })
  ---
  - null
-- {'bucket_id': 1, 'code': 2, 'type': 'ShardingError', 'message': 
'NON_MASTER: {"bucket_id":1}',
-  'name': 'NON_MASTER'}
+- {'replica_uuid': '1e02ae8a-afc0-4e91-ba34-843a356b8ed7', 
'replicaset_uuid': '<replicaset_2>',
+  'type': 'ShardingError', 'message': 'Replica 
1e02ae8a-afc0-4e91-ba34-843a356b8ed7
+    is not a master for replicaset <replicaset_2> anymore',
+  'name': 'NON_MASTER', 'code': 2}
  ...
  -- Reconfigure router and test that the WRITE request does work
  vshard.router.cfg(cfg)
diff --git a/test/storage/storage.result b/test/storage/storage.result
index 51492a2..d0bf792 100644
--- a/test/storage/storage.result
+++ b/test/storage/storage.result
@@ -595,9 +595,10 @@ vshard.storage.call(100500, 'read', 
'customer_lookup', {1})
  ---
  - null
  - bucket_id: 100500
+  reason: Not found
    code: 1
    type: ShardingError
-  message: 'WRONG_BUCKET: {"bucket_id":100500}'
+  message: 'Cannot perform action with bucket 100500, reason: Not found'
    name: WRONG_BUCKET
  ...
  --
@@ -624,7 +625,7 @@ vshard.storage.bucket_send(1, 'unknown uuid')
    type: ShardingError
    name: NO_SUCH_REPLICASET
    replicaset_uuid: unknown uuid
-  message: 'NO_SUCH_REPLICASET: {"replicaset_uuid":"unknown uuid"}'
+  message: Replicaset unknown uuid not found
  ...
  -- Successful transfer.
  vshard.storage.bucket_send(1, replicaset2_uuid)
diff --git a/test/unit/error.result b/test/unit/error.result
index 74571ca..d1f04d0 100644
--- a/test/unit/error.result
+++ b/test/unit/error.result
@@ -41,14 +41,22 @@ test_run:grep_log('default', 
'"reason":"reason","code":11,"type":"ShardingError"
  --
  -- Part of gh-100: check `error.vshard`.
  --
-lerror.vshard(lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+lerror.vshard(lerror.code.WRONG_BUCKET, 1, 'arg2')
  ---
-- bucket_id: arg1
+- bucket_id: 1
+  reason: arg2
    code: 1
    type: ShardingError
+  message: 'Cannot perform action with bucket 1, reason: arg2'
    name: WRONG_BUCKET
-  message: 'WRONG_BUCKET: {"bucket_id":"arg1","destination":"arg2"}'
-  destination: arg2
+...
+-- Pass an arg of a wrong type.
+ok, res = pcall(lerror.vshard, lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+---
+...
+res:match('bad argument #2.*')
+---
+- 'bad argument #2 to ''format'' (number expected, got string)'
  ...
  -- Pass less args than msg requires.
  ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER)
diff --git a/test/unit/error.test.lua b/test/unit/error.test.lua
index 7496982..ef9d5cd 100644
--- a/test/unit/error.test.lua
+++ b/test/unit/error.test.lua
@@ -19,7 +19,10 @@ test_run:grep_log('default', 
'"reason":"reason","code":11,"type":"ShardingError"
  --
  -- Part of gh-100: check `error.vshard`.
  --
-lerror.vshard(lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+lerror.vshard(lerror.code.WRONG_BUCKET, 1, 'arg2')
+-- Pass an arg of a wrong type.
+ok, res = pcall(lerror.vshard, lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+res:match('bad argument #2.*')
  -- Pass less args than msg requires.
  ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER)
  res:match('bad argument #2.*')
diff --git a/vshard/error.lua b/vshard/error.lua
index 59e4fac..429e6da 100644
--- a/vshard/error.lua
+++ b/vshard/error.lua
@@ -14,23 +14,28 @@ local json = require('json')
  local error_message_template = {
      [1] = {
          name = 'WRONG_BUCKET',
-        args = {'bucket_id', 'destination'}
+        msg = 'Cannot perform action with bucket %d, reason: %s',
+        args = {'bucket_id', 'reason', 'destination'}
      },
      [2] = {
          name = 'NON_MASTER',
-        args = {'bucket_id', 'destination'}
+        msg = 'Replica %s is not a master for replicaset %s anymore',
+        args = {'replica_uuid', 'replicaset_uuid'}
      },
      [3] = {
          name = 'BUCKET_ALREADY_EXISTS',
+        msg = 'Bucket %d already exists',
          args = {'bucket_id'}
      },
      [4] = {
          name = 'NO_SUCH_REPLICASET',
+        msg = 'Replicaset %s not found',
          args = {'replicaset_uuid'}
      },
      [5] = {
          name = 'MOVE_TO_SELF',
-        args = {'replicaset_uuid', 'bucket_id'}
+        msg = 'Cannot move: bucket %d is already on replicaset %s',
+        args = {'bucket_id', 'replicaset_uuid'}
      },
      [6] = {
           name = 'MISSING_MASTER',
@@ -39,6 +44,7 @@ local error_message_template = {
      },
      [7] = {
          name = 'TRANSFER_IS_IN_PROGRESS',
+        msg = 'Bucket %d is transferring to replicaset %s',
          args = {'bucket_id', 'destination'}
      },
      [8] = {
@@ -48,6 +54,7 @@ local error_message_template = {
      },
      [9] = {
          name = 'NO_ROUTE_TO_BUCKET',
+        msg = 'Bucket %d cannot be found. Is rebalancing in progress?',
          args = {'bucket_id'}
      },
      [10] = {
@@ -95,13 +102,13 @@ local error_message_template = {
          msg = 'Replicaset is locked'
      }
  }
-
  --
  -- User-visible error_name -> error_number dictionary.
  --
  local error_code = {}
  for code, err in pairs(error_message_template) do
      assert(type(code) == 'number')
+    assert(err.msg, 'msg is required field')
      assert(error_code[err.name] == nil, "Dublicate error name")
      error_code[err.name] = code
  end
@@ -142,11 +149,7 @@ local function vshard_error(code, ...)
      for i = 1, #args do
          ret[args[i]] = select(i, ...)
      end
-    if format.msg then
-        ret.message = string.format(format.msg, ...)
-    else
-        ret.message = string.format('%s: %s', format.name, ret)
-    end
+    ret.message = string.format(format.msg, ...)
      ret.type = 'ShardingError'
      ret.code = code
      ret.name = format.name
diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
index 2d38ff9..125b5b7 100644
--- a/vshard/storage/init.lua
+++ b/vshard/storage/init.lua
@@ -428,31 +428,42 @@ local function bucket_check_state(bucket_id, mode)
      assert(mode == 'read' or mode == 'write')
      local bucket = box.space._bucket:get({bucket_id})
      local errcode = nil
+    local reason = nil
      if not bucket then
          errcode = lerror.code.WRONG_BUCKET
+        reason = 'Not found'
          goto finish
      elseif mode == 'read' then
          if not bucket_is_readable(bucket) then
              errcode = lerror.code.WRONG_BUCKET
+            reason = 'read is prohibited'
              goto finish
          end
      elseif not bucket_is_writable(bucket) then
          if bucket_is_transfer_in_progress(bucket) then
              errcode = lerror.code.TRANSFER_IS_IN_PROGRESS
+            return bucket, lerror.vshard(errcode, bucket_id, 
bucket.destination)
          else
              errcode = lerror.code.WRONG_BUCKET
+            reason = 'write is prohibited'
+            goto finish
          end
-        goto finish
      elseif M.this_replicaset.master ~= M.this_replica then
          errcode = lerror.code.NON_MASTER
-        goto finish
+        return bucket, lerror.vshard(errcode, M.this_replica.uuid,
+ M.this_replicaset.uuid)
      end
      assert(not errcode)
      assert(mode == 'read' and bucket_is_readable(bucket) or
             mode == 'write' and bucket_is_writable(bucket))
+-- Only WRONG_BUCKET errors use this label.
  ::finish::
+    if errcode and bucket and bucket.destination then
+        reason = "bucket is moving to " .. bucket.destination
+    end
      return bucket, errcode and
-           lerror.vshard(errcode, bucket_id, bucket and bucket.destination)
+           lerror.vshard(errcode, bucket_id, reason,
+                         bucket and bucket.destination)
  end

  --
@@ -721,8 +732,8 @@ local function bucket_send(bucket_id, destination)
      end

      if destination == box.info.cluster.uuid then
-        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, 
replicaset_uuid,
-                                  bucket_id)
+        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, bucket_id,
+                                  replicaset_uuid)
      end

      local data = bucket_collect_internal(bucket_id)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 2/3] Refactor error reporting system
  2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
@ 2018-06-07 16:13     ` Alex Khatskevich
  0 siblings, 0 replies; 11+ messages in thread
From: Alex Khatskevich @ 2018-06-07 16:13 UTC (permalink / raw)
  To: Vladislav Shpilevoy, tarantool-patches


>> +-- * name -- Key by which an error code can be retrieved from
>> +--   exprted `code` dictionary.
> 1. exprted -> ?
Fixed.
-- * name -- Key by which an error code can be retrieved from
--   the expoted by the module `code` dictionary.
>> +-- * msg -- Error message which can cantain parameters described
> 2. cantain -> contain. And it must contain. Not can.
fixed
-- * msg -- Error message which can use `args` using
--   `string.format` notation.
> 3. You have found that uuid is always nil for NO_ROUTE_TO_BUCKET.
> Why do you need it in args?
Fixed
> 4. Garbage diff. And this empty line was put here deliberately.
> The comment refers to both box_error and vshard_error.
fixed.
> 5. vstard -> vshard.
Fixed
> 6. arg -> args. Error objects above has args attribute.
fixed
> 7. Please, start a sentence with capital letter and finish with dot.
Ok.
> 8. Why? Either the pcall returns an error and you fail in the assert,
> or simple unprotected string.format() fails. No difference. Just to
> simple string.format().
fixed.
> 9. You do not need local msg here.
fixed
>> +    else
>> +        msg = string.format('%s: %s', format.name, 
>> json.encode(tostring(ret)))
>
> 10. Why do you need encode(tostring())? Ret already has __tostring = 
> json.encode,
> so just do this:
>
>     string.format('%s: %s', format.name, ret)
>
> Diff is below. I did not run the tests. Please, apply and fix the 
> tests if
> needed.
>
> @@ -141,18 +141,14 @@ local function vshard_error(code, ...)
>      for i = 1, #args do
>          ret[args[i]] = select(i, ...)
>      end
> -    local msg
>      if format.msg then
> -        local ok
> -        ok, msg = pcall(string.format, format.msg, ...)
> -        assert(ok)
> +        ret.message = string.format(format.msg, ...)
>      else
> -        msg = string.format('%s: %s', format.name, 
> json.encode(tostring(ret)))
> +        ret.message = string.format('%s: %s', format.name, ret)
>      end
>      ret.type = 'ShardingError'
>      ret.code = code
>      ret.name = format.name
> -    ret.message = msg
>      return ret
>  end
fixed
> 11. Unreachable uuid is always nil as we have found.
Fixed
>>       end
>>         return nil, err
>> @@ -719,14 +717,12 @@ local function bucket_send(bucket_id, destination)
>>       end
>>       local replicaset = M.replicasets[destination]
>>       if replicaset == nil then
>> -        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET,
>> -                                  {replicaset_uuid = destination})
>> +        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET, 
>> destination)
>>       end
>
> 12. NO_SUCH_REPLICASET has two arguments. And you have assert(#args >= 
> args_passed_cnt),
> that has not been failed. It means, that bucket_send has no a test on 
> sending to
> non-existing replicaset. Please,
>     * add a test on bucket_send to non-existing replicaset;
>     * add unit tests on error building.
New diff:

commit af0bfccfbba87a8dcccd71f0dd7d2f8b6c2317cf
Author: AKhatskevich <avkhatskevich@tarantool.org>
Date:   Tue Jun 5 17:05:15 2018 +0300

     Refactor error reporting system

     This commit applies stricter rules on error reporting:
      * error may has only arguments specified in `args` field of
        `error_message_template`
      * arguments may be used in error message
      * arguments are saved in error object by names from `args`

     Extra:
      * testcase for NO_SUCH_REPLICASET added

     Part of #100

diff --git a/test/misc/check_uuid_on_connect.result 
b/test/misc/check_uuid_on_connect.result
index d54c367..6ac2353 100644
--- a/test/misc/check_uuid_on_connect.result
+++ b/test/misc/check_uuid_on_connect.result
@@ -182,10 +182,12 @@ test_run:switch('bad_uuid_router')
  vshard.router.bucket_discovery(1)
  ---
  - null
-- type: ShardingError
-  unreachable_uuid: ac522f65-aa94-4134-9f64-51ee384f1a54
+- bucket_id: 1
    code: 8
-  bucket_id: 1
+  unreachable_uuid: ac522f65-aa94-4134-9f64-51ee384f1a54
+  name: UNREACHABLE_REPLICASET
+  message: There is no active replicas in replicaset 
ac522f65-aa94-4134-9f64-51ee384f1a54
+  type: ShardingError
  ...
  -- Ok to work with correct replicasets.
  vshard.router.bucket_discovery(2).uuid
diff --git a/test/router/reroute_wrong_bucket.result 
b/test/router/reroute_wrong_bucket.result
index eda3bab..f8021f2 100644
--- a/test/router/reroute_wrong_bucket.result
+++ b/test/router/reroute_wrong_bucket.result
@@ -109,9 +109,11 @@ test_run:switch('router_1')
  vshard.router.call(100, 'read', 'customer_lookup', {1}, {timeout = 1})
  ---
  - null
-- type: ShardingError
-  bucket_id: 100
+- bucket_id: 100
    code: 9
+  type: ShardingError
+  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":100}'
+  name: NO_ROUTE_TO_BUCKET
  ...
  -- Wait reconfiguration durigin timeout, if a replicaset was not
  -- found by bucket.destination from WRONG_BUCKET or
@@ -188,7 +190,8 @@ test_run:grep_log('router_1', 'please update 
configuration')
  ...
  err
  ---
-- {'type': 'ShardingError', 'bucket_id': 100, 'code': 1, 'destination': 
'ac522f65-aa94-4134-9f64-51ee384f1a54'}
+- {'bucket_id': 100, 'code': 1, 'type': 'ShardingError', 'destination': 
'ac522f65-aa94-4134-9f64-51ee384f1a54',
+  'name': 'WRONG_BUCKET', 'message': 'WRONG_BUCKET: 
{"bucket_id":100,"destination":"ac522f65-aa94-4134-9f64-51ee384f1a54"}'}
  ...
  --
  -- Now try again, but update configuration during call(). It must
diff --git a/test/router/router.result b/test/router/router.result
index 5f3ceca..5d99255 100644
--- a/test/router/router.result
+++ b/test/router/router.result
@@ -195,15 +195,19 @@ vshard.router.bucket_count()
  util.check_error(vshard.router.call, 1, 'read', 'echo', {123})
  ---
  - null
-- type: ShardingError
-  bucket_id: 1
+- bucket_id: 1
    code: 9
+  type: ShardingError
+  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":1}'
+  name: NO_ROUTE_TO_BUCKET
  ...
  replicaset, err = vshard.router.bucket_discovery(1); return err == nil 
or err
  ---
-- type: ShardingError
-  bucket_id: 1
+- bucket_id: 1
    code: 9
+  type: ShardingError
+  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":1}'
+  name: NO_ROUTE_TO_BUCKET
  ...
  vshard.router.bootstrap()
  ---
@@ -214,8 +218,9 @@ vshard.router.bootstrap()
  ---
  - null
  - type: ShardingError
-  code: 10
+  name: NON_EMPTY
    message: Cluster is already bootstrapped
+  code: 10
  ...
  --
  -- gh-108: negative bucket count on discovery.
@@ -312,9 +317,11 @@ util.check_error(vshard.router.call, 0, 'read', 
'echo', {123})
  ...
  replicaset, err = vshard.router.bucket_discovery(0); return err == nil 
or err
  ---
-- type: ShardingError
-  bucket_id: 0
+- bucket_id: 0
    code: 9
+  type: ShardingError
+  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":0}'
+  name: NO_ROUTE_TO_BUCKET
  ...
  replicaset, err = vshard.router.bucket_discovery(1); return err == nil 
or err
  ---
@@ -353,7 +360,8 @@ vshard.router.call(1, 'read', 'echo', {123})
  util.check_error(vshard.router.call, 1, 'write', 'echo', {123})
  ---
  - null
-- {'type': 'ShardingError', 'bucket_id': 1, 'code': 7, 'destination': 
'<replicaset_1>'}
+- {'bucket_id': 1, 'code': 7, 'type': 'ShardingError', 'destination': 
'<replicaset_1>',
+  'name': 'TRANSFER_IS_IN_PROGRESS', 'message': 
'TRANSFER_IS_IN_PROGRESS: {"bucket_id":1,"destination":"<replicaset_1>"}'}
  ...
  test_run:cmd('switch storage_2_a')
  ---
@@ -397,10 +405,12 @@ test_run:cmd('stop server storage_2_a')
  util.check_error(vshard.router.call, 1, 'read', 'echo', {123})
  ---
  - null
-- type: ShardingError
-  unreachable_uuid: <replicaset_2>
+- bucket_id: 1
    code: 8
-  bucket_id: 1
+  unreachable_uuid: <replicaset_2>
+  name: UNREACHABLE_REPLICASET
+  message: There is no active replicas in replicaset <replicaset_2>
+  type: ShardingError
  ...
  vshard.router.buckets_info(0, 3)
  ---
@@ -420,9 +430,11 @@ test_run:cmd('start server storage_2_a')
  vshard.router.route(vshard.consts.DEFAULT_BUCKET_COUNT + 100)
  ---
  - null
-- type: ShardingError
-  bucket_id: 3100
+- bucket_id: 3100
    code: 9
+  type: ShardingError
+  message: 'NO_ROUTE_TO_BUCKET: {"bucket_id":3100}'
+  name: NO_ROUTE_TO_BUCKET
  ...
  util.check_error(vshard.router.route, 'asdfg')
  ---
@@ -956,7 +968,8 @@ test_run:cmd("switch router_1")
  util.check_error(vshard.router.call, 1, 'write', 'echo', { 'hello 
world' })
  ---
  - null
-- {'type': 'ShardingError', 'code': 2, 'bucket_id': 1}
+- {'bucket_id': 1, 'code': 2, 'type': 'ShardingError', 'message': 
'NON_MASTER: {"bucket_id":1}',
+  'name': 'NON_MASTER'}
  ...
  -- Reconfigure router and test that the WRITE request does work
  vshard.router.cfg(cfg)
diff --git a/test/storage/storage.result b/test/storage/storage.result
index e93ad24..51492a2 100644
--- a/test/storage/storage.result
+++ b/test/storage/storage.result
@@ -594,9 +594,11 @@ vshard.storage.call(1, 'read', 'customer_lookup', {1})
  vshard.storage.call(100500, 'read', 'customer_lookup', {1})
  ---
  - null
-- type: ShardingError
-  bucket_id: 100500
+- bucket_id: 100500
    code: 1
+  type: ShardingError
+  message: 'WRONG_BUCKET: {"bucket_id":100500}'
+  name: WRONG_BUCKET
  ...
  --
  -- Test not existing space in bucket data.
@@ -614,6 +616,17 @@ vshard.storage.bucket_recv(100, 'from_uuid', 
{{1000, {{1}}}})
  --
  -- Bucket transfer
  --
+-- Transfer to unknown replicaset.
+vshard.storage.bucket_send(1, 'unknown uuid')
+---
+- null
+- code: 4
+  type: ShardingError
+  name: NO_SUCH_REPLICASET
+  replicaset_uuid: unknown uuid
+  message: 'NO_SUCH_REPLICASET: {"replicaset_uuid":"unknown uuid"}'
+...
+-- Successful transfer.
  vshard.storage.bucket_send(1, replicaset2_uuid)
  ---
  - true
diff --git a/test/storage/storage.test.lua b/test/storage/storage.test.lua
index 948decc..f4bbf0e 100644
--- a/test/storage/storage.test.lua
+++ b/test/storage/storage.test.lua
@@ -137,6 +137,11 @@ vshard.storage.bucket_recv(100, 'from_uuid', 
{{1000, {{1}}}})
  --
  -- Bucket transfer
  --
+
+-- Transfer to unknown replicaset.
+vshard.storage.bucket_send(1, 'unknown uuid')
+
+-- Successful transfer.
  vshard.storage.bucket_send(1, replicaset2_uuid)
  _ = test_run:cmd("switch storage_2_a")
  vshard.storage.buckets_info()
diff --git a/test/unit/error.result b/test/unit/error.result
index a46fb0d..74571ca 100644
--- a/test/unit/error.result
+++ b/test/unit/error.result
@@ -20,13 +20,13 @@ tostring(box_error)
  ---
  - '{"type":"ClientError","code":78,"message":"Timeout 
exceeded","trace":[{"file":"[C]","line":4294967295}]}'
  ...
-vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, {uuid = 
'uuid', reason = 'reason'}, 'message 1 2 3')
+vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, 'uuid', 
'reason')
  ---
  ...
  tostring(vshard_error)
  ---
-- 
'{"reason":"reason","code":11,"type":"ShardingError","uuid":"uuid","message":"message
-  1 2 3"}'
+- 
'{"reason":"reason","code":11,"type":"ShardingError","name":"UNREACHABLE_MASTER","uuid":"uuid","message":"Master
+  of replicaset uuid is unreachable: reason"}'
  ...
  log = require('log')
  ---
@@ -38,6 +38,42 @@ test_run:grep_log('default', 
'"reason":"reason","code":11,"type":"ShardingError"
  ---
  - '"reason":"reason","code":11,"type":"ShardingError"'
  ...
+--
+-- Part of gh-100: check `error.vshard`.
+--
+lerror.vshard(lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+---
+- bucket_id: arg1
+  code: 1
+  type: ShardingError
+  name: WRONG_BUCKET
+  message: 'WRONG_BUCKET: {"bucket_id":"arg1","destination":"arg2"}'
+  destination: arg2
+...
+-- Pass less args than msg requires.
+ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER)
+---
+...
+res:match('bad argument #2.*')
+---
+- 'bad argument #2 to ''format'' (no value)'
+...
+-- Pass more args than `args` field contains.
+ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER, 'arg1', 'arg2')
+---
+...
+res:match('Wrong number of.*')
+---
+- Wrong number of arguments passed to MISSING_MASTER error
+...
+-- Pass wrong format code.
+ok, res = pcall(lerror.vshard, 'Wrong format code', 'arg1', 'arg2')
+---
+...
+res:match('Error message format not found.')
+---
+- Error message format not found.
+...
  function raise_lua_err() assert(false) end
  ---
  ...
diff --git a/test/unit/error.test.lua b/test/unit/error.test.lua
index 4b5c20f..7496982 100644
--- a/test/unit/error.test.lua
+++ b/test/unit/error.test.lua
@@ -9,13 +9,27 @@ ok, err = pcall(box.error, box.error.TIMEOUT)
  box_error = lerror.box(err)
  tostring(box_error)

-vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, {uuid = 
'uuid', reason = 'reason'}, 'message 1 2 3')
+vshard_error = lerror.vshard(lerror.code.UNREACHABLE_MASTER, 'uuid', 
'reason')
  tostring(vshard_error)

  log = require('log')
  log.info('Log error: %s', vshard_error)
  test_run:grep_log('default', 
'"reason":"reason","code":11,"type":"ShardingError"')

+--
+-- Part of gh-100: check `error.vshard`.
+--
+lerror.vshard(lerror.code.WRONG_BUCKET, 'arg1', 'arg2')
+-- Pass less args than msg requires.
+ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER)
+res:match('bad argument #2.*')
+-- Pass more args than `args` field contains.
+ok, res = pcall(lerror.vshard, lerror.code.MISSING_MASTER, 'arg1', 'arg2')
+res:match('Wrong number of.*')
+-- Pass wrong format code.
+ok, res = pcall(lerror.vshard, 'Wrong format code', 'arg1', 'arg2')
+res:match('Error message format not found.')
+
  function raise_lua_err() assert(false) end
  ok, err = pcall(raise_lua_err)
  lerror.make(err)
diff --git a/vshard/error.lua b/vshard/error.lua
index 8d26d11..59e4fac 100644
--- a/vshard/error.lua
+++ b/vshard/error.lua
@@ -1,6 +1,111 @@
  local ffi = require('ffi')
  local json = require('json')

+--
+-- Error messages description.
+-- * name -- Key by which an error code can be retrieved from
+--   the expoted by the module `code` dictionary.
+-- * msg -- Error message which can use `args` using
+--   `string.format` notation.
+-- * args -- Names of arguments passed while constructing an
+--   error. After constructed, an error-object contains provided
+--   arguments by the names specified in the field.
+--
+local error_message_template = {
+    [1] = {
+        name = 'WRONG_BUCKET',
+        args = {'bucket_id', 'destination'}
+    },
+    [2] = {
+        name = 'NON_MASTER',
+        args = {'bucket_id', 'destination'}
+    },
+    [3] = {
+        name = 'BUCKET_ALREADY_EXISTS',
+        args = {'bucket_id'}
+    },
+    [4] = {
+        name = 'NO_SUCH_REPLICASET',
+        args = {'replicaset_uuid'}
+    },
+    [5] = {
+        name = 'MOVE_TO_SELF',
+        args = {'replicaset_uuid', 'bucket_id'}
+    },
+    [6] = {
+         name = 'MISSING_MASTER',
+         msg = 'Master is not configured for replicaset %s',
+         args = {'replicaset_uuid'}
+    },
+    [7] = {
+        name = 'TRANSFER_IS_IN_PROGRESS',
+        args = {'bucket_id', 'destination'}
+    },
+    [8] = {
+        name = 'UNREACHABLE_REPLICASET',
+        msg = 'There is no active replicas in replicaset %s',
+        args = {'unreachable_uuid', 'bucket_id'}
+    },
+    [9] = {
+        name = 'NO_ROUTE_TO_BUCKET',
+        args = {'bucket_id'}
+    },
+    [10] = {
+        name = 'NON_EMPTY',
+        msg = 'Cluster is already bootstrapped'
+    },
+    [11] = {
+        name = 'UNREACHABLE_MASTER',
+        msg = 'Master of replicaset %s is unreachable: %s',
+        args = {'uuid', 'reason'}
+    },
+    [12] = {
+        name = 'OUT_OF_SYNC',
+        msg = 'Replica is out of sync'
+    },
+    [13] = {
+        name = 'HIGH_REPLICATION_LAG',
+        msg = 'High replication lag: %f',
+        args = {'lag'}
+    },
+    [14] = {
+        name = 'UNREACHABLE_REPLICA',
+        msg = "Replica %s isn't active",
+        args = {'unreachable_uuid'}
+    },
+    [15] = {
+        name = 'LOW_REDUNDANCY',
+        msg = 'Only one replica is active'
+    },
+    [16] = {
+        name = 'INVALID_REBALANCING',
+        msg = 'Sending and receiving buckets at same time is not allowed'
+    },
+    [17] = {
+        name = 'SUBOPTIMAL_REPLICA',
+        msg = 'A current read replica in replicaset %s is not optimal'
+    },
+    [18] = {
+        name = 'UNKNOWN_BUCKETS',
+        msg = '%d buckets are not discovered',
+        arg = {'not_discovered_cnt'}
+    },
+    [19] = {
+        name = 'REPLICASET_IS_LOCKED',
+        msg = 'Replicaset is locked'
+    }
+}
+
+--
+-- User-visible error_name -> error_number dictionary.
+--
+local error_code = {}
+for code, err in pairs(error_message_template) do
+    assert(type(code) == 'number')
+    assert(error_code[err.name] == nil, "Dublicate error name")
+    error_code[err.name] = code
+end
+
  --
  -- There are 2 error types:
  -- * box_error - it is created on tarantool errors: client error,
@@ -16,14 +121,35 @@ local function box_error(original_error)
      return setmetatable(original_error:unpack(), {__tostring = 
json.encode})
  end

-local function vshard_error(code, args, msg)
-    local ret = setmetatable({type = 'ShardingError', code = code,
-                              message = msg}, {__tostring = json.encode})
-    if args then
-        for k, v in pairs(args) do
-            ret[k] = v
-        end
+--
+-- Construct an vshard error.
+-- @param code Number, one of error_code constants.
+-- @param ... Arguments from `error_message_template` `args`
+--        field. Caller have to pass at least as many arguments
+--        as `msg` field requires.
+-- @retval ShardingError object.
+--
+local function vshard_error(code, ...)
+    local format = error_message_template[code]
+    assert(format, 'Error message format not found.')
+    local args_passed_cnt = select('#', ...)
+    local args = format.args or {}
+    assert(#args >= args_passed_cnt,
+           string.format('Wrong number of arguments passed to %s error',
+                         format.name))
+    local ret = setmetatable({}, {__tostring = json.encode})
+    -- Save error arguments.
+    for i = 1, #args do
+        ret[args[i]] = select(i, ...)
      end
+    if format.msg then
+        ret.message = string.format(format.msg, ...)
+    else
+        ret.message = string.format('%s: %s', format.name, ret)
+    end
+    ret.type = 'ShardingError'
+    ret.code = code
+    ret.name = format.name
      return ret
  end

@@ -45,70 +171,6 @@ local function make_error(e)
      end
  end

-local error_code = {
-    WRONG_BUCKET = 1,
-    NON_MASTER = 2,
-    BUCKET_ALREADY_EXISTS = 3,
-    NO_SUCH_REPLICASET = 4,
-    MOVE_TO_SELF = 5,
-    MISSING_MASTER = 6,
-    TRANSFER_IS_IN_PROGRESS = 7,
-    UNREACHABLE_REPLICASET = 8,
-    NO_ROUTE_TO_BUCKET = 9,
-    NON_EMPTY = 10,
-    UNREACHABLE_MASTER = 11,
-    OUT_OF_SYNC = 12,
-    HIGH_REPLICATION_LAG = 13,
-    UNREACHABLE_REPLICA = 14,
-    LOW_REDUNDANCY = 15,
-    INVALID_REBALANCING = 16,
-    SUBOPTIMAL_REPLICA = 17,
-    UNKNOWN_BUCKETS = 18,
-    REPLICASET_IS_LOCKED = 19,
-}
-
-local error_message_template = {
-    [error_code.MISSING_MASTER] = {
-         name = 'MISSING_MASTER',
-         msg = 'Master is not configured for replicaset %s'
-    },
-    [error_code.UNREACHABLE_MASTER] = {
-        name = 'UNREACHABLE_MASTER',
-        msg = 'Master of replicaset %s is unreachable: %s'
-    },
-    [error_code.OUT_OF_SYNC] = {
-        name = 'OUT_OF_SYNC',
-        msg = 'Replica is out of sync'
-    },
-    [error_code.HIGH_REPLICATION_LAG] = {
-        name = 'HIGH_REPLICATION_LAG',
-        msg = 'High replication lag: %f'
-    },
-    [error_code.UNREACHABLE_REPLICA] = {
-        name = 'UNREACHABLE_REPLICA',
-        msg = "Replica %s isn't active"
-    },
-    [error_code.UNREACHABLE_REPLICASET] = {
-        name = 'UNREACHABLE_REPLICASET',
-        msg = 'There is no active replicas in replicaset %s'
-    },
-    [error_code.LOW_REDUNDANCY] = {
-        name = 'LOW_REDUNDANCY',
-        msg = 'Only one replica is active'
-    },
-    [error_code.INVALID_REBALANCING] = {
-        name = 'INVALID_REBALANCING',
-        msg = 'Sending and receiving buckets at same time is not allowed'
-    },
-    [error_code.SUBOPTIMAL_REPLICA] = {
-        name = 'SUBOPTIMAL_REPLICA',
-        msg = 'A current read replica in replicaset %s is not optimal'
-    },
-    [error_code.UNKNOWN_BUCKETS] = {
-        name = 'UNKNOWN_BUCKETS',
-        msg = '%d buckets are not discovered',
-    }
-}

  local function make_alert(code, ...)
      local format = error_message_template[code]
diff --git a/vshard/replicaset.lua b/vshard/replicaset.lua
index 7fcf2df..99f59aa 100644
--- a/vshard/replicaset.lua
+++ b/vshard/replicaset.lua
@@ -114,8 +114,8 @@ end
  local function replicaset_connect_master(replicaset)
      local master = replicaset.master
      if master == nil then
-        return nil, lerror.vshard(lerror.code.MASTER_IS_MISSING,
-                                  {replicaset_uuid = replicaset.uuid})
+        return nil, lerror.vshard(lerror.code.MISSING_MASTER,
+                                  replicaset.uuid)
      end
      return replicaset_connect_to_replica(replicaset, master)
  end
diff --git a/vshard/router/init.lua b/vshard/router/init.lua
index 42e9c86..21093e5 100644
--- a/vshard/router/init.lua
+++ b/vshard/router/init.lua
@@ -85,8 +85,7 @@ local function bucket_discovery(bucket_id)
          if last_err.type == 'ClientError' and
             last_err.code == box.error.NO_CONNECTION then
              err = lerror.vshard(lerror.code.UNREACHABLE_REPLICASET,
-                                {bucket_id = bucket_id,
-                                 unreachable_uuid = unreachable_uuid})
+                                unreachable_uuid, bucket_id)
          else
              err = lerror.make(last_err)
          end
@@ -97,9 +96,7 @@ local function bucket_discovery(bucket_id)
          -- bucket was found to be RECEIVING on one replicaset, and
          -- was not found on other replicasets (it was sent during
          -- discovery).
-        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET,
-                            {bucket_id = bucket_id,
-                             unreachable_uuid = unreachable_uuid})
+        err = lerror.vshard(lerror.code.NO_ROUTE_TO_BUCKET, bucket_id)
      end

      return nil, err
@@ -519,8 +516,7 @@ local function cluster_bootstrap()
              return nil, err
          end
          if count > 0 then
-            return nil, lerror.vshard(lerror.code.NON_EMPTY, {},
-                                      'Cluster is already bootstrapped')
+            return nil, lerror.vshard(lerror.code.NON_EMPTY)
          end
      end
      lreplicaset.calculate_etalon_balance(M.replicasets, 
M.total_bucket_count)
diff --git a/vshard/storage/init.lua b/vshard/storage/init.lua
index d5e7b57..2d38ff9 100644
--- a/vshard/storage/init.lua
+++ b/vshard/storage/init.lua
@@ -452,8 +452,7 @@ local function bucket_check_state(bucket_id, mode)
             mode == 'write' and bucket_is_writable(bucket))
  ::finish::
      return bucket, errcode and
-           lerror.vshard(errcode, {bucket_id = bucket_id,
-                                   destination = bucket and 
bucket.destination})
+           lerror.vshard(errcode, bucket_id, bucket and bucket.destination)
  end

  --
@@ -514,8 +513,7 @@ local function bucket_recv(bucket_id, from, data)

      local bucket = box.space._bucket:get({bucket_id})
      if bucket ~= nil then
-        return nil, lerror.vshard(lerror.code.BUCKET_ALREADY_EXISTS,
-                                  {bucket_id = bucket_id})
+        return nil, lerror.vshard(lerror.code.BUCKET_ALREADY_EXISTS, 
bucket_id)
      end

      box.begin()
@@ -719,14 +717,12 @@ local function bucket_send(bucket_id, destination)
      end
      local replicaset = M.replicasets[destination]
      if replicaset == nil then
-        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET,
-                                  {replicaset_uuid = destination})
+        return nil, lerror.vshard(lerror.code.NO_SUCH_REPLICASET, 
destination)
      end

      if destination == box.info.cluster.uuid then
-        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF,
-                                  {bucket_id = bucket_id,
-                                   replicaset_uuid = replicaset_uuid})
+        return nil, lerror.vshard(lerror.code.MOVE_TO_SELF, 
replicaset_uuid,
+                                  bucket_id)
      end

      local data = bucket_collect_internal(bucket_id)
@@ -1260,8 +1256,7 @@ end
  --
  local function rebalancer_apply_routes(routes)
      if is_this_replicaset_locked() then
-        return false, lerror.vshard(lerror.code.REPLICASET_IS_LOCKED, nil,
-                                    "Replicaset is locked");
+        return false, lerror.vshard(lerror.code.REPLICASET_IS_LOCKED);
      end
      assert(not rebalancing_is_in_progress())
      -- Can not apply routes here because of gh-946 in tarantool

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [tarantool-patches] Re: [PATCH 3/3] Add error messages
  2018-06-07 16:12     ` Alex Khatskevich
@ 2018-06-07 18:44       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 11+ messages in thread
From: Vladislav Shpilevoy @ 2018-06-07 18:44 UTC (permalink / raw)
  To: Alex Khatskevich, tarantool-patches


Thanks for the fixes! Finally the errors have become pretty.

>> 4. Same as 2.
> Fixed along with
> "bucket moving to " -> "bucket moving to "

What the difference? "bucket moving to" == "bucket moving to".

>>
>>>       end
>>>       assert(not errcode)
>>>       assert(mode == 'read' and bucket_is_readable(bucket) or
>>>              mode == 'write' and bucket_is_writable(bucket))
>>> -::finish::
>>> +::wrong_bucket::
>>
>> 6. The code below is executed both on error and on success. But
>> label is named 'wrong_bucket'. It is not correct. On success
>> path it is guaranteed that bucket ~= nil.
> Renamed back to `finish`. IMHO `wrong_bucket` suited well here.

You had labeled the success code as error processing. It is not ok.
And in the same code you check 'if bucket and ...', but bucket on
success is not nil - it is guaranteed. We must optimize the common
case. And the bucket is ok most of time.

+-- Only WRONG_BUCKET errors use this label.

This is wrong. See three lines above - they process a case when the
bucket is ok. You can label it ::wrong_bucket::, but then you must
separate this code from success path. I refactored this function,
you can look at it on the master branch.

The patchset is pushed with my fixes.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-06-07 18:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-06 15:57 [tarantool-patches] [PATCH 0/3][vshard] Add error messages AKhatskevich
2018-06-06 15:57 ` [tarantool-patches] [PATCH 1/3] Fix test on bucket_transferring error AKhatskevich
2018-06-06 15:57 ` [tarantool-patches] [PATCH 2/3] Refactor error reporting system AKhatskevich
2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
2018-06-07 16:13     ` Alex Khatskevich
2018-06-06 15:57 ` [tarantool-patches] [PATCH 3/3] Add error messages AKhatskevich
2018-06-07 12:22   ` [tarantool-patches] " Vladislav Shpilevoy
2018-06-07 16:12     ` Alex Khatskevich
2018-06-07 18:44       ` Vladislav Shpilevoy
2018-06-07 12:22 ` [tarantool-patches] Re: [PATCH 0/3][vshard] " Vladislav Shpilevoy
2018-06-07 13:16   ` Alex Khatskevich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox