From 4cc9972d319cac9806dd8d139dce6aa4c12b16dd Mon Sep 17 00:00:00 2001
From: bigbes <bigbes@gmail.com>
Date: Wed, 10 Dec 2014 04:54:56 +0300
Subject: [PATCH] Fixes gh-636 - Flush schema in box.net.box

Added method remote:reload_schema()
---
 src/lua/box_net_box.lua       | 36 +++++++--------
 test/box/box.net.box.result   | 82 ++++++++++++++++++++++++++++++++++-
 test/box/box.net.box.test.lua | 25 +++++++++++
 3 files changed, 125 insertions(+), 18 deletions(-)

diff --git a/src/lua/box_net_box.lua b/src/lua/box_net_box.lua
index aa293dee61..91b6f483b0 100644
--- a/src/lua/box_net_box.lua
+++ b/src/lua/box_net_box.lua
@@ -40,20 +40,18 @@ local GREETING_SIZE     = 128
 
 local TIMEOUT_INFINITY  = 500 * 365 * 86400
 
-local sequence_mt = { __serialize = 'sequence'}
-local mapping_mt = { __serialize = 'mapping'}
+local sequence_mt = { __serialize = 'sequence' }
+local mapping_mt = { __serialize = 'mapping' }
 
 local CONSOLE_FAKESYNC  = 15121974
 
 local function request(header, body)
-
     -- hint msgpack to always encode header and body as a map
     header = msgpack.encode(setmetatable(header, mapping_mt))
     body = msgpack.encode(setmetatable(body, mapping_mt))
 
     local len = msgpack.encode(string.len(header) + string.len(body))
 
-
     return len .. header .. body
 end
 
