int map_join(lua_State *L) { int rc = 0; int err_rc = -1; map_t *map = (map_t *)lua_touserdata(L, 1); for (uint32_t i = 0; i < map->num_threads; i++) { if (map->threads[i].rb) { int ret = pthread_join(map->threads[i].thread, NULL); if (ret) return LUA_HANDLE_ERROR(L, ret); if (map->threads[i].ret) { err_rc = rc; } while (ringbuffer_peek(map->threads[i].rb)) { rb_load(L, map->threads[i].rb); rc++; } ringbuffer_destroy(map->threads[i].rb); } } free(map->threads); map->threads = NULL; map->num_threads = 0; if (err_rc >= 0) { return LUA_HANDLE_ERROR_STR(L, lua_tostring(L, err_rc - rc)); } return rc; }
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) { int i, ret; int status; int nchunks; int committedBytes; DataChunk chunks[2]; WINPR_BIO_BUFFERED_SOCKET* ptr = (WINPR_BIO_BUFFERED_SOCKET*) bio->ptr; ret = num; ptr->writeBlocked = FALSE; BIO_clear_flags(bio, BIO_FLAGS_WRITE); /* we directly append extra bytes in the xmit buffer, this could be prevented * but for now it makes the code more simple. */ if (buf && num && !ringbuffer_write(&ptr->xmitBuffer, (const BYTE*) buf, num)) { WLog_ERR(TAG, "an error occured when writing (num: %d)", num); return -1; } committedBytes = 0; nchunks = ringbuffer_peek(&ptr->xmitBuffer, chunks, ringbuffer_used(&ptr->xmitBuffer)); for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size); if (status <= 0) { if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); ret = -1; /* fatal error */ goto out; } if (BIO_should_write(bio->next_bio)) { BIO_set_flags(bio, BIO_FLAGS_WRITE); ptr->writeBlocked = TRUE; goto out; /* EWOULDBLOCK */ } } committedBytes += status; chunks[i].size -= status; chunks[i].data += status; } } out: ringbuffer_commit_read_bytes(&ptr->xmitBuffer, committedBytes); return ret; }
int16_t cereal_peek() { if (!ringbuffer_isempty(&cereal_incoming)) { return ringbuffer_peek(&cereal_incoming); } else { return -1; } }
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) { int status, ret; rdpTcp* tcp = (rdpTcp*) bio->ptr; int nchunks, committedBytes, i; DataChunk chunks[2]; ret = num; tcp->writeBlocked = FALSE; BIO_clear_flags(bio, BIO_FLAGS_WRITE); /* we directly append extra bytes in the xmit buffer, this could be prevented * but for now it makes the code more simple. */ if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num)) { fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num); return -1; } committedBytes = 0; nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer)); for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size); if (status <= 0) { if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); ret = -1; /* fatal error */ goto out; } if (BIO_should_write(bio->next_bio)) { BIO_set_flags(bio, BIO_FLAGS_WRITE); tcp->writeBlocked = TRUE; goto out; /* EWOULDBLOCK */ } } committedBytes += status; chunks[i].size -= status; chunks[i].data += status; } } out: ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes); return ret; }
/** * Get a pointer to the key. If the buffer isn't continous we need to * allocate a temporary chunk of memory and copy the packet over there. * packet will return the pointer to the newly allocated packet or * NULL if we didn't have to allocate anything. * * @param server the server owning the key * @param nkey the number of bytes in the key * @param packet where to store the result * @return pointer to the key */ static const char *get_key(lcb_server_t *server, lcb_uint16_t *nkey, char **packet) { protocol_binary_request_header req; lcb_size_t nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req)); lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req); char *keyptr; *packet = server->cmd_log.read_head; lcb_assert(nr == sizeof(req)); *nkey = ntohs(req.request.keylen); keyptr = *packet + sizeof(req) + req.request.extlen; *packet = NULL; if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, packetsize)) { *packet = malloc(packetsize); if (*packet == NULL) { lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL); return NULL; } nr = ringbuffer_peek(&server->cmd_log, *packet, packetsize); if (nr != packetsize) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); free(*packet); return NULL; } keyptr = *packet + sizeof(req) + req.request.extlen; } return keyptr; }
int map_check_errors(lua_State *L) { map_t *map = (map_t *)lua_touserdata(L, 1); for (uint32_t i = 0; i < map->num_threads; i++) { if (map->threads[i].ret) { pthread_join(map->threads[i].thread, NULL); while (ringbuffer_peek(map->threads[i].rb)) { rb_load(L, map->threads[i].rb); } ringbuffer_destroy(map->threads[i].rb); map->threads[i].rb = NULL; return LUA_HANDLE_ERROR_STR(L, lua_tostring(L, -1)); } } return 0; }
static int sock_send_msg(lua_State *L, int index, int sock, ringbuffer_t *rb, copy_context_t *copy_context) { ringbuffer_push_write_pos(rb); int ret = rb_save(L, index, rb, 1); if (ret) return LUA_HANDLE_ERROR(L, ret); size_t len = ringbuffer_peek(rb); ringbuffer_pop_write_pos(rb); if (ret) return ret; ret = sock_send(sock, &len, sizeof(len), copy_context); if (ret < 0) return LUA_HANDLE_ERROR(L, errno); if (ret != sizeof(len)) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes"); ret = sock_send(sock, ringbuffer_buf_ptr(rb), len, copy_context); if (ret < 0) return LUA_HANDLE_ERROR(L, errno); if ((size_t)ret != len) return LUA_HANDLE_ERROR_STR(L, "failed to send the correct number of bytes"); return 0; }
static void* thread_func(void *arg) { #ifdef _OPENMP // prevent MKL/BLAS from crashing on the reader threads // its use of open-mp eats up way too many threads omp_set_num_threads(1); #endif map_thread_t *map_thread = (map_thread_t *)arg; lua_State *L = luaL_newstate(); if (_ipc_static_init_thread) { _ipc_static_init_thread(L); } else { luaL_openlibs(L); } // in order to deserialize arguments we need torch and libipc // TODO: detect these on the main thread when serializing arguments int top = lua_gettop(L); if (luaL_loadstring(L, "require 'torch'; require 'libipc'; pcall(require, 'twutil')")) { lua_close(L); return NULL; } map_thread->ret = lua_pcall(L, 0, 0, 0); if (map_thread->ret) { fprintf(stderr, "WARN: ipc.map thread pcall failed: %s\n", lua_tostring(L, -1)); } else { top = lua_gettop(L); int i = 0; while (ringbuffer_peek(map_thread->rb)) { rb_load(L, map_thread->rb); i++; } map_thread->ret = lua_pcall(L, i - 1, LUA_MULTRET, 0); if (map_thread->ret) { fprintf(stderr, "WARN: ipc.map thread pcall failed: %s\n", lua_tostring(L, -1)); } } int k = lua_gettop(L) - top; for (int i = 1; i <= k; i++) { int ret = rb_save_with_growth(L, top + i, map_thread->rb); if (ret) { fprintf(stderr, "WARN: ipc.map thread failed to write results: %s\n", strerror(-ret)); map_thread->ret = ret; break; } } lua_close(L); return 0; }
APULSE_EXPORT int pa_stream_peek(pa_stream *s, const void **data, size_t *nbytes) { trace_info_f("F %s s=%p\n", __func__, s); if (!s) return -1; size_t len = ringbuffer_readable_size(s->rb); s->peek_buffer_data_len = ringbuffer_peek(s->rb, s->peek_buffer, len); if (nbytes) *nbytes = s->peek_buffer_data_len; if (data) *data = s->peek_buffer; return 0; }
static int workqueue_queue_write(lua_State *L, int index, queue_t *queue) { pthread_mutex_lock(&queue->mutex); int ret = 0; while (1) { ringbuffer_push_write_pos(queue->rb); ret = rb_save(L, index, queue->rb, 0); if (ret) { ringbuffer_pop_write_pos(queue->rb); if (ringbuffer_peek(queue->rb)) { pthread_cond_wait(&queue->write_avail_cond, &queue->mutex); } else { return LUA_HANDLE_ERROR_STR(L, "workqueue.write message is too big for the ring buffer."); } } else { break; } } queue->num_items++; pthread_cond_signal(&queue->read_avail_cond); pthread_mutex_unlock(&queue->mutex); return ret; }
static void observe_response_handler(lcb_server_t *server, packet_info *info) { lcb_t root = server->instance; lcb_error_t rc = map_error(root, PACKET_STATUS(info)); lcb_uint32_t ttp; lcb_uint32_t ttr; lcb_size_t pos; VBUCKET_CONFIG_HANDLE config; const char *end, *ptr; /** * If we have an error we must decode the request instead */ if (rc != LCB_SUCCESS) { protocol_binary_request_header req; lcb_size_t nr; nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes)); if (nr != sizeof(req.bytes)) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); abort(); } if (req.request.bodylen) { lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen); char *packet = server->cmd_log.read_head; int allocated = 0; if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) { packet = malloc(npacket); if (packet == NULL) { lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL); abort(); } nr = ringbuffer_peek(&server->cmd_log, packet, npacket); if (nr != npacket) { lcb_error_handler(root, LCB_EINTERNAL, NULL); free(packet); abort(); } allocated = 1; } lcb_failout_observe_request(server, &info->ct, packet, npacket, rc); if (allocated) { free(packet); } } return; } /** The CAS field is split into TTP/TTR values */ ptr = (char *)&info->res.response.cas; memcpy(&ttp, ptr, sizeof(ttp)); memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttp)); ttp = ntohl(ttp); ttr = ntohl(ttr); /** Actual payload sequence of (vb, nkey, key). Repeats multiple times */ ptr = info->payload; end = (char *)ptr + PACKET_NBODY(info); config = root->vbucket_config; for (pos = 0; ptr < end; pos++) { lcb_cas_t cas; lcb_uint8_t obs; lcb_uint16_t nkey, vb; const char *key; lcb_observe_resp_t resp; memcpy(&vb, ptr, sizeof(vb)); vb = ntohs(vb); ptr += sizeof(vb); memcpy(&nkey, ptr, sizeof(nkey)); nkey = ntohs(nkey); ptr += sizeof(nkey); key = (const char *)ptr; ptr += nkey; obs = *((lcb_uint8_t *)ptr); ptr += sizeof(obs); memcpy(&cas, ptr, sizeof(cas)); ptr += sizeof(cas); setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs, server->index == vbucket_get_master(config, vb), ttp, ttr); PACKET_TRACE(TRACE_OBSERVE_PROGRESS, info, rc, &resp); lcb_observe_invoke_callback(root, &info->ct, rc, &resp); } /* run callback with null-null-null to signal the end of transfer */ if ((info->ct.flags & LCB_CMD_F_OBS_BCAST) && lcb_lookup_server_with_command(root, CMD_OBSERVE, PACKET_OPAQUE(info), server) < 0) { lcb_observe_resp_t resp; memset(&resp, 0, sizeof(resp)); PACKET_TRACE_NORES(TRACE_OBSERVE_END, info, rc); lcb_observe_invoke_callback(root, &info->ct, LCB_SUCCESS, &resp); } }
int lcb_proto_parse_single(lcb_server_t *c, hrtime_t stop) { int rv; packet_info info; protocol_binary_request_header req; lcb_size_t nr; lcb_connection_t conn = &c->connection; rv = lcb_packet_read_ringbuffer(&info, conn->input); if (rv == -1) { return -1; } else if (rv == 0) { return 0; } /* Is it already timed out? */ nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req)); if (nr < sizeof(req) || /* the command log doesn't know about it */ (PACKET_OPAQUE(&info) < req.request.opaque && PACKET_OPAQUE(&info) > 0)) { /* sasl comes with zero opaque */ /* already processed. */ lcb_packet_release_ringbuffer(&info, conn->input); return 1; } nr = ringbuffer_peek(&c->output_cookies, &info.ct, sizeof(info.ct)); if (nr != sizeof(info.ct)) { lcb_error_handler(c->instance, LCB_EINTERNAL, NULL); lcb_packet_release_ringbuffer(&info, conn->input); return -1; } info.ct.vbucket = ntohs(req.request.vbucket); switch (info.res.response.magic) { case PROTOCOL_BINARY_REQ: /* * The only way to get request packets is if someone started * to send us TAP requests, and we don't support that anymore */ lcb_error_handler(c->instance, LCB_EINTERNAL, "Protocol error. someone sent us a command!"); return -1; case PROTOCOL_BINARY_RES: { int was_connected = c->connection_ready; rv = lcb_server_purge_implicit_responses(c, PACKET_OPAQUE(&info), stop, 0); if (rv != 0) { lcb_packet_release_ringbuffer(&info, conn->input); return -1; } if (c->instance->histogram) { lcb_record_metrics(c->instance, stop - info.ct.start, PACKET_OPCODE(&info)); } if (PACKET_STATUS(&info) != PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET || PACKET_OPCODE(&info) == CMD_GET_REPLICA || PACKET_OPCODE(&info) == CMD_OBSERVE) { rv = lcb_dispatch_response(c, &info); if (rv == -1) { lcb_error_handler(c->instance, LCB_EINTERNAL, "Received unknown command response"); abort(); return -1; } /* keep command and cookie until we get complete STAT response */ swallow_command(c, &info.res, was_connected); } else { rv = handle_not_my_vbucket(c, &info, &req, &info.ct); if (rv == -1) { return -1; } else if (rv == 0) { lcb_dispatch_response(c, &info); swallow_command(c, &info.res, was_connected); } } break; } default: lcb_error_handler(c->instance, LCB_PROTOCOL_ERROR, NULL); lcb_packet_release_ringbuffer(&info, conn->input); return -1; } lcb_packet_release_ringbuffer(&info, conn->input); return 1; }
static void observe_response_handler(lcb_server_t *server, struct lcb_command_data_st *command_data, protocol_binary_response_header *res) { lcb_t root = server->instance; lcb_uint16_t status = ntohs(res->response.status); lcb_error_t rc = map_error(root, status); lcb_uint32_t ttp; lcb_uint32_t ttr; lcb_size_t pos; VBUCKET_CONFIG_HANDLE config; const char *end, *ptr = (const char *)&res->response.cas; /** * If we have an error we must decode the request instead */ if (rc != LCB_SUCCESS) { protocol_binary_request_header req; lcb_size_t nr; nr = ringbuffer_peek(&server->cmd_log, req.bytes, sizeof(req.bytes)); if (nr != sizeof(req.bytes)) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); abort(); } if (req.request.bodylen) { lcb_size_t npacket = sizeof(req.bytes) + ntohl(req.request.bodylen); char *packet = server->cmd_log.read_head; int allocated = 0; if (!ringbuffer_is_continous(&server->cmd_log, RINGBUFFER_READ, npacket)) { packet = malloc(npacket); if (packet == NULL) { lcb_error_handler(root, LCB_CLIENT_ENOMEM, NULL); abort(); } nr = ringbuffer_peek(&server->cmd_log, packet, npacket); if (nr != npacket) { lcb_error_handler(root, LCB_EINTERNAL, NULL); free(packet); abort(); } allocated = 1; } lcb_failout_observe_request(server, command_data, packet, npacket, rc); if (allocated) { free(packet); } } return; } memcpy(&ttp, ptr, sizeof(ttp)); ttp = ntohl(ttp); memcpy(&ttr, ptr + sizeof(ttp), sizeof(ttr)); ttr = ntohl(ttr); ptr = (const char *)res + sizeof(res->bytes); end = ptr + ntohl(res->response.bodylen); config = root->vbucket_config; for (pos = 0; ptr < end; pos++) { lcb_cas_t cas; lcb_uint8_t obs; lcb_uint16_t nkey, vb; const char *key; lcb_observe_resp_t resp; memcpy(&vb, ptr, sizeof(vb)); vb = ntohs(vb); ptr += sizeof(vb); memcpy(&nkey, ptr, sizeof(nkey)); nkey = ntohs(nkey); ptr += sizeof(nkey); key = (const char *)ptr; ptr += nkey; obs = *((lcb_uint8_t *)ptr); ptr += sizeof(obs); memcpy(&cas, ptr, sizeof(cas)); ptr += sizeof(cas); setup_lcb_observe_resp_t(&resp, key, nkey, cas, obs, server->index == vbucket_get_master(config, vb), ttp, ttr); TRACE_OBSERVE_PROGRESS(res->response.opaque, command_data->vbucket, res->response.opcode, rc, &resp); lcb_observe_invoke_callback(root, command_data, rc, &resp); } /* run callback with null-null-null to signal the end of transfer */ if ((command_data->flags & LCB_CMD_F_OBS_BCAST) && lcb_lookup_server_with_command(root, CMD_OBSERVE, res->response.opaque, server) < 0) { lcb_observe_resp_t resp; memset(&resp, 0, sizeof(resp)); TRACE_OBSERVE_END(res->response.opaque, command_data->vbucket, res->response.opcode, rc); lcb_observe_invoke_callback(root, command_data, LCB_SUCCESS, &resp); } }
static int parse_single(libcouchbase_server_t *c, hrtime_t stop) { protocol_binary_request_header req; protocol_binary_response_header header; libcouchbase_size_t nr; char *packet; libcouchbase_size_t packetsize; struct libcouchbase_command_data_st ct; nr = ringbuffer_peek(&c->input, header.bytes, sizeof(header)); if (nr < sizeof(header)) { return 0; } packetsize = ntohl(header.response.bodylen) + (libcouchbase_uint32_t)sizeof(header); if (c->input.nbytes < packetsize) { return 0; } /* Is it already timed out? */ nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req)); if (nr < sizeof(req) || /* the command log doesn't know about it */ (header.response.opaque < req.request.opaque && header.response.opaque > 0)) { /* sasl comes with zero opaque */ /* already processed. */ ringbuffer_consumed(&c->input, packetsize); return 1; } packet = c->input.read_head; /* we have everything! */ if (!ringbuffer_is_continous(&c->input, RINGBUFFER_READ, packetsize)) { /* The buffer isn't continous.. for now just copy it out and ** operate on the copy ;) */ if ((packet = malloc(packetsize)) == NULL) { libcouchbase_error_handler(c->instance, LIBCOUCHBASE_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_read(&c->input, packet, packetsize); if (nr != packetsize) { libcouchbase_error_handler(c->instance, LIBCOUCHBASE_EINTERNAL, NULL); free(packet); return -1; } } nr = ringbuffer_peek(&c->output_cookies, &ct, sizeof(ct)); if (nr != sizeof(ct)) { libcouchbase_error_handler(c->instance, LIBCOUCHBASE_EINTERNAL, NULL); if (packet != c->input.read_head) { free(packet); } return -1; } ct.vbucket = ntohs(req.request.vbucket); switch (header.response.magic) { case PROTOCOL_BINARY_REQ: c->instance->request_handler[header.response.opcode](c, &ct, (void *)packet); break; case PROTOCOL_BINARY_RES: { int was_connected = c->connected; if (libcouchbase_server_purge_implicit_responses(c, header.response.opaque, stop) != 0) { if (packet != c->input.read_head) { free(packet); } return -1; } if (c->instance->histogram) { libcouchbase_record_metrics(c->instance, stop - ct.start, header.response.opcode); } if (ntohs(header.response.status) != PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET || header.response.opcode == CMD_GET_REPLICA) { c->instance->response_handler[header.response.opcode](c, &ct, (void *)packet); /* keep command and cookie until we get complete STAT response */ if (was_connected && (header.response.opcode != PROTOCOL_BINARY_CMD_STAT || header.response.keylen == 0)) { nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req)); assert(nr == sizeof(req)); ringbuffer_consumed(&c->cmd_log, ntohl(req.request.bodylen)); ringbuffer_consumed(&c->output_cookies, sizeof(ct)); } } else { int idx; char *body; libcouchbase_size_t nbody; libcouchbase_server_t *new_srv; /* re-schedule command to new server */ nr = ringbuffer_read(&c->cmd_log, req.bytes, sizeof(req)); assert(nr == sizeof(req)); idx = vbucket_found_incorrect_master(c->instance->vbucket_config, ntohs(req.request.vbucket), (int)c->index); assert((libcouchbase_size_t)idx < c->instance->nservers); new_srv = c->instance->servers + idx; req.request.opaque = ++c->instance->seqno; nbody = ntohl(req.request.bodylen); body = malloc(nbody); if (body == NULL) { libcouchbase_error_handler(c->instance, LIBCOUCHBASE_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_read(&c->cmd_log, body, nbody); assert(nr == nbody); nr = ringbuffer_read(&c->output_cookies, &ct, sizeof(ct)); assert(nr == sizeof(ct)); /* Preserve the cookie and timestamp for the command. This means * that the library will retry the command until its time will * out and the client will get LIBCOUCHBASE_ETIMEDOUT error in * command callback */ libcouchbase_server_retry_packet(new_srv, &ct, &req, sizeof(req)); libcouchbase_server_write_packet(new_srv, body, nbody); libcouchbase_server_end_packet(new_srv); libcouchbase_server_send_packets(new_srv); free(body); } break; } default: libcouchbase_error_handler(c->instance, LIBCOUCHBASE_PROTOCOL_ERROR, NULL); if (packet != c->input.read_head) { free(packet); } return -1; } if (packet != c->input.read_head) { free(packet); } else { ringbuffer_consumed(&c->input, packetsize); } return 1; }
int tls_write_all(rdpTls* tls, const BYTE* data, int length) { int status, nchunks, commitedBytes; rdpTcp *tcp; #ifdef HAVE_POLL_H struct pollfd pollfds; #else fd_set rset, wset; fd_set *rsetPtr, *wsetPtr; struct timeval tv; #endif BIO* bio = tls->bio; DataChunk chunks[2]; BIO* bufferedBio = findBufferedBio(bio); if (!bufferedBio) { DEBUG_WARN( "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__); return -1; } tcp = (rdpTcp*) bufferedBio->ptr; do { status = BIO_write(bio, data, length); if (status > 0) break; if (!BIO_should_retry(bio)) return -1; #ifdef HAVE_POLL_H pollfds.fd = tcp->sockfd; pollfds.revents = 0; pollfds.events = 0; if (tcp->writeBlocked) { pollfds.events |= POLLOUT; } else if (tcp->readBlocked) { pollfds.events |= POLLIN; } else { DEBUG_WARN( "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); USleep(10); continue; } do { status = poll(&pollfds, 1, 100); } while ((status < 0) && (errno == EINTR)); #else /* we try to handle SSL want_read and want_write nicely */ rsetPtr = wsetPtr = NULL; if (tcp->writeBlocked) { wsetPtr = &wset; FD_ZERO(&wset); FD_SET(tcp->sockfd, &wset); } else if (tcp->readBlocked) { rsetPtr = &rset; FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); } else { DEBUG_WARN( "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__); USleep(10); continue; } tv.tv_sec = 0; tv.tv_usec = 100 * 1000; status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv); #endif if (status < 0) return -1; } while (TRUE); /* make sure the output buffer is empty */ commitedBytes = 0; while ((nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer)))) { int i; for (i = 0; i < nchunks; i++) { while (chunks[i].size) { status = BIO_write(tcp->socketBio, chunks[i].data, chunks[i].size); if (status > 0) { chunks[i].size -= status; chunks[i].data += status; commitedBytes += status; continue; } if (!BIO_should_retry(tcp->socketBio)) goto out_fail; #ifdef HAVE_POLL_H pollfds.fd = tcp->sockfd; pollfds.events = POLLIN; pollfds.revents = 0; do { status = poll(&pollfds, 1, 100); } while ((status < 0) && (errno == EINTR)); #else FD_ZERO(&rset); FD_SET(tcp->sockfd, &rset); tv.tv_sec = 0; tv.tv_usec = 100 * 1000; status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv); #endif if (status < 0) goto out_fail; } } } ringbuffer_commit_read_bytes(&tcp->xmitBuffer, commitedBytes); return length; out_fail: ringbuffer_commit_read_bytes(&tcp->xmitBuffer, commitedBytes); return -1; }
bool unittest_ringbuffer(void) { uint8_t byteBuffer[128]; unsigned length; ringbuffer_t rb = { byteBuffer, sizeof(byteBuffer), 0, 0 }; log_logMessage(LOGLEVEL_INFO, "Testing ringbuffer"); // Initialize the buffer. ringbuffer_init(&rb); // Write bytes to the buffer, then read them. for (length = 0;length <= sizeof(byteBuffer) + 1;length ++) { ringbuffer_status_t rs; unsigned rl, wl; // Write 0..length bytes to the ringbuffer. for (wl = 0;wl < length;wl ++) { rs = ringbuffer_put(&rb, (length + wl) & 0xff); if (wl < sizeof(byteBuffer)) { expectTrue(ring_ok == rs); expectTrue(ringbuffer_length(&rb) == (wl + 1)); } else { expectTrue(ring_full == rs); expectTrue(ringbuffer_length(&rb) == sizeof(byteBuffer)); } } // for wl if (wl > sizeof(byteBuffer)) { wl = sizeof(byteBuffer); } // Read 1..length+1 bytes from the ringbuffer. for (rl = 0;rl <= length;rl ++) { int c = ringbuffer_get(&rb); if (rl < wl) { expectTrue(c >= 0); expectTrue(((length + rl) & 0xff) == c); expectTrue(ringbuffer_length(&rb) == (wl - rl - 1)); } else { expectTrue(c < 0); expectTrue(ringbuffer_length(&rb) == 0); } c = ringbuffer_peek(&rb); if (rl + 1 < wl) { expectTrue(c >= 0); expectTrue(((length + rl + 1) & 0xff) == c); } else { expectTrue(c < 0); } } // for rl } // for length return true; } // unittest_ringbuffer()
/* * Drop all packets with sequence number less than specified. * * The packets are considered as stale and the caller will receive * appropriate error code in the operation callback. * * Returns 0 on success */ int lcb_server_purge_implicit_responses(lcb_server_t *c, lcb_uint32_t seqno, hrtime_t end, int all) { protocol_binary_request_header req; /** Instance level allocated buffers */ ringbuffer_t *cmdlog, *cookies; lcb_size_t nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req)); /* There should at _LEAST_ be _ONE_ message in here if we're not * trying to purge _ALL_ of the messages in the queue */ if (all && nr == 0) { return 0; } /** * Reading the command log is not re-entrant safe, as an additional * command to the same server may result in the command log being modified. * To this end, we must first buffer all the commands in a separate * ringbuffer (or simple buffer) for that matter, and only *then* * invoke the callbacks */ lcb_assert(nr == sizeof(req)); if (req.request.opaque >= seqno) { return 0; } cmdlog = &c->instance->purged_buf; cookies = &c->instance->purged_cookies; ringbuffer_reset(cmdlog); ringbuffer_reset(cookies); /** * Move all the commands we want to purge into the relevant ("local") buffers. * We will later read from these local buffers */ while (req.request.opaque < seqno) { lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req); ringbuffer_memcpy(cmdlog, &c->cmd_log, packetsize); ringbuffer_consumed(&c->cmd_log, packetsize); ringbuffer_memcpy(cookies, &c->output_cookies, sizeof(struct lcb_command_data_st)); ringbuffer_consumed(&c->output_cookies, sizeof(struct lcb_command_data_st)); nr = ringbuffer_peek(&c->cmd_log, req.bytes, sizeof(req.bytes)); if (!nr) { break; } lcb_assert(nr == sizeof(req)); } nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req)); lcb_assert(nr == sizeof(req)); if (!all) { lcb_assert(c->cmd_log.nbytes); } do { struct lcb_command_data_st ct; char *packet = cmdlog->read_head; lcb_size_t packetsize = ntohl(req.request.bodylen) + (lcb_uint32_t)sizeof(req); char *keyptr; union { lcb_get_resp_t get; lcb_store_resp_t store; lcb_remove_resp_t remove; lcb_touch_resp_t touch; lcb_unlock_resp_t unlock; lcb_arithmetic_resp_t arithmetic; lcb_observe_resp_t observe; } resp; nr = ringbuffer_read(cookies, &ct, sizeof(ct)); lcb_assert(nr == sizeof(ct)); if (c->instance->histogram) { lcb_record_metrics(c->instance, end - ct.start, req.request.opcode); } if (!ringbuffer_is_continous(cmdlog, RINGBUFFER_READ, packetsize)) { packet = malloc(packetsize); if (packet == NULL) { lcb_error_handler(c->instance, LCB_CLIENT_ENOMEM, NULL); return -1; } nr = ringbuffer_peek(cmdlog, packet, packetsize); if (nr != packetsize) { lcb_error_handler(c->instance, LCB_EINTERNAL, NULL); free(packet); return -1; } } switch (req.request.opcode) { case PROTOCOL_BINARY_CMD_GATQ: case PROTOCOL_BINARY_CMD_GETQ: keyptr = packet + sizeof(req) + req.request.extlen; setup_lcb_get_resp_t(&resp.get, keyptr, ntohs(req.request.keylen), NULL, 0, 0, 0, 0); TRACE_GET_END(req.request.opaque, ntohs(req.request.vbucket), req.request.opcode, LCB_KEY_ENOENT, &resp.get); c->instance->callbacks.get(c->instance, ct.cookie, LCB_KEY_ENOENT, &resp.get); break; case CMD_OBSERVE: lcb_failout_observe_request(c, &ct, packet, sizeof(req.bytes) + ntohl(req.request.bodylen), LCB_SERVER_BUG); break; case PROTOCOL_BINARY_CMD_NOOP: break; default: { char errinfo[128] = { '\0' }; snprintf(errinfo, 128, "Unknown implicit send message op=%0x", req.request.opcode); lcb_error_handler(c->instance, LCB_EINTERNAL, errinfo); return -1; } } if (packet != cmdlog->read_head) { free(packet); } ringbuffer_consumed(cmdlog, packetsize); nr = ringbuffer_peek(cmdlog, req.bytes, sizeof(req)); if (nr == 0) { return 0; } lcb_assert(nr == sizeof(req)); } while (1); /* CONSTCOND */ return 0; }
static void purge_single_server(lcb_server_t *server, lcb_error_t error, hrtime_t min_nonstale, hrtime_t *tmo_next) { protocol_binary_request_header req; struct lcb_command_data_st ct; lcb_size_t nr; char *packet; lcb_size_t packetsize; char *keyptr; ringbuffer_t rest; ringbuffer_t *stream = &server->cmd_log; ringbuffer_t *cookies; ringbuffer_t *mirror = NULL; /* mirror buffer should be purged with main stream */ lcb_connection_t conn = &server->connection; lcb_size_t send_size = 0; lcb_size_t stream_size = ringbuffer_get_nbytes(stream); hrtime_t now = gethrtime(); if (server->connection_ready) { cookies = &server->output_cookies; } else { cookies = &server->pending_cookies; mirror = &server->pending; } if (conn->output) { /* This will usually be false for v1 */ send_size = ringbuffer_get_nbytes(conn->output); } lcb_assert(ringbuffer_initialize(&rest, 1024)); do { int allocated = 0; lcb_uint32_t headersize; lcb_uint16_t nkey; nr = ringbuffer_peek(cookies, &ct, sizeof(ct)); if (nr != sizeof(ct)) { break; } nr = ringbuffer_peek(stream, req.bytes, sizeof(req)); if (nr != sizeof(req)) { break; } packetsize = (lcb_uint32_t)sizeof(req) + ntohl(req.request.bodylen); if (stream->nbytes < packetsize) { break; } if (min_nonstale && ct.start >= min_nonstale) { lcb_log(LOGARGS(server, INFO), "Still have %d ms remaining for command", (ct.start - min_nonstale) / 1000000); if (tmo_next) { *tmo_next = (ct.start - min_nonstale) + 1; } break; } lcb_log(LOGARGS(server, INFO), "Command with cookie=%p timed out from server %s:%s", ct.cookie, server->curhost.host, server->curhost.port); ringbuffer_consumed(cookies, sizeof(ct)); lcb_assert(nr == sizeof(req)); packet = stream->read_head; if (server->instance->histogram) { lcb_record_metrics(server->instance, now - ct.start, req.request.opcode); } if (server->connection_ready && stream_size > send_size && (stream_size - packetsize) < send_size) { /* Copy the rest of the current packet into the temporary stream */ /* I do believe I have some IOV functions to do that? */ lcb_size_t nbytes = packetsize - (stream_size - send_size); lcb_assert(ringbuffer_memcpy(&rest, conn->output, nbytes) == 0); ringbuffer_consumed(conn->output, nbytes); send_size -= nbytes; } stream_size -= packetsize; headersize = (lcb_uint32_t)sizeof(req) + req.request.extlen + htons(req.request.keylen); if (!ringbuffer_is_continous(stream, RINGBUFFER_READ, headersize)) { packet = malloc(headersize); if (packet == NULL) { lcb_error_handler(server->instance, LCB_CLIENT_ENOMEM, NULL); abort(); } nr = ringbuffer_peek(stream, packet, headersize); if (nr != headersize) { lcb_error_handler(server->instance, LCB_EINTERNAL, NULL); free(packet); abort(); } allocated = 1; } keyptr = packet + sizeof(req) + req.request.extlen; nkey = ntohs(req.request.keylen); failout_single_request(server, &req, &ct, error, keyptr, nkey, packet); if (allocated) { free(packet); } ringbuffer_consumed(stream, packetsize); if (mirror) { ringbuffer_consumed(mirror, packetsize); } } while (1); /* CONSTCOND */ if (server->connection_ready && conn->output) { /* Preserve the rest of the stream */ lcb_size_t nbytes = ringbuffer_get_nbytes(stream); send_size = ringbuffer_get_nbytes(conn->output); if (send_size >= nbytes) { ringbuffer_consumed(conn->output, send_size - nbytes); lcb_assert(ringbuffer_memcpy(&rest, conn->output, nbytes) == 0); } ringbuffer_reset(conn->output); ringbuffer_append(&rest, conn->output); } ringbuffer_destruct(&rest); lcb_maybe_breakout(server->instance); }