A fix for Bug#850031 "Assertion failure in iproto_interact()".
Fix fiber_bread() to read at_least bytes, not
buf->len - at_least bytes, as it used to work before.
Many places that call fiber_bread rely on this.
---
core/fiber.m | 26 ++++++++++++++++----------
core/log_io_remote.m | 39 ++++++++++++++-------------------------
include/fiber.h | 2 +-
3 files changed, 31 insertions(+), 36 deletions(-)
diff --git a/core/fiber.m b/core/fiber.m
index 69714e3..bd21edd 100644
--- a/core/fiber.m
+++ b/core/fiber.m
@@ -665,28 +665,34 @@ read_inbox(void)
}
/**
+ * Read at least at_least bytes from a socket.
+ *
+ * @retval 0 socket is closed by the sender
+ * @reval -1 a system error
+ * @retval >0 success, size of the last read chunk is returned
+ *
* @note: this is a cancellation point.
*/
-int
+ssize_t
fiber_bread(struct tbuf *buf, size_t at_least)
{
ssize_t r;
tbuf_ensure(buf, MAX(cfg.readahead, at_least));
+ size_t stop_at = buf->len + at_least;
fiber_io_start(fiber->fd, EV_READ);
- for (;;) {
+
+ while (buf->len < stop_at)
fiber_io_yield();
+
r = read(fiber->fd, buf->data + buf->len, buf->size - buf->len);
- if (r > 0) {
- buf->len += r;
- if (buf->len >= at_least)
- break;
- } else {
- if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
- continue;
+ if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ continue;
+ else if (r <= 0)
break;
- }
+
+ buf->len += r;
}
fiber_io_stop(fiber->fd, EV_READ);
diff --git a/core/log_io_remote.m b/core/log_io_remote.m
index 41b49e6..664bdad 100644
--- a/core/log_io_remote.m
+++ b/core/log_io_remote.m
@@ -42,36 +42,25 @@
static int
default_remote_row_handler(struct recovery_state *r, struct tbuf *row);
-static u32
-row_v11_len(struct tbuf *r)
-{
- if (r->len < sizeof(struct row_v11))
- return 0;
-
- if (r->len < sizeof(struct row_v11) + row_v11(r)->len)
- return 0;
-
- return sizeof(struct row_v11) + row_v11(r)->len;
-}
-
static struct tbuf *
remote_row_reader_v11()
{
- const int header_size = sizeof(struct row_v11);
- struct tbuf *m;
+ ssize_t to_read = sizeof(struct row_v11) - fiber->rbuf->len;
- for (;;) {
- if (row_v11_len(fiber->rbuf) != 0) {
- m = tbuf_split(fiber->rbuf, row_v11_len(fiber->rbuf));
- say_debug("read row bytes:%" PRIu32 " %s", m->len,
tbuf_to_hex(m));
- return m;
- }
+ if (to_read > 0 && fiber_bread(fiber->rbuf, to_read) <= 0)
+ goto error;
- if (fiber_bread(fiber->rbuf, header_size) <= 0) {
- say_error("unexpected eof reading row header");
- return NULL;
- }
- }
+ ssize_t request_len = row_v11(fiber->rbuf)->len + sizeof(struct
row_v11);
+ to_read = request_len - fiber->rbuf->len;
+
+ if (to_read > 0 && fiber_bread(fiber->rbuf, to_read) <= 0)
+ goto error;
+
+ say_debug("read row bytes:%" PRI_SSZ, request_len);
+ return tbuf_split(fiber->rbuf, request_len);
+error:
+ say_error("unexpected eof reading row header");
+ return NULL;
}
static struct tbuf *
diff --git a/include/fiber.h b/include/fiber.h
index 8b04ab6..bd51069 100644
--- a/include/fiber.h
+++ b/include/fiber.h
@@ -148,7 +148,7 @@ void yield(void);
void fiber_destroy_all();
struct msg *read_inbox(void);
-int fiber_bread(struct tbuf *, size_t v);
+ssize_t fiber_bread(struct tbuf *, size_t v);
inline static void iov_add_unsafe(const void *buf, size_t len)
{
--
1.7.0.4
_______________________________________________
Mailing list: https://launchpad.net/~tarantool-developers
Post to : [email protected]
Unsubscribe : https://launchpad.net/~tarantool-developers
More help : https://help.launchpad.net/ListHelp