@@ -158,8 +156,7 @@ local proto = {
     end,
 
     -- select
-    select  = function(sync, spaceno, indexno, key, opts)
-
+    select = function(sync, spaceno, indexno, key, opts)
         if opts == nil then
             opts = {}
         end
@@ -517,6 +514,17 @@ local remote_methods = {
         }
     end,
 
+    reload_schema = function(self)
+         xpcall(function() self:_load_schema() end,
+               function(e)
+                  log.info("Can't load schema: %s", tostring(e))
+               end)
+
+         if self.state ~= 'error' and self.state ~= 'closed' then
+               self:_switch_state('active')
+         end
+    end,
+
     close = function(self)
         if self.state ~= 'closed' then
             self:_switch_state('closed')
@@ -779,11 +787,11 @@ local remote_methods = {
 
     _auth = function(self)
         if self.opts.user == nil or self.opts.password == nil then
-            self:_switch_state 'authen'
+            self:_switch_state('authen')
             return
         end
 
-        self:_switch_state 'auth'
+        self:_switch_state('auth')
 
         local auth_res = self:_request_internal('auth',
             false, self.opts.user, self.opts.password, self.handshake)
@@ -793,7 +801,7 @@ local remote_methods = {
             return
         end
 
-        self:_switch_state 'authen'
+        self:_switch_state('authen')
     end,
 
     -- states wakeup _read_worker
@@ -821,10 +829,9 @@ local remote_methods = {
         return false
     end,
 
-
     _load_schema = function(self)
-        if self.state ~= 'authen' then
-            self:_fatal 'Can not load schema from the state'
+        if self.state == 'closed' or self.state == 'error' then
+            self:_fatal('Can not load schema from the state')
             return
         end
 
@@ -837,7 +844,6 @@ local remote_methods = {
 
         local sl = {}
 
-
         for _, space in pairs(spaces) do
             local name = space[3]
             local id = space[1]
@@ -851,7 +857,6 @@ local remote_methods = {
                 field_count     = field_count,
                 enabled         = true,
                 index           = {}
-
             }
             if #space > 5 and string.match(space[6], 'temporary') then
                 s.temporary = true
@@ -863,7 +868,6 @@ local remote_methods = {
 
             sl[id] = s
             sl[name] = s
-
         end
 
         for _, index in pairs(indexes) do
@@ -1072,11 +1076,9 @@ local remote_methods = {
     end,
 
     _request_internal = function(self, name, raise, ...)
-
         local sync = self.proto:sync()
         local request = self.proto[name](sync, ...)
         return self:_request_raw(sync, request, raise)
-        
     end,
 
     -- private (low level) methods
diff --git a/test/box/box.net.box.result b/test/box/box.net.box.result
index b5af04d8a7..8a3590ecad 100644
--- a/test/box/box.net.box.result
+++ b/test/box/box.net.box.result
@@ -141,7 +141,7 @@ cn.space.net_box_test_space:insert{234, 1,2,3}
 ...
 cn.space.net_box_test_space.insert{234, 1,2,3}
 ---
-- error: 'builtin/net.box.lua:229: Use space:method(...) instead space.method(...)'
+- error: 'builtin/net.box.lua:226: Use space:method(...) instead space.method(...)'
 ...
 cn.space.net_box_test_space:replace{354, 1,2,3}
 ---
@@ -648,3 +648,83 @@ end;
 gh594()
 ---
 ...
+-- #636: Reload schema on demand
+sp = box.schema.create_space('test_old')
+---
+...
+sp:create_index('primary')
+---
+- unique: true
+  parts:
+  - type: NUM
+    fieldno: 1
+  id: 0
+  space_id: 512
+  name: primary
+  type: TREE
+...
+sp:insert{1, 2, 3}
+---
+- [1, 2, 3]
+...
+LISTEN = require('uri').parse(box.cfg.listen)
+---
+...
+uri = string.format('%s:%s', LISTEN.host, LISTEN.service)
+---
+...
+con = remote.new(uri)
+---
+...
+con:ping()
+---
+- true
+...
+con.space.test_old:select{}
+---
+- - [1, 2, 3]
+...
+con.space.test:select{}
+---
+- error: '[string "return con.space.test:select{} "]:1: attempt to index field ''test''
+    (a nil value)'
+...
+sp = box.schema.create_space('test')
+---
+...
+sp:create_index('primary')
+---
+- unique: true
+  parts:
+  - type: NUM
+    fieldno: 1
+  id: 0
+  space_id: 513
+  name: primary
+  type: TREE
+...
+sp:insert{2, 3, 4}
+---
+- [2, 3, 4]
+...
+con.space.test:select{}
+---
+- error: '[string "return con.space.test:select{} "]:1: attempt to index field ''test''
+    (a nil value)'
+...
+con:reload_schema()
+---
+...
+con.space.test:select{}
+---
+- - [2, 3, 4]
+...
+box.space.test:drop()
+---
+...
+box.space.test_old:drop()
+---
+...
+con:close()
+---
+...
diff --git a/test/box/box.net.box.test.lua b/test/box/box.net.box.test.lua
index 65309c0321..76d529e97d 100644
--- a/test/box/box.net.box.test.lua
+++ b/test/box/box.net.box.test.lua
@@ -262,3 +262,28 @@ function gh594()
 end;
 --# setopt delimiter ''
 gh594()
+
+-- #636: Reload schema on demand
+sp = box.schema.create_space('test_old')
+sp:create_index('primary')
+sp:insert{1, 2, 3}
+
+LISTEN = require('uri').parse(box.cfg.listen)
+uri = string.format('%s:%s', LISTEN.host, LISTEN.service)
+
+con = remote.new(uri)
+con:ping()
+con.space.test_old:select{}
+con.space.test:select{}
+
+sp = box.schema.create_space('test')
+sp:create_index('primary')
+sp:insert{2, 3, 4}
+
+con.space.test:select{}
+con:reload_schema()
+con.space.test:select{}
+
+box.space.test:drop()
+box.space.test_old:drop()
+con:close()
-- 
GitLab