Восстановление после "Duplicate key exists in unique index"

95 views
Skip to first unread message

Eugene Prokopiev

unread,
Jun 17, 2019, 2:34:52 AM6/17/19
to tarantool-ru
Здравствуйте!

Существует ли правильная процедура восстановления после ошибки "Duplicate key exists in unique index"? Воспроизвожу проблему так:

В каталоге ~/tnt/1:

$ tarantool
tarantool> box.cfg{listen=3001,replication={'127.0.0.1:3001','127.0.0.1:3002'}}

В каталоге ~/tnt/2:

$ tarantool
tarantool> box.cfg{listen=3002,replication={'127.0.0.1:3001','127.0.0.1:3002'}}
tarantool> box.schema.user.grant('guest', 'read,write,replication', 'universe')
tarantool> box.schema.space.create('db')
tarantool> box.space.db:create_index('id',{type='hash',parts={1,'number'}})
tarantool> box.space.db:insert({1,'one'})
tarantool> box.space.db:insert({2,'two'})
tarantool> box.space.db:select{}


Теперь блокирую обмен между экземплярами tarantool:

# iptables -A INPUT -p tcp --dport 3001 -j DROP
# iptables -A INPUT -p tcp --dport 3002 -j DROP

Добавляю кортеж на двух экземплярах:

tarantool> box.space.db:insert({3,'three'})
tarantool> box.space.db:select{}

Разблокирую обмен:

[root@app1 ~]# iptables -F

На обоих экземплярах получаю:

2019-06-17 08:53:56.057 [16769] main/106/applier/127.0.0.1:3002 box.cc:324 E> error applying row: {type: 'INSERT', replica_id: 1, lsn: 3, space_id: 512, index_id: 0, tuple: [3, "three"]}
2019-06-17 08:53:56.057 [16769] main/106/applier/127.0.0.1:3002 I> can't read row
2019-06-17 08:53:56.057 [16769] main/106/applier/127.0.0.1:3002 memtx_hash.c:287 E> ER_TUPLE_FOUND: Duplicate key exists in unique index 'id' in space 'db'


Я знаю, что допускать таких случаев нельзя. Но сейчас мне интересно, что делать, если это уже случилось?

Eugene Prokopiev

unread,
Jun 17, 2019, 3:20:49 AM6/17/19
to tarantool-ru
Добавлю, что запуск box.cfg с replication_skip_conflict=true проблему не решает - та же самая последовательность действий все равно приводит к остановке репликации:

2019-06-17 09:43:45.787 [17040] main/105/applier/127.0.0.1:3001 box.cc:324 E> error applying row: {type: 'INSERT', replica_id: 2, lsn: 1, space_id: 512, index_id: 0, tuple: [1, "one"]}
2019-06-17 09:48:44.783 [17040] main/101/interactive C> failed to synchronize with 1 out of 2 replicas
2019-06-17 09:48:44.783 [17040] main/101/interactive C> entering orphan mode
2019-06-17 09:48:44.784 [17040] main/111/checkpoint_daemon I> started
2019-06-17 09:48:44.784 [17040] main/111/checkpoint_daemon I> scheduled the next snapshot at Mon Jun 17 11:38:16 2019


Konstantin Osipov

unread,
Jun 17, 2019, 4:57:14 AM6/17/19
to tarant...@googlegroups.com
* Eugene Prokopiev <eugene.p...@gmail.com> [19/06/17 11:07]:
> Добавлю, что запуск box.cfg с replication_skip_conflict=true проблему не
> решает - та же самая последовательность действий все равно приводит к
> остановке репликации:

Попробуйте сделать box.snapshot() на обоих инстансах и
рестартовать.

Если не поможет, снимите пожалуйста box.info.vclock с обоих и
пришлите сюда.



--
Konstantin Osipov, Moscow, Russia

Eugene Prokopiev

unread,
Jun 17, 2019, 9:27:08 AM6/17/19
to tarantool-ru
Не помогло, снимаю:

tarantool> box.info.vclock
---
- {2: 1, 1: 4}

tarantool> box.info.vclock
---
- {1: 5}

понедельник, 17 июня 2019 г., 11:57:14 UTC+3 пользователь Konstantin Osipov написал:

Eugene Prokopiev

unread,
Jun 19, 2019, 1:13:29 AM6/19/19
to tarantool-ru
Пробую решить проблему с помощью https://www.tarantool.io/ru/doc/1.10/book/box/box_space/#box-space-before-replace :

#!/usr/bin/env tarantool

local console = require('console')
local log = require('log')

if arg[1] and arg[2] then
  box.cfg{listen=arg[1],replication={'127.0.0.1:'..arg[1],'127.0.0.1:'..arg[2]},read_only=false}
  box.once('init',function()

    box.schema.user.grant('guest', 'read,write,replication', 'universe')
    box.schema.space.create('db')

    box.space.db:create_index('id',{type='hash',parts={1,'number'}})
    box.space.db:before_replace(function(old, new)
      if not old and new and new.id and box.space.db:select{new.id} then
        log.info('BEFORE REPLACE NEW VALUE : '..new.id)
        return {math.random(10,100),'random'}
      else
        return
      end
    end)

    box.space.db:insert({1,'one'})
  end)
  console.start()
else
  print 'Wrong args'
end


Т.е. идея в том, чтобы вместо встроенного механизма проверки на уникальность проверить ее вручную и если уже есть такая запись - вставить вместо нее другую (random конечно не гарантирует уникальность, но для проверки идеи должен сгодиться)

Однако в случае моего конфликта дело до моего триггера даже не доходит. Как в триггере идентифицировать именно мой случай?
Reply all
Reply to author
Forward
0 new messages