Skip to content

Commit 5432188

Browse files
author
moticless
committed
On Send fail report Received error; Add MSG_NOSIGNAL
* If error occurred while writing to the server. In this case the function will try to read replies from the server. Maybe one of the replies will contain an error message that explains why write got failed. * Ignore SIGPIPE signal on write (Replace writev() with sendmsg())
1 parent df07dbc commit 5432188

File tree

1 file changed

+41
-15
lines changed

1 file changed

+41
-15
lines changed

src/ext/respToRedisLoader.c

+41-15
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,25 @@ static void onReadRepliesError(RdbxRespToRedisLoader *ctx) {
5454
ctx->respReader.countReplies);
5555
}
5656

57-
/* Read 'numToRead' replies from the socket. * Return 0 for success, 1 otherwise. */
58-
static int readReplies(RdbxRespToRedisLoader *ctx, int numToRead) {
57+
/* Read 'numToRead' replies from the socket.
58+
*
59+
* numToRead - minimum number of replies to read from the socket before
60+
* returning.
61+
* sendError - if set, an error occurred while writing to the server. In
62+
* this case the function will try to read replies from the
63+
* server. Maybe one of the replies will contain an error message
64+
* that explains why write got failed. Whether error message is
65+
* received or not, the function will return to the original issue.
66+
*
67+
* Return 0 for success, 1 otherwise. */
68+
static int readReplies(RdbxRespToRedisLoader *ctx, int numToRead, int sendError) {
5969
char buff[REPLY_BUFF_SIZE];
6070

6171
RespReaderCtx *respReader = &ctx->respReader;
6272
size_t countRepliesBefore = respReader->countReplies;
6373
size_t repliesExpected = respReader->countReplies + numToRead;
6474

65-
while (respReader->countReplies < repliesExpected) {
75+
while ((respReader->countReplies < repliesExpected) || (sendError)) {
6676
int bytesReceived = recv(ctx->fd, buff, sizeof(buff), 0);
6777

6878
if (bytesReceived > 0) {
@@ -71,12 +81,23 @@ static int readReplies(RdbxRespToRedisLoader *ctx, int numToRead) {
7181
onReadRepliesError(ctx);
7282
return 1;
7383
}
84+
continue;
85+
}
86+
87+
/* handle error */
88+
89+
if (sendError)
90+
return 0; /* Failed read error message from dst. Back to original issue. */
7491

75-
} else if (bytesReceived == 0) {
76-
RDB_reportError(ctx->p, (RdbRes) RDBX_ERR_RESP2REDIS_CONN_CLOSE, "Connection closed by the remote side");
92+
if (bytesReceived == 0) {
93+
RDB_reportError(ctx->p, (RdbRes) RDBX_ERR_RESP2REDIS_CONN_CLOSE,
94+
"Connection closed by the remote side");
7795
return 1;
7896
} else {
79-
RDB_reportError(ctx->p, (RdbRes) RDBX_ERR_RESP2REDIS_FAILED_READ, "Failed to recv() from Redis server. (errno=%d)", errno);
97+
RDB_reportError(ctx->p,
98+
(RdbRes) RDBX_ERR_RESP2REDIS_FAILED_READ,
99+
"Failed to recv() from Redis server. errno=%d: %s",
100+
errno, strerror(errno));
80101
return 1;
81102
}
82103
}
@@ -106,29 +127,30 @@ static int redisLoaderWritev(void *context, struct iovec *iov, int iovCnt,
106127
RdbxRespToRedisLoader *ctx = context;
107128

108129
if (unlikely(ctx->pendingCmds.num == ctx->pendingCmds.pipelineDepth)) {
109-
if (readReplies(ctx, 1 /* at least one */))
130+
if (readReplies(ctx, 1 /* at least one */, 0))
110131
return 1;
111132
}
112133

113134
if (startCmd) recordCommandSent(ctx, startCmd);
114135

115136
while (1)
116137
{
117-
writeResult = writev(ctx->fd, iov, iovCnt);
138+
struct msghdr msg = { .msg_iov = iov, .msg_iovlen = iovCnt };
139+
writeResult = sendmsg(ctx->fd, &msg, MSG_NOSIGNAL /*Ignore SIGPIPE signal*/);
118140

119141
/* check for error */
120142
if (unlikely(writeResult == -1)) {
121143
if (errno == EINTR) {
122144
if ((retries++) >= MAX_EINTR_RETRY) {
123145
RDB_reportError(ctx->p, (RdbRes) RDBX_ERR_RESP2REDIS_FAILED_WRITE,
124146
"Failed to write socket. Exceeded EINTR retry limit");
125-
return 1;
147+
break;
126148
}
127149
continue;
128150
} else {
129151
RDB_reportError(ctx->p, (RdbRes) RDBX_ERR_RESP2REDIS_FAILED_WRITE,
130152
"Failed to write socket (errno=%d)", errno);
131-
return 1;
153+
break;
132154
}
133155
}
134156

@@ -140,24 +162,28 @@ static int redisLoaderWritev(void *context, struct iovec *iov, int iovCnt,
140162
}
141163

142164
/* if managed to send all iov entries */
143-
if (likely(iovCnt == 0))
144-
break;
165+
if (likely(iovCnt == 0)) {
166+
ctx->pendingCmds.num += endCmd;
167+
return 0;
168+
}
145169

146170
/* Update pointed iov entry. Only partial of its data sent */
147171
iov->iov_len -= writeResult;
148172
iov->iov_base = (char *) iov->iov_base + writeResult;
149173
}
150174

151-
ctx->pendingCmds.num += endCmd;
152-
return 0;
175+
/* Error occurred. Try to receive error msg from dst, which might explain
176+
why write got failed */
177+
readReplies(ctx, 0, 1/*sendError*/);
178+
return 1;
153179
}
154180

155181
/* Flush the pending commands by reading the remaining replies.
156182
* Return 0 for success, 1 otherwise. */
157183
static int redisLoaderFlush(void *context) {
158184
RdbxRespToRedisLoader *ctx = context;
159185
if (ctx->pendingCmds.num)
160-
return readReplies(ctx, ctx->pendingCmds.num);
186+
return readReplies(ctx, ctx->pendingCmds.num, 0);
161187
return 0;
162188
}
163189

0 commit comments

Comments
 (0)