Tarantool development patches archive
 help / color / mirror / Atom feed
From: Serge Petrenko <sergepetrenko@tarantool.org>
To: v.shpilevoy@tarantool.org, gorcunov@gmail.com, sergos@tarantool.org
Cc: tarantool-patches@dev.tarantool.org
Subject: [Tarantool-patches] [RAFT 05/10] [tosquash] xrow: refactor raft request codec
Date: Wed, 26 Aug 2020 10:52:37 +0300	[thread overview]
Message-ID: <c611dd646bdd1b9e9f849084945d02fbbbb62d32.1598427905.git.sergepetrenko@tarantool.org> (raw)
In-Reply-To: <cover.1598427905.git.sergepetrenko@tarantool.org>

From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>

There were a few issues:

- In decode() memset was used without raft_request tail assuming
  that vclock storage pointer is always in the end. Better not
  to assume such things. The patch makes the decode() caller to
  pass vclock storage explicitly if necessary.

- Little improvement over the readibility of the encoder to make
  more 'patterned'. Consisting of a sequence of similar code
  blocks of kind:

      if (is_field_set) {
          ++map_size;
          size += mp_sizeof_uint(field_key) +
                  mp_sizeof_...(field_value);
      }
      ...
      if (is_field_set) {
          pos = mp_encode_uint(pos, field_key);
          pos = mp_encode_...(pos, field_value);
      }

  Instead of unique handling of certain fields. Also the vote is
  now not encoded into each message, because no need in that.

- Added malformed packet handling. Note, that we don't consider
  the invalid MessagePack case. But probably should do it
  eventually. Other requests don't handle it, because they ar
  checked either by iproto thread or by relay thread. Need to see
  if raft message are also already validated by some mp_check()
  in relay.
---
 src/box/applier.cc     |  4 +--
 src/box/box.cc         |  3 +-
 src/box/memtx_engine.c |  3 +-
 src/box/xrow.c         | 76 +++++++++++++++++++++++++++---------------
 src/box/xrow.h         |  3 +-
 5 files changed, 57 insertions(+), 32 deletions(-)

diff --git a/src/box/applier.cc b/src/box/applier.cc
index f27436b79..8e6d1b2a4 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -886,9 +886,7 @@ apply_raft_row(struct xrow_header *row)
 
 	struct raft_request req;
 	struct vclock candidate_clock;
-	req.vclock = &candidate_clock;
-
-	if (xrow_decode_raft(row, &req) != 0)
+	if (xrow_decode_raft(row, &req, &candidate_clock) != 0)
 		return -1;
 
 	raft_process_msg(&req);
diff --git a/src/box/box.cc b/src/box/box.cc
index 8323de531..b871f45e2 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -377,7 +377,8 @@ apply_wal_row(struct xstream *stream, struct xrow_header *row)
 	}
 	if (iproto_type_is_raft_request(row->type)) {
 		struct raft_request raft_req;
-		if (xrow_decode_raft(row, &raft_req) != 0)
+		/* Vclock is never persisted in WAL by Raft. */
+		if (xrow_decode_raft(row, &raft_req, NULL) != 0)
 			diag_raise();
 		raft_process(&raft_req);
 		return;
diff --git a/src/box/memtx_engine.c b/src/box/memtx_engine.c
index 26274de80..a034baa6c 100644
--- a/src/box/memtx_engine.c
+++ b/src/box/memtx_engine.c
@@ -206,7 +206,8 @@ memtx_engine_recover_raft(const struct xrow_header *row)
 {
 	assert(row->type == IPROTO_RAFT);
 	struct raft_request req;
-	if (xrow_decode_raft(row, &req) != 0)
+	/* Vclock is never persisted in WAL by Raft. */
+	if (xrow_decode_raft(row, &req, NULL) != 0)
 		return -1;
 	raft_process(&req);
 	return 0;
diff --git a/src/box/xrow.c b/src/box/xrow.c
index 836de3575..11fdacc0d 100644
--- a/src/box/xrow.c
+++ b/src/box/xrow.c
@@ -958,25 +958,29 @@ int
 xrow_encode_raft(struct xrow_header *row, struct region *region,
 		 const struct raft_request *r)
 {
-	assert(mp_sizeof_map(2) == mp_sizeof_map(4));
 	/*
-	 * Term and vote are encoded every time for the sake of
-	 * snapshot, while state and vclock are optional.
+	 * Terms is encoded always. Sometimes the rest can be even ignored if
+	 * the term is too old.
 	 */
-	size_t size = mp_sizeof_map(2) +
-		      mp_sizeof_uint(IPROTO_RAFT_TERM) +
-		      mp_sizeof_uint(r->term) +
-		      mp_sizeof_uint(IPROTO_RAFT_VOTE) +
-		      mp_sizeof_uint(r->vote);
-
-	size += (r->state != 0) * (mp_sizeof_uint(IPROTO_RAFT_STATE) +
-				   mp_sizeof_uint(r->state));
+	int map_size = 1;
+	size_t size = mp_sizeof_uint(IPROTO_RAFT_TERM) +
+		      mp_sizeof_uint(r->term);
+	if (r->vote != 0) {
+		++map_size;
+		size += mp_sizeof_uint(IPROTO_RAFT_VOTE) +
+			mp_sizeof_uint(r->vote);
+	}
+	if (r->state != 0) {
+		++map_size;
+		size += mp_sizeof_uint(IPROTO_RAFT_STATE) +
+			mp_sizeof_uint(r->state);
+	}
 	if (r->vclock != NULL) {
+		++map_size;
 		size += mp_sizeof_uint(IPROTO_RAFT_VCLOCK) +
-		mp_sizeof_vclock_ignore0(r->vclock);
+			mp_sizeof_vclock_ignore0(r->vclock);
 	}
-
-	int map_size = 2 + (r->state != 0) + (r->vclock != NULL);
+	size += mp_sizeof_map(map_size);
 
 	char *buf = region_alloc(region, size);
 	if (buf == NULL) {
@@ -992,8 +996,10 @@ xrow_encode_raft(struct xrow_header *row, struct region *region,
 	buf = mp_encode_map(buf, map_size);
 	buf = mp_encode_uint(buf, IPROTO_RAFT_TERM);
 	buf = mp_encode_uint(buf, r->term);
-	buf = mp_encode_uint(buf, IPROTO_RAFT_VOTE);
-	buf = mp_encode_uint(buf, r->vote);
+	if (r->vote != 0) {
+		buf = mp_encode_uint(buf, IPROTO_RAFT_VOTE);
+		buf = mp_encode_uint(buf, r->vote);
+	}
 	if (r->state != 0) {
 		buf = mp_encode_uint(buf, IPROTO_RAFT_STATE);
 		buf = mp_encode_uint(buf, r->state);
@@ -1002,38 +1008,52 @@ xrow_encode_raft(struct xrow_header *row, struct region *region,
 		buf = mp_encode_uint(buf, IPROTO_RAFT_VCLOCK);
 		buf = mp_encode_vclock_ignore0(buf, r->vclock);
 	}
-
 	return 0;
 }
 
 int
-xrow_decode_raft(const struct xrow_header *row, struct raft_request *r)
+xrow_decode_raft(const struct xrow_header *row, struct raft_request *r,
+		 struct vclock *vclock)
 {
-	/* TODO: handle bad format. */
 	assert(row->type == IPROTO_RAFT);
-	assert(row->bodycnt == 1);
-	assert(row->group_id == GROUP_LOCAL);
-	memset(r, 0, sizeof(*r) - sizeof(struct vclock *));
-	const char *pos = row->body[0].iov_base;
+	if (row->bodycnt != 1 || row->group_id != GROUP_LOCAL) {
+		diag_set(ClientError, ER_INVALID_MSGPACK,
+			 "malformed raft request");
+		return -1;
+	}
+	memset(r, 0, sizeof(*r));
+	r->vclock = vclock;
+
+	const char *begin = row->body[0].iov_base;
+	const char *end = begin + row->body[0].iov_len;
+	const char *pos = begin;
 	uint32_t map_size = mp_decode_map(&pos);
 	for (uint32_t i = 0; i < map_size; ++i)
 	{
+		if (mp_typeof(*pos) != MP_UINT)
+			goto bad_msgpack;
 		uint64_t key = mp_decode_uint(&pos);
 		switch (key) {
 		case IPROTO_RAFT_TERM:
+			if (mp_typeof(*pos) != MP_UINT)
+				goto bad_msgpack;
 			r->term = mp_decode_uint(&pos);
 			break;
 		case IPROTO_RAFT_VOTE:
+			if (mp_typeof(*pos) != MP_UINT)
+				goto bad_msgpack;
 			r->vote = mp_decode_uint(&pos);
 			break;
 		case IPROTO_RAFT_STATE:
+			if (mp_typeof(*pos) != MP_UINT)
+				goto bad_msgpack;
 			r->state = mp_decode_uint(&pos);
 			break;
 		case IPROTO_RAFT_VCLOCK:
-			if (r->vclock != NULL)
-				mp_decode_vclock_ignore0(&pos, r->vclock);
-			else
+			if (r->vclock == NULL)
 				mp_next(&pos);
+			else if (mp_decode_vclock_ignore0(&pos, r->vclock) != 0)
+				goto bad_msgpack;
 			break;
 		default:
 			mp_next(&pos);
@@ -1041,6 +1061,10 @@ xrow_decode_raft(const struct xrow_header *row, struct raft_request *r)
 		}
 	}
 	return 0;
+
+bad_msgpack:
+	xrow_on_decode_err(begin, end, ER_INVALID_MSGPACK, "raft body");
+	return -1;
 }
 
 int
diff --git a/src/box/xrow.h b/src/box/xrow.h
index 5d571a821..c627102dd 100644
--- a/src/box/xrow.h
+++ b/src/box/xrow.h
@@ -276,7 +276,8 @@ xrow_encode_raft(struct xrow_header *row, struct region *region,
 		 const struct raft_request *r);
 
 int
-xrow_decode_raft(const struct xrow_header *row, struct raft_request *r);
+xrow_decode_raft(const struct xrow_header *row, struct raft_request *r,
+		 struct vclock *vclock);
 
 /**
  * CALL/EVAL request.
-- 
2.20.1 (Apple Git-117)

  parent reply	other threads:[~2020-08-26  7:53 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-26  7:52 [Tarantool-patches] [RAFT 00/10] raft implementation Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 01/10] raft: introduce persistent raft state Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 02/10] raft: relay status updates to followers Serge Petrenko
2020-08-27 20:36   ` Vladislav Shpilevoy
2020-08-28 10:10     ` Sergey Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 03/10] [tosquash] raft: return raft_request to xrow Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 04/10] [tosquash] raft: introduce IPROTO_RAFT_VCLOCK Serge Petrenko
2020-08-26  7:52 ` Serge Petrenko [this message]
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 06/10] [tosquash] raft: don't fill raft_request manually Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 07/10] [tosquash] raft: rename curr_leader to leader Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 08/10] [tosquash] raft: rename raft_process to raft_process_recovery Serge Petrenko
2020-08-26  7:52 ` [Tarantool-patches] [RAFT 09/10] [tosquash] applier: handler error at raft row appliance Serge Petrenko
2020-08-26  7:53 ` [Tarantool-patches] [RAFT 10/10] [tosquash] relay: move raft broadcast details into relay Serge Petrenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c611dd646bdd1b9e9f849084945d02fbbbb62d32.1598427905.git.sergepetrenko@tarantool.org \
    --to=sergepetrenko@tarantool.org \
    --cc=gorcunov@gmail.com \
    --cc=sergos@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [RAFT 05/10] [tosquash] xrow: refactor raft request codec' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox