Fix illegal type names when upgrading to 2.10.4
This is an upgrade guide for fixing one specific problem which could happen with field type names. It’s only relevant when you’re upgrading from a Tarantool version <=2.10.3 to >=2.10.4.
Before gh-5940 was fixed, the empty string, n
, nu
, s
,
and st
(that is, leading parts of num
and str
) were accepted as valid field types.
Since 2.10.4, Tarantool doesn’t accept these strings and they must be replaced with
correct values num
and str
.
This instruction is also available on GitHub.
A snapshot can be validated against the issue using the following script:
#!/usr/bin/env tarantool
local xlog = require('xlog')
local json = require('json')
if arg[1] == nil then
print(('Usage: %s xxxxxxxxxxxxxxxxxxxx.snap'):format(arg[0]))
os.exit(1)
end
local illegal_types = {
[''] = true,
['n'] = true,
['nu'] = true,
['s'] = true,
['st'] = true,
}
local function report_field_def(name, field_def)
local msg = 'A field def in a _space entry %q contains an illegal type: %s'
print(msg:format(name, json.encode(field_def)))
end
local has_broken_format = false
for _, record in xlog.pairs(arg[1]) do
-- Filter inserts.
if record.HEADER == nil or record.HEADER.type ~= 'INSERT' then
goto continue
end
-- Filter _space records.
if record.BODY == nil or record.BODY.space_id ~= 280 then
goto continue
end
local tuple = record.BODY.tuple
local name = tuple[3]
local format = tuple[7]
local is_format_broken = false
for _, field_def in ipairs(format) do
if illegal_types[field_def.type] ~= nil then
report_field_def(name, field_def)
is_format_broken = true
end
if illegal_types[field_def[2]] ~= nil then
report_field_def(name, field_def)
is_format_broken = true
end
end
if is_format_broken then
has_broken_format = true
local msg = 'The following _space entry contains illegal type(s): %s'
print(msg:format(json.encode(record)))
end
::continue::
end
if has_broken_format then
print('')
print(('%s has an illegal type in a space format'):format(arg[1]))
print('It is recommended to proceed with the upgrade instruction:')
print('https://github.com/tarantool/tarantool/wiki/Fix-illegal-field-type-in-a-space-format-when-upgrading-to-2.10.4')
else
print('Everything looks nice!')
end
os.exit(has_broken_format and 2 or 0)
If the snapshot contains the values that aren’t valid in 2.10.4, you’ll get an output like the following:
To fix the application file that contains illegal type names, add the following code in it
before the box.cfg()
/vshard.cfg()
/cartridge.cfg()
call.
Note
In Cartridge applications, the instance file is called init.lua
.
-- Convert illegal type names in a space format that were
-- allowed before tarantool 2.10.4.
local log = require('log')
local json = require('json')
local transforms = {
[''] = 'num',
['n'] = 'num',
['nu'] = 'num',
['s'] = 'str',
['st'] = 'str',
}
-- The helper for before_replace().
local function transform_field_def(name, field_def, field, new_type)
local field_def_old_str = json.encode(field_def)
field_def[field] = new_type
local field_def_new_str = json.encode(field_def)
local msg = 'Transform a field def in a _space entry %q: %s -> %s'
log.info(msg:format(name, field_def_old_str, field_def_new_str))
end
-- _space trigger.
local function before_replace(_, tuple)
if tuple == nil then return tuple end
local name = tuple[3]
local format = tuple[7]
-- Update format if necessary.
local is_format_changed = false
for i, field_def in ipairs(format) do
local new_type = transforms[field_def.type]
if new_type ~= nil then
transform_field_def(name, field_def, 'type', new_type)
is_format_changed = true
end
local new_type = transforms[field_def[2]]
if new_type ~= nil then
transform_field_def(name, field_def, 2, new_type)
is_format_changed = true
end
end
-- No changed: skip.
if not is_format_changed then return tuple end
-- Rebuild the tuple.
local new_tuple = tuple:transform(7, 1, format)
log.info(('Transformed _space entry %s to %s'):format(
json.encode(tuple), json.encode(new_tuple)))
return new_tuple
end
-- on_schema_init trigger to set before_replace().
local function on_schema_init()
box.space._space:before_replace(before_replace)
end
-- Set the trigger on _space.
box.ctl.on_schema_init(on_schema_init)
You can delete these triggers after the box.cfg()
/vshard.cfg()
/cartridge.cfg()
call.
An example for a Cartridge application:
The triggers will report the changes the make in the following form: