diff --git a/src/Makefile.in b/src/Makefile.in index 2dd611c..15ab52a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -9,7 +9,7 @@ TOP_HEADERS = sf_types.h sf_global.h sf_define.h sf_nio.h sf_service.h \ sf_func.h sf_util.h sf_configs.h sf_proto.h sf_binlog_writer.h \ sf_cluster_cfg.h sf_sharding_htable.h sf_connection_manager.h \ sf_serializer.h sf_binlog_index.h sf_file_writer.h \ - sf_ordered_writer.h + sf_ordered_writer.h sf_iov.h IDEMP_SERVER_HEADER = idempotency/server/server_types.h \ idempotency/server/server_channel.h \ @@ -24,7 +24,7 @@ IDEMP_CLIENT_HEADER = idempotency/client/client_types.h \ ALL_HEADERS = $(TOP_HEADERS) $(IDEMP_SERVER_HEADER) $(IDEMP_CLIENT_HEADER) -SHARED_OBJS = sf_nio.lo sf_service.lo sf_global.lo \ +SHARED_OBJS = sf_nio.lo sf_iov.lo sf_service.lo sf_global.lo \ sf_func.lo sf_util.lo sf_configs.lo sf_proto.lo \ sf_binlog_writer.lo sf_sharding_htable.lo \ sf_cluster_cfg.lo sf_connection_manager.lo \ diff --git a/src/sf_iov.c b/src/sf_iov.c new file mode 100644 index 0000000..6aa65c4 --- /dev/null +++ b/src/sf_iov.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2020 YuQing <384681@qq.com> + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "fastcommon/logger.h" +#include "fastcommon/sockopt.h" +#include "sf_define.h" +#include "sf_iov.h" + +int sf_iova_consume(SFDynamicIOVArray *iova, const int consume_len) +{ + struct iovec *iob; + int bytes; + int remain_len; + int result; + + if (iova->cnt <= 0) { + logError("file: "__FILE__", line: %d, " + "invalid iov count: %d", __LINE__, iova->cnt); + return EINVAL; + } + + if ((result=sf_iova_check_alloc(iova)) != 0) { + return result; + } + + iob = iova->iov; + bytes = iob->iov_len; + while (bytes < consume_len) { + ++iob; + bytes += iob->iov_len; + } + if (bytes == consume_len) { + ++iob; + if (iob < (iova->iov + iova->cnt)) { + bytes += iob->iov_len; + } + } + + iova->cnt -= (iob - iova->iov); + iova->iov = iob; + if (iova->cnt == 0) { + struct iovec *last; + last = iob - 1; + last->iov_base = (char *)last->iov_base + last->iov_len; + last->iov_len = 0; + } else { + /* adjust the first element */ + remain_len = bytes - consume_len; + if (remain_len < iob->iov_len) { + iob->iov_base = (char *)iob->iov_base + + (iob->iov_len - remain_len); + iob->iov_len = remain_len; + } + } + + return 0; +} + +static inline void iova_slice(SFDynamicIOVArray *iova, const int slice_len) +{ + struct iovec *iob; + struct iovec *end; + int bytes; + int exceed_len; + + bytes = 0; + end = iova->ptr + iova->input.cnt; + for (iob=iova->iov; iobiov_len; + if (bytes > slice_len) { + exceed_len = bytes - slice_len; + iob->iov_len -= exceed_len; + break; + } else if (bytes == slice_len) { + break; + } + } + + iova->cnt = (iob - iova->iov) + 1; +} + +int sf_iova_first_slice(SFDynamicIOVArray *iova, const int slice_len) +{ + int result; + + if ((result=sf_iova_check_alloc(iova)) != 0) { + return result; + } + + iova_slice(iova, slice_len); + return 0; +} + +int sf_iova_next_slice(SFDynamicIOVArray *iova, + const int consume_len, const int slice_len) +{ + struct iovec *last; + struct iovec *origin; + int remain_len; + int result; + + if ((result=sf_iova_consume(iova, consume_len)) != 0) { + return result; + } + + last = iova->iov + iova->cnt - 1; + origin = iova->input.iov + (last - iova->ptr); + remain_len = ((char *)origin->iov_base + origin->iov_len) - + (char *)last->iov_base; + if (last->iov_len != remain_len) { + last->iov_len = remain_len; + if (iova->cnt == 0) { + iova->iov = last; + } + } + + iova_slice(iova, slice_len); + return 0; +} diff --git a/src/sf_iov.h b/src/sf_iov.h new file mode 100644 index 0000000..3e21ee9 --- /dev/null +++ b/src/sf_iov.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 YuQing <384681@qq.com> + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef _SF_IOV_H +#define _SF_IOV_H + +#include "fastcommon/shared_func.h" +#include "sf_types.h" + +#define SF_IOV_FIXED_SIZE 256 + +typedef struct sf_dynamic_iov_array { + struct iovec holder[SF_IOV_FIXED_SIZE]; + struct iovec *ptr; + + struct { + struct iovec *iov; + int cnt; + } input; + + struct iovec *iov; + int cnt; +} SFDynamicIOVArray; + +#define sf_iova_init(iova, _iov, _cnt) \ + (iova).iov = (iova).input.iov = _iov; \ + (iova).cnt = (iova).input.cnt = _cnt + +#define sf_iova_destroy(iova) \ + if ((iova).iov != (iova).input.iov && \ + (iova).ptr != (iova).holder) \ + free((iova).ptr) + +#ifdef __cplusplus +extern "C" { +#endif + +static inline int sf_iova_check_alloc(SFDynamicIOVArray *iova) +{ + if (iova->iov == iova->input.iov) { + if (iova->input.cnt <= SF_IOV_FIXED_SIZE) { + iova->ptr = iova->holder; + } else { + iova->ptr = fc_malloc(iova->input.cnt * + sizeof(struct iovec)); + if (iova->ptr == NULL) { + return ENOMEM; + } + } + + memcpy(iova->ptr, iova->input.iov, iova->input.cnt * + sizeof(struct iovec)); + iova->iov = iova->ptr; + } + + return 0; +} + +int sf_iova_consume(SFDynamicIOVArray *iova, const int consume_len); + +int sf_iova_first_slice(SFDynamicIOVArray *iova, const int slice_len); + +int sf_iova_next_slice(SFDynamicIOVArray *iova, + const int consume_len, const int slice_len); + +#ifdef __cplusplus +} +#endif + +#endif