diff --git a/extra/schema_erase.lua b/extra/schema_erase.lua
deleted file mode 100644
index 8a50d8eaf36d109680fa151145c246ce255e0c1a..0000000000000000000000000000000000000000
--- a/extra/schema_erase.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-_schema = box.space[box.schema.SCHEMA_ID]
-_space = box.space[box.schema.SPACE_ID]
-_index = box.space[box.schema.INDEX_ID]
-_user = box.space[box.schema.USER_ID]
-_func = box.space[box.schema.FUNC_ID]
-_priv = box.space[box.schema.PRIV_ID]
-_cluster = box.space[box.schema.CLUSTER_ID]
--- destroy everything - save snapshot produces an empty snapshot now
-
--- space:truncate() doesn't work with disabled triggers on __index
-local function truncate(space)
-    local pk = space.index[0]
-    while pk:len() > 0 do
-        local state, t
-        for state, t in pk:pairs() do
-            local key = {}
-            for _k2, parts in ipairs(pk.parts) do
-                table.insert(key, t[parts.fieldno])
-            end
-            space:delete(key)
-        end
-    end
-end
-
-_space:run_triggers(false)
-_index:run_triggers(false)
-_user:run_triggers(false)
-_func:run_triggers(false)
-_priv:run_triggers(false)
-
-truncate(_space)
-truncate(_index)
-truncate(_user)
-truncate(_func)
-truncate(_priv)
-_schema:delete('version')
-_schema:delete('max_id')
diff --git a/extra/schema_fill.lua b/extra/schema_fill.lua
deleted file mode 100644
index 79afb2d9f2150e09de883b896d1bb714d5b7059a..0000000000000000000000000000000000000000
--- a/extra/schema_fill.lua
+++ /dev/null
@@ -1,202 +0,0 @@
-_space:run_triggers(false)
-_index:run_triggers(false)
-_user:run_triggers(false)
-_func:run_triggers(false)
-_priv:run_triggers(false)
-
--- Guest user id - the default user
-GUEST = 0
--- Super User ID
-ADMIN = 1
--- role 'PUBLIC' is special, it's automatically granted to every user
-PUBLIC = 2
-
-EMPTY_MAP = setmetatable({}, { __serialize = 'map' })
---
--- system spaces
---
-_schema = box.space[box.schema.SCHEMA_ID]
-_space = box.space[box.schema.SPACE_ID]
-_index = box.space[box.schema.INDEX_ID]
-_func = box.space[box.schema.FUNC_ID]
-_user = box.space[box.schema.USER_ID]
-_priv = box.space[box.schema.PRIV_ID]
-_cluster = box.space[box.schema.CLUSTER_ID]
--- define schema version
-_schema:insert{'version', 1, 6}
-_schema:insert{'max_id', box.schema.SYSTEM_ID_MAX}
--- define system spaces
---
--- _schema
---
-_space:insert{_schema.id, ADMIN, '_schema', 'memtx', 0, EMPTY_MAP, {}}
---
--- _space
---
-_space:insert{_space.id, ADMIN, '_space', 'memtx', 0, EMPTY_MAP, {}}
---
--- _index
---
-_space:insert{_index.id, ADMIN, '_index', 'memtx', 0, EMPTY_MAP, {}}
---
--- _func
---
-_space:insert{_func.id, ADMIN, '_func', 'memtx', 0, EMPTY_MAP, {}}
---
--- _user
---
-_space:insert{_user.id, ADMIN, '_user', 'memtx', 0, EMPTY_MAP, {}}
---
--- _priv
---
-_space:insert{_priv.id, ADMIN, '_priv', 'memtx', 0, EMPTY_MAP, {}}
---
--- _cluster
---
-_space:insert{_cluster.id, ADMIN, '_cluster', 'memtx', 0, EMPTY_MAP, {}}
-
--- define formats.
--- stick to the following convention:
--- prefer user id (owner id) in field #2 (base-1)
--- prefer object name in field #3 (base-1)
--- 
-format={}
-format[1] = {type='str', name='key'}
-_schema:format(format)
-format={}
-format[1] = {name='id', type='num'}
-format[2] = {name='owner', type='num'}
-format[3] = {name='name', type='str'}
-format[4] = {name='engine', type='str'}
-format[5] = {name='field_count', type='num'}
-format[6] = {name='flags', type='str'}
-format[7] = {name='format', type='*'}
-_space:format(format)
-format = {}
-format[1] = {name = 'id', type = 'num'}
-format[2] = {name = 'iid', type = 'num'}
-format[3] = {name = 'name', type = 'str'}
-format[4] = {name = 'type', type = 'str'}
-format[5] = {name = 'opts', type = 'array'}
-format[6] = {name = 'parts', type = 'array'}
-_index:format(format)
-format={}
-format[1] = {name='id', type='num'}
-format[2] = {name='owner', type='num'}
-format[3] = {name='name', type='str'}
-format[4] = {name='setuid', type='num'}
-_func:format(format)
-format={}
-format[1] = {name='id', type='num'}
-format[2] = {name='owner', type='num'}
-format[3] = {name='name', type='str'}
-format[4] = {name='type', type='str'}
-format[5] = {name='auth', type='*'}
-_user:format(format)
-format={}
-format[1] = {name='grantor', type='num'}
-format[2] = {name='grantee', type='num'}
-format[3] = {name='object_type', type='str'}
-format[4] = {name='object_id', type='num'}
-format[5] = {name='privilege', type='num'}
-_priv:format(format)
-format = {}
-format[1] = {name='id', type='num'}
-format[2] = {name='uuid', type='str'}
-_cluster:format(format)
--- define indexes
--- stick to the following convention:
--- index on owner id is index #1 (base-0)
--- index on object name is index #2 (base-0)
--- space name is unique
-_index:insert{_schema.id, 0, 'primary', 'tree', { unique = true }, {{0, 'str'}}}
-_index:insert{_space.id, 0, 'primary', 'tree', { unique = true }, {{0, 'num'}}}
-_index:insert{_space.id, 1, 'owner', 'tree', {unique = false }, {{1, 'num'}}}
-_index:insert{_space.id, 2, 'name', 'tree', { unique = true }, {{2, 'str'}}}
-
--- index name is unique within a space
-_index:insert{_index.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}, {1, 'num'}}}
-_index:insert{_index.id, 2, 'name', 'tree', {unique = true}, {{0, 'num'}, {2, 'str'}}}
--- user name and id are unique
-_index:insert{_user.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
-_index:insert{_user.id, 1, 'owner', 'tree', {unique = false}, {{1, 'num'}}}
-_index:insert{_user.id, 2, 'name', 'tree', {unique = true}, {{2, 'str'}}}
--- function name and id are unique
-_index:insert{_func.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
-_index:insert{_func.id, 1, 'owner', 'tree', {unique = false}, {{1, 'num'}}}
-_index:insert{_func.id, 2, 'name', 'tree', {unique = true}, {{2, 'str'}}}
---
-_index:insert{_priv.id, 0, 'primary', 'tree', {unique = true}, {{1, 'num'}, {2, 'str'}, {3, 'num'}}}
--- owner index  - to quickly find all privileges granted by a user
-_index:insert{_priv.id, 1, 'owner', 'tree', {unique = false}, {{0, 'num'}}}
--- object index - to quickly find all grants on a given object
-_index:insert{_priv.id, 2, 'object', 'tree', {unique = false}, {{2, 'str'}, {3, 'num'}}}
--- primary key: node id
-_index:insert{_cluster.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
--- node uuid key: node uuid
-_index:insert{_cluster.id, 1, 'uuid', 'tree', {unique = true}, {{1, 'str'}}}
-
---
--- Pre-created users and grants
---
-_user:insert{GUEST, ADMIN, 'guest', 'user'}
-_user:insert{ADMIN, ADMIN, 'admin', 'user'}
-_user:insert{PUBLIC, ADMIN, 'public', 'role'}
--- space schema is: grantor id, user id, object_type, object_id, privilege
--- primary key: user id, object type, object id
-RPL_ID = _user:auto_increment{ADMIN, 'replication', 'role'}[1]
--- grant admin access to the universe
-_priv:insert{1, 1, 'universe', 0, 7}
--- grant 'public' role access to 'box.schema.user.info' function
-_func:insert{1, 1, 'box.schema.user.info', 1}
-_priv:insert{1, 2, 'function', 1, 4}
--- replication can read the entire universe
-_priv:insert{1, RPL_ID, 'universe', 0, 1}
--- replication can append to '_cluster' system space
-_priv:insert{1, RPL_ID, 'space', box.schema.CLUSTER_ID, 2}
--- grant role 'public' to 'guest'
-_priv:insert{1, 0, 'role', 2, 4}
-
---
--- Create system views
---
-
-_space:run_triggers(true)
-
-local views = {
-    [box.schema.SPACE_ID] = box.schema.VSPACE_ID;
-    [box.schema.INDEX_ID] = box.schema.VINDEX_ID;
-    [box.schema.USER_ID] = box.schema.VUSER_ID;
-    [box.schema.FUNC_ID] = box.schema.VFUNC_ID;
-    [box.schema.PRIV_ID] = box.schema.VPRIV_ID;
-}
-
---
--- create definitions for system views, and grant
--- privileges on system views to 'PUBLIC' role
---
-
-for source_id, target_id in pairs(views) do
-    local def = _space:get(source_id):totable()
-    def[1] = target_id
-    def[3] = "_v"..def[3]:sub(2)
-    def[4] = 'sysview'
-    _space:insert(def)
-    local idefs = {}
-    for _, idef in _index:pairs(source_id, { iterator = 'EQ'}) do
-        idef = idef:totable()
-        idef[1] = target_id
-        table.insert(idefs, idef)
-    end
-    for _, idef in ipairs(idefs) do
-        _index:insert(idef)
-    end
-    -- public can read system views
-    _priv:insert{1, PUBLIC, 'space', target_id, 1}
-end
-
-_space:run_triggers(true)
-_index:run_triggers(true)
-_user:run_triggers(true)
-_func:run_triggers(true)
-_priv:run_triggers(true)
diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 880f80c6d760681059e209aab52c46c0e4f531c2..d3b1b038356c6c4fcdae6b001c4ade94534ce935 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -9,6 +9,7 @@ lua_source(lua_sources lua/tuple.lua)
 lua_source(lua_sources lua/session.lua)
 lua_source(lua_sources lua/snapshot_daemon.lua)
 lua_source(lua_sources lua/net_box.lua)
+lua_source(lua_sources lua/upgrade.lua)
 set(bin_sources)
 bin_source(bin_sources bootstrap.snap bootstrap.h)
 
diff --git a/src/box/lua/init.c b/src/box/lua/init.c
index 165f9e61e28331992139005088a61de155408cec..9fdec991bb46be99815584a9a8a2e51bc2ed22aa 100644
--- a/src/box/lua/init.c
+++ b/src/box/lua/init.c
@@ -59,15 +59,17 @@ extern char session_lua[],
 	tuple_lua[],
 	load_cfg_lua[],
 	snapshot_daemon_lua[],
-	net_box_lua[];
+	net_box_lua[],
+	upgrade_lua[];
 
 static const char *lua_sources[] = {
 	"box/session", session_lua,
 	"box/schema", schema_lua,
 	"box/tuple", tuple_lua,
 	"box/snapshot_daemon", snapshot_daemon_lua,
-	"box/load_cfg", load_cfg_lua,
+	"box/upgrade", upgrade_lua,
 	"box/net_box", net_box_lua,
+	"box/load_cfg", load_cfg_lua,
 	NULL
 };
 
diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
new file mode 100644
index 0000000000000000000000000000000000000000..bc7cefa2c016b772c1e1b0c58615cdec1a51043c
--- /dev/null
+++ b/src/box/lua/upgrade.lua
@@ -0,0 +1,505 @@
+local log = require('log')
+local bit = require('bit')
+local json = require('json')
+
+local VERSION_ID
+
+-- Guest user id - the default user
+local GUEST = 0
+-- Super User ID
+local ADMIN = 1
+-- role 'PUBLIC' is special, it's automatically granted to every user
+local PUBLIC = 2
+
+
+--------------------------------------------------------------------------------
+-- Utils
+--------------------------------------------------------------------------------
+
+local function setmap(tab)
+    return setmetatable(tab, { __serialize = 'map' })
+end
+
+local function ismap(tab)
+    if type(tab) ~= 'table' then
+        return false
+    end
+    local mt = getmetatable(tab)
+    return mt and (mt.__serialize == 'map' or mt.__serialize == 'mapping')
+end
+
+local function version_id(major, minor, patch)
+    return bit.bor(bit.lshift(bit.bor(bit.lshift(major, 8), minor), 8), patch)
+end
+
+-- space:truncate() doesn't work with disabled triggers on __index
+local function truncate(space)
+    local pk = space.index[0]
+    while pk:len() > 0 do
+        local state, t
+        for state, t in pk:pairs() do
+            local key = {}
+            for _k2, parts in ipairs(pk.parts) do
+                table.insert(key, t[parts.fieldno])
+            end
+            space:delete(key)
+        end
+    end
+end
+
+local function set_system_triggers(val)
+    box.space._space:run_triggers(val)
+    box.space._index:run_triggers(val)
+    box.space._user:run_triggers(val)
+    box.space._func:run_triggers(val)
+    box.space._priv:run_triggers(val)
+end
+
+--------------------------------------------------------------------------------
+-- Bootstrap
+--------------------------------------------------------------------------------
+
+local function erase()
+    truncate(box.space._space)
+    truncate(box.space._index)
+    truncate(box.space._user)
+    truncate(box.space._func)
+    truncate(box.space._priv)
+    --truncate(box.space._schema)
+    box.space._schema:delete('version')
+    box.space._schema:delete('max_id')
+end
+
+local function initial()
+    -- stick to the following convention:
+    -- prefer user id (owner id) in field #1
+    -- prefer object name in field #2
+    -- index on owner id is index #1
+    -- index on object name is index #2
+    --
+
+    local _schema = box.space[box.schema.SCHEMA_ID]
+    local _space = box.space[box.schema.SPACE_ID]
+    local _index = box.space[box.schema.INDEX_ID]
+    local _func = box.space[box.schema.FUNC_ID]
+    local _user = box.space[box.schema.USER_ID]
+    local _priv = box.space[box.schema.PRIV_ID]
+    local _cluster = box.space[box.schema.CLUSTER_ID]
+    local MAP = setmap({})
+
+    --
+    -- _schema
+    --
+    log.info("create space _schema")
+    _space:insert{_schema.id, ADMIN, '_schema', 'memtx', 0, MAP, {}}
+    log.info("create index primary on _schema")
+    _index:insert{_schema.id, 0, 'primary', 'tree', { unique = true }, {{0, 'str'}}}
+
+    --
+    -- _space
+    --
+    log.info("create space _space")
+    _space:insert{_space.id, ADMIN, '_space', 'memtx', 0, MAP, {}}
+    -- space name is unique
+    log.info("create index primary on _space")
+    _index:insert{_space.id, 0, 'primary', 'tree', { unique = true }, {{0, 'num'}}}
+    log.info("create index owner on _space")
+    _index:insert{_space.id, 1, 'owner', 'tree', {unique = false }, {{1, 'num'}}}
+    log.info("create index index name on _space")
+    _index:insert{_space.id, 2, 'name', 'tree', { unique = true }, {{2, 'str'}}}
+
+    --
+    -- _index
+    --
+    log.info("create space _index")
+    _space:insert{_index.id, ADMIN, '_index', 'memtx', 0, MAP, {}}
+    -- index name is unique within a space
+    log.info("create index primary on _index")
+    _index:insert{_index.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}, {1, 'num'}}}
+    log.info("create index name on _index")
+    _index:insert{_index.id, 2, 'name', 'tree', {unique = true}, {{0, 'num'}, {2, 'str'}}}
+
+    --
+    -- _func
+    --
+    log.info("create space _func")
+    _space:insert{_func.id, ADMIN, '_func', 'memtx', 0, MAP, {}}
+    -- function name and id are unique
+    log.info("create index _func:primary")
+    _index:insert{_func.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
+    log.info("create index _func:owner")
+    _index:insert{_func.id, 1, 'owner', 'tree', {unique = false}, {{1, 'num'}}}
+    log.info("create index _func:name")
+    _index:insert{_func.id, 2, 'name', 'tree', {unique = true}, {{2, 'str'}}}
+
+    --
+    -- _user
+    --
+    log.info("create space _user")
+    _space:insert{_user.id, ADMIN, '_user', 'memtx', 0, MAP, {}}
+    -- user name and id are unique
+    log.info("create index _func:primary")
+    _index:insert{_user.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
+    log.info("create index _func:owner")
+    _index:insert{_user.id, 1, 'owner', 'tree', {unique = false}, {{1, 'num'}}}
+    log.info("create index _func:name")
+    _index:insert{_user.id, 2, 'name', 'tree', {unique = true}, {{2, 'str'}}}
+
+    --
+    -- _priv
+    --
+    log.info("create space _priv")
+    _space:insert{_priv.id, ADMIN, '_priv', 'memtx', 0, MAP, {}}
+    --
+    -- space schema is: grantor id, user id, object_type, object_id, privilege
+    -- primary key: user id, object type, object id
+    log.info("create index primary on _priv")
+    _index:insert{_priv.id, 0, 'primary', 'tree', {unique = true}, {{1, 'num'}, {2, 'str'}, {3, 'num'}}}
+    -- owner index  - to quickly find all privileges granted by a user
+    log.info("create index owner on _priv")
+    _index:insert{_priv.id, 1, 'owner', 'tree', {unique = false}, {{0, 'num'}}}
+    -- object index - to quickly find all grants on a given object
+    log.info("create index object on _priv")
+    _index:insert{_priv.id, 2, 'object', 'tree', {unique = false}, {{2, 'str'}, {3, 'num'}}}
+
+    --
+    -- _cluster
+    --
+    log.info("create space _cluster")
+    _space:insert{_cluster.id, ADMIN, '_cluster', 'memtx', 0, MAP, {}}
+    -- primary key: node id
+    log.info("create index primary on _cluster")
+    _index:insert{_cluster.id, 0, 'primary', 'tree', {unique = true}, {{0, 'num'}}}
+    -- node uuid key: node uuid
+    log.info("create index uuid on _cluster")
+    _index:insert{_cluster.id, 1, 'uuid', 'tree', {unique = true}, {{1, 'str'}}}
+
+    --
+    -- Pre-create user and grants
+    log.info("create user guest")
+    _user:insert{GUEST, ADMIN, 'guest', 'user'}
+    log.info("create user admin")
+    _user:insert{ADMIN, ADMIN, 'admin', 'user'}
+    log.info("create role public")
+    _user:insert{PUBLIC, ADMIN, 'public', 'role'}
+    log.info("grant read,write,execute on universe to admin")
+    _priv:insert{ADMIN, ADMIN, 'universe', 0, 7}
+
+    -- grant role 'public' to 'guest'
+    log.info("grant role public to guest")
+    _priv:insert{ADMIN, GUEST, 'role', PUBLIC, 4}
+
+    log.info("set max_id to box.schema.SYSTEM_ID_MAX")
+    _schema:insert{'max_id', box.schema.SYSTEM_ID_MAX}
+
+    log.info("set schema version to 1.6.0")
+    _schema:insert({'version', 1, 6, 0})
+end
+
+--------------------------------------------------------------------------------
+-- Tarantool 1.6.8
+--------------------------------------------------------------------------------
+
+local function upgrade_index_options_to_1_6_8()
+    local indexes = {}
+    for _, def in box.space._index:pairs() do
+        if type(def[5]) == 'number' then
+            -- Tarantool < 1.6.5 format
+            local part_count = def[6]
+            local new_def = def:update({{'#', 7, 2 * part_count}}):totable()
+            new_def[5] = setmap({})
+            new_def[5].unique = def[5] ~= 0
+            new_def[6] = {}
+            for i=1,part_count,1 do
+                local field_id = def[7 + (i - 1) * 2]
+                local field_type = def[7 + (i - 1) * 2 + 1]
+                table.insert(new_def[6], { field_id, field_type })
+            end
+            table.insert(indexes, new_def)
+        elseif not ismap(def[5]) then
+            log.error("unexpected index options: %s", json.encode(def[5]))
+        end
+    end
+    for _, new_def in ipairs(indexes) do
+        log.info("alter index %s on %s set options to %s, parts to %s",
+                 new_def[3], box.space[new_def[1]].name,
+                 json.encode(new_def[5]), json.encode(new_def[6]))
+        box.space._index:replace(new_def)
+    end
+end
+
+local function upgrade_space_options_to_1_6_8()
+    local spaces = {}
+    for _, def in box.space._space:pairs() do
+        local new_def = def:totable()
+        new_def[6] = setmap({})
+        if def[6] == nil or def[6] == "" then
+            -- Tarantool < 1.6.8 format
+            table.insert(spaces, new_def)
+        elseif def[6] == 'temporary' then
+            -- Tarantool < 1.6.8 format
+            new_def[6].temporary = true
+            table.insert(spaces, new_def)
+        elseif not ismap(def[6]) then
+            log.error("unexpected space options: %s", json.encode(def[6]))
+        end
+    end
+    for _, new_def in ipairs(spaces) do
+        log.info("alter space %s set options to %s", new_def[3],
+                 json.encode(new_def[6]))
+        box.space._space:update(new_def[1], {{'=', 6, new_def[6]}})
+    end
+end
+
+local function upgrade_space_format_to_1_6_8()
+    local space_def = box.space._space:get(box.space._schema.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format[1] = {type='str', name='key'}
+        log.info("alter space _schema set format to %s", json.encode(format))
+        box.space._space:update(box.space._schema.id, {{'=', 7, format}})
+    end
+
+    local space_def = box.space._space:get(box.space._space.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format[1] = {name='id', type='num'}
+        format[2] = {name='owner', type='num'}
+        format[3] = {name='name', type='str'}
+        format[4] = {name='engine', type='str'}
+        format[5] = {name='field_count', type='num'}
+        format[6] = {name='flags', type='str'}
+        format[7] = {name='format', type='*'}
+        log.info("alter space _space set format")
+        box.space._space:format(format)
+    end
+
+    local space_def = box.space._space:get(box.space._index.id)
+    if space_def[7] == nil or next(space_def[7]) == nil or
+       space_def[7][5].name == 'unique' then
+        local format = {}
+        format[1] = {name = 'id', type = 'num'}
+        format[2] = {name = 'iid', type = 'num'}
+        format[3] = {name = 'name', type = 'str'}
+        format[4] = {name = 'type', type = 'str'}
+        format[5] = {name = 'opts', type = 'array'}
+        format[6] = {name = 'parts', type = 'array'}
+        log.info("alter space _index set format")
+        box.space._index:format(format)
+    end
+
+    local space_def = box.space._space:get(box.space._func.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format[1] = {name='id', type='num'}
+        format[2] = {name='owner', type='num'}
+        format[3] = {name='name', type='str'}
+        format[4] = {name='setuid', type='num'}
+        log.info("alter space _func set format")
+        box.space._func:format(format)
+    end
+
+    local space_def = box.space._space:get(box.space._user.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format[1] = {name='id', type='num'}
+        format[2] = {name='owner', type='num'}
+        format[3] = {name='name', type='str'}
+        format[4] = {name='type', type='str'}
+        format[5] = {name='auth', type='*'}
+        log.info("alter space _user set format")
+        box.space._user:format(format)
+    end
+
+    local space_def = box.space._space:get(box.space._priv.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format={}
+        format[1] = {name='grantor', type='num'}
+        format[2] = {name='grantee', type='num'}
+        format[3] = {name='object_type', type='str'}
+        format[4] = {name='object_id', type='num'}
+        format[5] = {name='privilege', type='num'}
+        log.info("alter space _priv set format")
+        box.space._priv:format(format)
+    end
+
+    local space_def = box.space._space:get(box.space._cluster.id)
+    if space_def[7] == nil or next(space_def[7]) == nil then
+        local format = {}
+        format[1] = {name='id', type='num'}
+        format[2] = {name='uuid', type='str'}
+        log.info("alter space _schema set format")
+        box.space._cluster:format(format)
+    end
+
+    local spaces = {}
+    for _, space_def in box.space._space:pairs() do
+        if space_def[7] == nil then
+            table.insert(spaces, space_def)
+        end
+    end
+    for _, space_def in ipairs(spaces) do
+        log.info("alter space %s set format", space_def[3])
+        box.space._space:update(space_def[1], {{'=', 7, {}}})
+    end
+end
+
+local function create_sysview(source_id, target_id)
+    --
+    -- Create definitions for the system view, and grant
+    -- privileges on system views to 'PUBLIC' role
+    --
+    local def = box.space._space:get(source_id):totable()
+    def[1] = target_id
+    def[3] = "_v"..def[3]:sub(2)
+    def[4] = 'sysview'
+    local space_def = box.space._space:get(target_id)
+    if space_def == nil then
+        log.info("create view %s...", def[3])
+        box.space._space:replace(def)
+    elseif json.encode(space_def[7]) ~= json.encode(def[7]) then
+        -- sync box.space._vXXX format with box.space._XXX format
+        log.info("alter space %s set format", def[3])
+        box.space._space:update(def[1], {{ '=', 7, def[7] }})
+    end
+    local idefs = {}
+    for _, idef in box.space._index:pairs(source_id, { iterator = 'EQ'}) do
+        idef = idef:totable()
+        idef[1] = target_id
+        table.insert(idefs, idef)
+    end
+    for _, idef in ipairs(idefs) do
+        if box.space._index:get({idef[1], idef[2]}) == nil then
+            log.info("create index %s on %s", idef[3], def[3])
+            box.space._index:replace(idef)
+        end
+    end
+    -- public can read system views
+    if box.space._priv.index.primary:count({PUBLIC, 'space', target_id}) == 0 then
+        log.info("grant read access to 'public' role for %s view", def[3])
+        box.space._priv:insert({1, PUBLIC, 'space', target_id, 1})
+    end
+end
+
+local function upgrade_users_to_1_6_8()
+    if box.space._user.index.name:count({'replication'}) == 0 then
+        log.info("create role replication")
+        local RPL_ID = box.space._user:auto_increment{ADMIN, 'replication', 'role'}[1]
+        -- replication can read the entire universe
+        log.info("grant read on universe to replication")
+        box.space._priv:replace{1, RPL_ID, 'universe', 0, 1}
+        -- replication can append to '_cluster' system space
+        log.info("grant write on space _cluster to replication")
+        box.space._priv:replace{1, RPL_ID, 'space', box.space._cluster.id, 2}
+    end
+
+    if box.space._priv.index.primary:count({ADMIN, 'universe', 0}) == 0 then
+        -- grant admin access to the universe
+        log.info("grant all on universe to admin")
+        box.space._priv:insert{ADMIN, ADMIN, 'universe', 0, 7}
+    end
+
+    if box.space._func.index.name:count("box.schema.user.info") == 0 then
+        -- create "box.schema.user.info" function
+        log.info('create function "box.schema.user.info" with setuid')
+        box.space._func:auto_increment{ADMIN, 'box.schema.user.info', 1}
+
+        -- grant 'public' role access to 'box.schema.user.info' function
+        log.info('grant execute on function "box.schema.user.info" to public')
+        box.space._priv:replace{ADMIN, PUBLIC, 'function', 1, 4}
+    end
+end
+
+local function upgrade_priv_to_1_6_8()
+    -- see e5862c387c7151b812810b1a51086b82a7eedcc4
+    local index_def = box.space._index.index.name:get({312, 'owner'})
+    local parts = index_def[6]
+    if parts[1][1] == 1 then
+        log.info("fix index owner for _priv")
+        parts = {{0, 'num'}}
+        box.space._index:update({index_def[1], index_def[2]},
+                                {{'=', 6, parts }})
+    end
+end
+
+local function upgrade_func_to_1_6_8()
+    local funcs = {}
+    for _, def in box.space._func:pairs() do
+        local new_def = def:totable()
+        if new_def[5] == nil then
+            new_def[5] = 'LUA'
+            table.insert(funcs, new_def)
+        end
+    end
+    for _, def in ipairs(funcs) do
+        box.space._func:update(def[1], {{ '=', 5, def[5] }})
+    end
+end
+
+local function upgrade_to_1_6_8()
+    if VERSION_ID >= version_id(1, 6, 8) then
+        return
+    end
+
+    upgrade_index_options_to_1_6_8()
+    upgrade_space_options_to_1_6_8()
+    upgrade_space_format_to_1_6_8()
+    upgrade_users_to_1_6_8()
+    upgrade_priv_to_1_6_8()
+    upgrade_func_to_1_6_8()
+
+    create_sysview(box.schema.SPACE_ID, box.schema.VSPACE_ID)
+    create_sysview(box.schema.INDEX_ID, box.schema.VINDEX_ID)
+    create_sysview(box.schema.USER_ID, box.schema.VUSER_ID)
+    create_sysview(box.schema.FUNC_ID, box.schema.VFUNC_ID)
+    create_sysview(box.schema.PRIV_ID, box.schema.VPRIV_ID)
+
+    local max_id = box.space._schema:get('max_id')
+    if max_id == nil then
+        local id = box.space._space.index.primary:max()[1]
+        if id < box.schema.SYSTEM_ID_MAX then
+            id = box.schema.SYSTEM_ID_MAX
+        end
+        log.info("set max_id to %d", id)
+        box.space._schema:insert{'max_id', id}
+    end
+
+    log.info("set schema version to 1.6.8")
+    box.space._schema:replace({'version', 1, 6, 8})
+end
+
+--------------------------------------------------------------------------------
+
+local function upgrade()
+    box.cfg{}
+    local version = box.space._schema:get{'version'}
+    if version == nil then
+        error('Missing "version" in box.space._schema')
+    end
+    local major = version[2]
+    local minor = version[3]
+    local patch = version[4] or 0
+    VERSION_ID = version_id(major, minor, patch)
+
+    upgrade_to_1_6_8()
+end
+
+local function bootstrap()
+    set_system_triggers(false)
+
+    -- erase current schema
+    erase()
+    -- insert initial schema
+    initial()
+    -- upgrade schema to the latest version
+    upgrade()
+
+    set_system_triggers(true)
+
+    -- save new bootstrap.snap
+    box.snapshot()
+end
+
+box.schema.upgrade = upgrade;
+box.internal.bootstrap = bootstrap;
diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result
index 177f37450a1e28fb0ccbaf2252aaa8183345c61b..a3cf08af5c81ee659d2d440ad7020287acf8a324 100644
--- a/test/box-py/bootstrap.result
+++ b/test/box-py/bootstrap.result
@@ -1,46 +1,11 @@
-dofile("<sourcedir>/extra/schema_erase.lua")
+box.internal.bootstrap()
 ---
 ...
 box.space._schema:select{}
 ---
-- - ['cluster', '<cluster uuid>']
-...
-box.space._cluster:select{}
----
-- - [1, '<server uuid>']
-...
-box.space._space:select{}
----
-- []
-...
-box.space._index:select{}
----
-- []
-...
-box.space._user:select{}
----
-- []
-...
-box.space._func:select{}
----
-- []
-...
-box.space._priv:select{}
----
-- []
-...
-dofile("<sourcedir>/extra/schema_fill.lua")
----
-...
-box.snapshot()
----
-- ok
-...
-box.space._schema:select{}
----
 - - ['cluster', '<cluster uuid>']
   - ['max_id', 511]
-  - ['version', 1, 6]
+  - ['version', 1, 6, 8]
 ...
 box.space._cluster:select{}
 ---
@@ -125,7 +90,7 @@ box.space._user:select{}
 ...
 box.space._func:select{}
 ---
-- - [1, 1, 'box.schema.user.info', 1]
+- - [1, 1, 'box.schema.user.info', 1, 'LUA']
 ...
 box.space._priv:select{}
 ---
diff --git a/test/box-py/bootstrap.test.py b/test/box-py/bootstrap.test.py
index 3f4e557cc8a61093dc34176f40ed8e813e32199e..7d1c316c02cc6822ad5a09a41b7374c2a8671945 100644
--- a/test/box-py/bootstrap.test.py
+++ b/test/box-py/bootstrap.test.py
@@ -7,19 +7,8 @@ sys.stdout.push_filter(server_uuid, '<server uuid>')
 cluster_uuid = yaml.load(server.admin('box.space._schema:get("cluster")',
     silent = True))[0][1]
 sys.stdout.push_filter(cluster_uuid, '<cluster uuid>')
-sys.stdout.push_filter(server.sourcedir, '<sourcedir>')
 
-server.admin('dofile("%s/extra/schema_erase.lua")' % server.sourcedir)
-server.admin('box.space._schema:select{}')
-server.admin('box.space._cluster:select{}')
-server.admin('box.space._space:select{}')
-server.admin('box.space._index:select{}')
-server.admin('box.space._user:select{}')
-server.admin('box.space._func:select{}')
-server.admin('box.space._priv:select{}')
-
-server.admin('dofile("%s/extra/schema_fill.lua")' % server.sourcedir)
-server.admin("box.snapshot()")
+server.admin('box.internal.bootstrap()')
 server.restart()
 
 server.admin('box.space._schema:select{}')
diff --git a/test/xlog/lua/schema.lua b/test/xlog/lua/schema.lua
new file mode 120000
index 0000000000000000000000000000000000000000..9dad317344becb0703ac3a9bc2e3d780e959088f
--- /dev/null
+++ b/test/xlog/lua/schema.lua
@@ -0,0 +1 @@
+../../../extra/schema.lua
\ No newline at end of file
diff --git a/test/xlog/suite.cfg b/test/xlog/suite.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..50f56ffde850d4c814e21549475866028930d079
--- /dev/null
+++ b/test/xlog/suite.cfg
@@ -0,0 +1,8 @@
+{
+    "upgrade.test.lua": {
+        "1.6.5": {"version": "1.6.5"},
+        "1.6.6": {"version": "1.6.6"},
+        "1.6.7": {"version": "1.6.7"},
+        "1.6.8": {"version": "1.6.8"}
+    }
+}
diff --git a/test/xlog/suite.ini b/test/xlog/suite.ini
index fc186417670674e01f312c7f3672d1b48413aa20..c1bdb58525b40d208768ab92793dc9aff85f7777 100644
--- a/test/xlog/suite.ini
+++ b/test/xlog/suite.ini
@@ -5,5 +5,6 @@ script = xlog.lua
 disabled =
 valgrind_disabled =
 release_disabled = errinj.test.lua panic_on_lsn_gap.test.lua
-lua_libs =
+config = suite.cfg
+lua_libs = lua/schema.lua
 use_unix_sockets = True
diff --git a/test/xlog/upgrade.lua b/test/xlog/upgrade.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f43c25915ef9a8cea50662c70acb95fe75dee12e
--- /dev/null
+++ b/test/xlog/upgrade.lua
@@ -0,0 +1,8 @@
+#!/usr/bin/env tarantool
+
+box.cfg {
+    listen              = os.getenv("LISTEN"),
+    slab_alloc_arena    = 0.1
+}
+
+require('console').listen(os.getenv('ADMIN'))
diff --git a/test/xlog/upgrade.result b/test/xlog/upgrade.result
new file mode 100644
index 0000000000000000000000000000000000000000..3cc6a1d8fbce0a53ccd533d2cf45e8796ec8d33e
--- /dev/null
+++ b/test/xlog/upgrade.result
@@ -0,0 +1,196 @@
+test_run = require('test_run').new()
+---
+...
+version = test_run:get_cfg('version')
+---
+...
+work_dir = "xlog/upgrade/"..version
+---
+...
+test_run:cmd('create server upgrade with script="xlog/upgrade.lua", workdir="'..work_dir..'"')
+---
+- true
+...
+test_run:cmd("start server upgrade")
+---
+- true
+...
+test_run:switch('upgrade')
+---
+- true
+...
+test_run:cmd(string.format("push filter '%s' to '<server_uuid>'", box.info.cluster.uuid))
+---
+- true
+...
+--
+-- Upgrade
+--
+box.schema.upgrade()
+---
+...
+--
+-- Migrated data
+--
+box.space._schema:select()
+---
+- - ['cluster', '<server_uuid>']
+  - ['max_id', 513]
+  - ['version', 1, 6, 8]
+...
+box.space._space:select()
+---
+- - [272, 1, '_schema', 'memtx', 0, {}, [{'type': 'str', 'name': 'key'}]]
+  - [280, 1, '_space', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'engine', 'type': 'str'},
+      {'name': 'field_count', 'type': 'num'}, {'name': 'flags', 'type': 'str'}, {
+        'name': 'format', 'type': '*'}]]
+  - [281, 1, '_vspace', 'sysview', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'engine', 'type': 'str'},
+      {'name': 'field_count', 'type': 'num'}, {'name': 'flags', 'type': 'str'}, {
+        'name': 'format', 'type': '*'}]]
+  - [288, 1, '_index', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'iid',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'type', 'type': 'str'},
+      {'name': 'opts', 'type': 'array'}, {'name': 'parts', 'type': 'array'}]]
+  - [289, 1, '_vindex', 'sysview', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'iid',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'type', 'type': 'str'},
+      {'name': 'opts', 'type': 'array'}, {'name': 'parts', 'type': 'array'}]]
+  - [296, 1, '_func', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'setuid', 'type': 'num'}]]
+  - [297, 1, '_vfunc', 'sysview', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'setuid', 'type': 'num'}]]
+  - [304, 1, '_user', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'type', 'type': 'str'},
+      {'name': 'auth', 'type': '*'}]]
+  - [305, 1, '_vuser', 'sysview', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'owner',
+        'type': 'num'}, {'name': 'name', 'type': 'str'}, {'name': 'type', 'type': 'str'},
+      {'name': 'auth', 'type': '*'}]]
+  - [312, 1, '_priv', 'memtx', 0, {}, [{'name': 'grantor', 'type': 'num'}, {'name': 'grantee',
+        'type': 'num'}, {'name': 'object_type', 'type': 'str'}, {'name': 'object_id',
+        'type': 'num'}, {'name': 'privilege', 'type': 'num'}]]
+  - [313, 1, '_vpriv', 'sysview', 0, {}, [{'name': 'grantor', 'type': 'num'}, {'name': 'grantee',
+        'type': 'num'}, {'name': 'object_type', 'type': 'str'}, {'name': 'object_id',
+        'type': 'num'}, {'name': 'privilege', 'type': 'num'}]]
+  - [320, 1, '_cluster', 'memtx', 0, {}, [{'name': 'id', 'type': 'num'}, {'name': 'uuid',
+        'type': 'str'}]]
+  - [512, 1, 'distro', 'memtx', 0, {}, [{'name': 'os', 'type': 'str'}, {'name': 'dist',
+        'type': 'str'}, {'name': 'version', 'type': 'num'}, {'name': 'time', 'type': 'num'}]]
+  - [513, 1, 'temporary', 'memtx', 0, {'temporary': true}, []]
+...
+box.space._index:select()
+---
+- - [272, 0, 'primary', 'tree', {'unique': true}, [[0, 'str']]]
+  - [280, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [280, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [280, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [281, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [281, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [281, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [288, 0, 'primary', 'tree', {'unique': true}, [[0, 'num'], [1, 'num']]]
+  - [288, 2, 'name', 'tree', {'unique': true}, [[0, 'num'], [2, 'str']]]
+  - [289, 0, 'primary', 'tree', {'unique': true}, [[0, 'num'], [1, 'num']]]
+  - [289, 2, 'name', 'tree', {'unique': true}, [[0, 'num'], [2, 'str']]]
+  - [296, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [296, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [296, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [297, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [297, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [297, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [304, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [304, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [304, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [305, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [305, 1, 'owner', 'tree', {'unique': false}, [[1, 'num']]]
+  - [305, 2, 'name', 'tree', {'unique': true}, [[2, 'str']]]
+  - [312, 0, 'primary', 'tree', {'unique': true}, [[1, 'num'], [2, 'str'], [3, 'num']]]
+  - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'num']]]
+  - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'str'], [3, 'num']]]
+  - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'num'], [2, 'str'], [3, 'num']]]
+  - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'num']]]
+  - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'str'], [3, 'num']]]
+  - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'num']]]
+  - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'str']]]
+  - [512, 0, 'primary', 'hash', {'unique': true}, [[0, 'str'], [1, 'str'], [2, 'num']]]
+  - [512, 1, 'codename', 'hash', {'unique': true}, [[1, 'str']]]
+  - [512, 2, 'time', 'tree', {'unique': false}, [[3, 'num']]]
+...
+box.space._user:select()
+---
+- - [0, 1, 'guest', 'user']
+  - [1, 1, 'admin', 'user']
+  - [2, 1, 'public', 'role']
+  - [3, 1, 'replication', 'role']
+  - [4, 1, 'someuser', 'user', {'chap-sha1': '2qvbQIHM4zMWhAmm2xGeGNjqoHM='}]
+  - [5, 1, 'somerole', 'role']
+...
+box.space._func:select()
+---
+- - [1, 1, 'box.schema.user.info', 1, 'LUA']
+  - [2, 4, 'somefunc', 1, 'LUA']
+  - [3, 1, 'someotherfunc', 0, 'LUA']
+...
+box.space._priv:select()
+---
+- - [1, 0, 'role', 2, 4]
+  - [1, 1, 'universe', 0, 7]
+  - [1, 2, 'function', 1, 4]
+  - [1, 2, 'function', 2, 4]
+  - [1, 2, 'space', 281, 1]
+  - [1, 2, 'space', 289, 1]
+  - [1, 2, 'space', 297, 1]
+  - [1, 2, 'space', 305, 1]
+  - [1, 2, 'space', 313, 1]
+  - [1, 3, 'space', 320, 2]
+  - [1, 3, 'universe', 0, 1]
+  - [1, 4, 'function', 3, 4]
+  - [1, 4, 'role', 2, 4]
+  - [1, 4, 'role', 5, 4]
+  - [1, 4, 'space', 513, 3]
+  - [1, 5, 'space', 512, 3]
+...
+box.space._vspace ~= nil
+---
+- true
+...
+box.space._vindex ~= nil
+---
+- true
+...
+box.space._vuser ~= nil
+---
+- true
+...
+box.space._vpriv ~= nil
+---
+- true
+...
+-- a test space
+box.space.distro:select{}
+---
+- - ['debian', 'lenny', 50, 1234602000]
+  - ['debian', 'etch', 40, 1176019200]
+  - ['debian', 'sarge', 31, 1118044800]
+  - ['ubuntu', 'trusty', 1404, 1397721600]
+  - ['ubuntu', 'vivid', 1504, 1429779600]
+  - ['ubuntu', 'wily', 1510, 1445504400]
+  - ['debian', 'wheezy', 70, 1367654400]
+  - ['debian', 'squeeze', 60, 1296896400]
+  - ['debian', 'jessie', 80, 1430038800]
+  - ['ubuntu', 'precise', 1510, 1335427200]
+  - ['debian', 'woody', 30, 1027065600]
+...
+test_run:cmd("clear filter")
+---
+- true
+...
+test_run:switch('default')
+---
+- true
+...
+test_run:cmd('stop server upgrade')
+---
+- true
+...
+test_run = nil
+---
+...
diff --git a/test/xlog/upgrade.test.lua b/test/xlog/upgrade.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8e9fa06488f6dd4dee99e80a717167fd07b12585
--- /dev/null
+++ b/test/xlog/upgrade.test.lua
@@ -0,0 +1,43 @@
+test_run = require('test_run').new()
+
+version = test_run:get_cfg('version')
+work_dir = "xlog/upgrade/"..version
+
+test_run:cmd('create server upgrade with script="xlog/upgrade.lua", workdir="'..work_dir..'"')
+test_run:cmd("start server upgrade")
+
+test_run:switch('upgrade')
+
+test_run:cmd(string.format("push filter '%s' to '<server_uuid>'", box.info.cluster.uuid))
+
+--
+-- Upgrade
+--
+
+box.schema.upgrade()
+
+--
+-- Migrated data
+--
+
+box.space._schema:select()
+box.space._space:select()
+box.space._index:select()
+box.space._user:select()
+box.space._func:select()
+box.space._priv:select()
+
+box.space._vspace ~= nil
+box.space._vindex ~= nil
+box.space._vuser ~= nil
+box.space._vpriv ~= nil
+
+-- a test space
+box.space.distro:select{}
+
+test_run:cmd("clear filter")
+
+test_run:switch('default')
+test_run:cmd('stop server upgrade')
+
+test_run = nil
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000000.snap b/test/xlog/upgrade/1.6.5/00000000000000000000.snap
new file mode 100644
index 0000000000000000000000000000000000000000..be9760da5eba68884297c8daa4bca72be61980fe
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000000.snap differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000000.xlog b/test/xlog/upgrade/1.6.5/00000000000000000000.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..67212ec34024793c7e03edd0811bb651a417518c
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000000.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000005.xlog b/test/xlog/upgrade/1.6.5/00000000000000000005.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..aadeeb5d3e16f3ecb823fa6d4e3bb86aca96b0a5
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000005.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000010.xlog b/test/xlog/upgrade/1.6.5/00000000000000000010.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..08481cfbce37053b19f95df36b0f762de347f7b9
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000010.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000015.xlog b/test/xlog/upgrade/1.6.5/00000000000000000015.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..5974cc5efa1191db30e39d14025ee8d325373628
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000015.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000020.xlog b/test/xlog/upgrade/1.6.5/00000000000000000020.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..fcdda66625dfa22783fcdad5d78b39de7220fbb1
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000020.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000025.xlog b/test/xlog/upgrade/1.6.5/00000000000000000025.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..eb528af94e585ffe220b8655151746454737e710
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000025.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/00000000000000000030.xlog b/test/xlog/upgrade/1.6.5/00000000000000000030.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..c074220ff400eb42b719ba84dfbf0dea43917ee9
Binary files /dev/null and b/test/xlog/upgrade/1.6.5/00000000000000000030.xlog differ
diff --git a/test/xlog/upgrade/1.6.5/version b/test/xlog/upgrade/1.6.5/version
new file mode 100644
index 0000000000000000000000000000000000000000..4dbbe844e701694efd328c7909638cae0ee71503
--- /dev/null
+++ b/test/xlog/upgrade/1.6.5/version
@@ -0,0 +1 @@
+1.6.5-0-g800652e
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000000.snap b/test/xlog/upgrade/1.6.6/00000000000000000000.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fbe660cb2d44ba4c1a5699572221b65af5abd0c2
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000000.snap differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000000.xlog b/test/xlog/upgrade/1.6.6/00000000000000000000.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..25a56e0fb4a80af1df9ace325b2e28d04365deaa
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000000.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000005.xlog b/test/xlog/upgrade/1.6.6/00000000000000000005.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..c5c2a6739232ee222a6669aa58d519379c77016b
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000005.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000010.xlog b/test/xlog/upgrade/1.6.6/00000000000000000010.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..646004591d54fefffc6b750097359f2cdee3d2c1
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000010.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000015.xlog b/test/xlog/upgrade/1.6.6/00000000000000000015.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..70657e4cf16ebb454e589ae487938bfa1dad08ee
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000015.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000020.xlog b/test/xlog/upgrade/1.6.6/00000000000000000020.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..968869384ee672a2b507a25b6c91a579cd0b5b4f
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000020.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000025.xlog b/test/xlog/upgrade/1.6.6/00000000000000000025.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..4db6f2ede10eb1fd40553d54f72f7c49b99b24e2
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000025.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/00000000000000000030.xlog b/test/xlog/upgrade/1.6.6/00000000000000000030.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..3ebc094477532fc5e96f63af2a06c8f02d815ddb
Binary files /dev/null and b/test/xlog/upgrade/1.6.6/00000000000000000030.xlog differ
diff --git a/test/xlog/upgrade/1.6.6/version b/test/xlog/upgrade/1.6.6/version
new file mode 100644
index 0000000000000000000000000000000000000000..aeab2cd467ea8affd8e974c5952c00b0aba000dd
--- /dev/null
+++ b/test/xlog/upgrade/1.6.6/version
@@ -0,0 +1 @@
+1.6.6-125-g935cb31
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000000.snap b/test/xlog/upgrade/1.6.7/00000000000000000000.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9661c86094cd65b93a2c0075c2daa92ce0c928db
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000000.snap differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000000.xlog b/test/xlog/upgrade/1.6.7/00000000000000000000.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..272a2bd0e9557c6a711be6d9f3453f154dbb3281
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000000.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000005.xlog b/test/xlog/upgrade/1.6.7/00000000000000000005.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..942d1f429fb8744678132d4337a68d5e98a5ed18
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000005.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000010.xlog b/test/xlog/upgrade/1.6.7/00000000000000000010.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..29972a4ab1782daa9b0abd490973d621ea4cbd6b
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000010.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000015.xlog b/test/xlog/upgrade/1.6.7/00000000000000000015.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..79107829a3dc1d529189bc924d3c79c0bb49469f
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000015.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000020.xlog b/test/xlog/upgrade/1.6.7/00000000000000000020.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..58a1635e73bc2e5f9bb8415a7e479a2f0156e7c2
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000020.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000025.xlog b/test/xlog/upgrade/1.6.7/00000000000000000025.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..b21f71954feb2997633fae625be71fc771bdb38e
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000025.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/00000000000000000030.xlog b/test/xlog/upgrade/1.6.7/00000000000000000030.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..9cf81a0299d7e7e60b60fb0c855b2203dec88c0c
Binary files /dev/null and b/test/xlog/upgrade/1.6.7/00000000000000000030.xlog differ
diff --git a/test/xlog/upgrade/1.6.7/version b/test/xlog/upgrade/1.6.7/version
new file mode 100644
index 0000000000000000000000000000000000000000..bd3f1ab14ba46797a2cb6f5eb583e45eebd3032b
--- /dev/null
+++ b/test/xlog/upgrade/1.6.7/version
@@ -0,0 +1 @@
+1.6.7-469-g1d364fb
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000000.snap b/test/xlog/upgrade/1.6.8/00000000000000000000.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4cc2b72f80d1c057712f2eca4f3db87f0760716f
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000000.snap differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000000.xlog b/test/xlog/upgrade/1.6.8/00000000000000000000.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..00e297763e41903385cc741797214e5d30214548
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000000.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000005.xlog b/test/xlog/upgrade/1.6.8/00000000000000000005.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..32d519af6304eb79ab53b07f30946bbc0ba99d1e
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000005.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000010.xlog b/test/xlog/upgrade/1.6.8/00000000000000000010.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..33736ff979390451d431c26efdc5d99a5e2b9b40
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000010.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000015.xlog b/test/xlog/upgrade/1.6.8/00000000000000000015.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..ac59e2293b9f5f3043b1e02d41db07d2e764aded
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000015.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000020.xlog b/test/xlog/upgrade/1.6.8/00000000000000000020.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..fba68f420f696d1cf92bb618ae2c99ad390a2429
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000020.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000025.xlog b/test/xlog/upgrade/1.6.8/00000000000000000025.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..30caee5fdf9143622eb688be94f4cde5b3d6d762
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000025.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/00000000000000000030.xlog b/test/xlog/upgrade/1.6.8/00000000000000000030.xlog
new file mode 100644
index 0000000000000000000000000000000000000000..d12b3552ec8d433630b5198a9bf7f77f58167884
Binary files /dev/null and b/test/xlog/upgrade/1.6.8/00000000000000000030.xlog differ
diff --git a/test/xlog/upgrade/1.6.8/version b/test/xlog/upgrade/1.6.8/version
new file mode 100644
index 0000000000000000000000000000000000000000..5fb7b3e42dd7882edca11ab5d7be40eaf1da7087
--- /dev/null
+++ b/test/xlog/upgrade/1.6.8/version
@@ -0,0 +1 @@
+1.6.8-525-ga571ac0
diff --git a/test/xlog/upgrade/fill.lua b/test/xlog/upgrade/fill.lua
new file mode 100644
index 0000000000000000000000000000000000000000..cb38b08e3c0b0bd0bc044d225bee8a5b9c5cfd20
--- /dev/null
+++ b/test/xlog/upgrade/fill.lua
@@ -0,0 +1,59 @@
+---
+--- A script to generate some dataset used by migration.test.lua
+---
+
+box.cfg{ rows_per_wal = 5 }
+box.schema.space.create("distro")
+box.space.distro:create_index('primary', { type = 'hash', unique = true,
+    parts = {1, 'str', 2, 'str', 3, 'num'}})
+box.space.distro:create_index('codename', { type = 'hash', unique = true,
+    parts = {2, 'str'}})
+box.space.distro:create_index('time', { type = 'tree', unique = false,
+    parts = {4, 'num'}})
+
+local function d(year, month, day)
+    return os.time { year = year, month = month, day = day }
+end
+
+box.space.distro:insert({'debian', 'jessie', 80, d(2015, 4, 26)})
+box.space.distro:insert({'debian', 'wheezy', 70, d(2013, 5, 04)})
+box.space.distro:insert({'debian', 'squeeze', 60, d(2011, 2, 05)})
+box.space.distro:insert({'debian', 'lenny', 50, d(2009, 2, 14)})
+box.space.distro:insert({'debian', 'etch', 40, d(2007, 4, 8)})
+box.space.distro:insert({'debian', 'sarge', 31, d(2005, 6, 6)})
+box.space.distro:insert({'debian', 'woody', 30, d(2002, 7, 19)})
+box.space.distro:insert({'ubuntu', 'wily', 1510, d(2015, 10, 22)})
+box.space.distro:insert({'ubuntu', 'vivid', 1504, d(2015, 4, 23)})
+box.space.distro:insert({'ubuntu', 'trusty', 1404, d(2014, 4, 17)})
+box.space.distro:insert({'ubuntu', 'precise', 1510, d(2012, 4, 26)})
+
+-- 1.6.5+
+if box.space.distro.format ~= nil then
+    local format={}
+    format[1] = {name='os', type='str'}
+    format[2] = {name='dist', type='str'}
+    format[3] = {name='version', type='num'}
+    format[4] = {name='time', type='num'}
+    box.space.distro:format(format)
+end
+
+box.schema.space.create('temporary', { temporary = true })
+box.schema.user.create('someuser', { password  = 'somepassword' })
+box.schema.user.grant('someuser', 'read,write', 'universe')
+box.session.su('someuser')
+box.schema.func.create('somefunc', { setuid = true })
+box.session.su('admin')
+box.schema.user.revoke('someuser', 'read,write', 'universe')
+box.schema.role.create('somerole')
+box.schema.user.grant('someuser', 'execute', 'role', 'somerole')
+if _TARANTOOL == nil or  _TARANTOOL < "1.6.6" then
+    box.schema.user.grant('somerole', 'read,write', 'space', 'distro')
+    box.schema.user.grant('public', 'execute', 'function', 'somefunc')
+else
+    box.schema.role.grant('somerole', 'read,write', 'space', 'distro')
+    box.schema.role.grant('public', 'execute', 'function', 'somefunc')
+end
+box.schema.func.create('someotherfunc')
+box.schema.user.grant('someuser', 'execute', 'function', 'someotherfunc')
+box.schema.user.grant('someuser', 'read,write', 'space', 'temporary')
+os.exit(0)