From 350b645a4790490bdd3f493b450814096697430a Mon Sep 17 00:00:00 2001
From: Georgy Kirichenko <georgy@tarantool.org>
Date: Thu, 23 Nov 2017 23:58:59 +0300
Subject: [PATCH] Don't exit from ddl until all other ddls are flushed

If any ddl operation is in progress then all other ddls are
waiting on schema latch. But after first ddl will be done any
other request may be issued just after it and commit order will be
broken in case of multimaster replication.  To prevent this
behavior any ddl operation should wait until all queued ddls are
done.

Fixes #2951
---
 src/box/alter.cc                        | 12 ++++++++++++
 test/replication/autobootstrap.result   | 21 +++++++++++++++++++++
 test/replication/autobootstrap.test.lua |  9 +++++++++
 3 files changed, 42 insertions(+)

diff --git a/src/box/alter.cc b/src/box/alter.cc
index 46c90c883a..e66863cbf1 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -3030,6 +3030,18 @@ unlock_after_dd(struct trigger *trigger, void *event)
 	(void) trigger;
 	(void) event;
 	latch_unlock(&schema_lock);
+	/*
+	 * There can be a some count of other latch awaiting fibers. All of
+	 * these fibers should continue their job before current fiber fires
+	 * next request. It is important especially for replication - if some
+	 * rows are applied out of order then lsn order will be broken. This
+	 * can be done with locking latch one more time - it guarantees that
+	 * all "queued" fibers did their job before current fiber wakes next
+	 * time. If there is no waiting fibers then locking will be done without
+	 * any yields.
+	 */
+	latch_lock(&schema_lock);
+	latch_unlock(&schema_lock);
 }
 
 static void
diff --git a/test/replication/autobootstrap.result b/test/replication/autobootstrap.result
index ae4e554024..04aeb4315f 100644
--- a/test/replication/autobootstrap.result
+++ b/test/replication/autobootstrap.result
@@ -204,6 +204,27 @@ box.space.test_u:select()
 _ = test_run:cmd("switch default")
 ---
 ...
+_ = test_run:cmd("switch autobootstrap1")
+---
+...
+for i = 0, 99 do box.schema.space.create('space' .. tostring(i)):format({{'id', 'unsigned'}}) end
+---
+...
+_ = test_run:cmd("switch autobootstrap2")
+---
+...
+_ = test_run:cmd("switch autobootstrap3")
+---
+...
+_ = test_run:cmd("switch autobootstrap1")
+---
+...
+for i = 0, 99 do box.space['space' .. tostring(i)]:drop() end
+---
+...
+_ = test_run:cmd("switch default")
+---
+...
 --
 -- Stop servers
 --
diff --git a/test/replication/autobootstrap.test.lua b/test/replication/autobootstrap.test.lua
index d8c1228391..f1e2a9991d 100644
--- a/test/replication/autobootstrap.test.lua
+++ b/test/replication/autobootstrap.test.lua
@@ -95,6 +95,15 @@ box.space.test_u:select()
 
 _ = test_run:cmd("switch default")
 
+_ = test_run:cmd("switch autobootstrap1")
+for i = 0, 99 do box.schema.space.create('space' .. tostring(i)):format({{'id', 'unsigned'}}) end
+_ = test_run:cmd("switch autobootstrap2")
+_ = test_run:cmd("switch autobootstrap3")
+
+_ = test_run:cmd("switch autobootstrap1")
+for i = 0, 99 do box.space['space' .. tostring(i)]:drop() end
+_ = test_run:cmd("switch default")
+
 --
 -- Stop servers
 --
-- 
GitLab