nghttpx: Allow units (k, m, and g) in --{read,write}-{rate,burst}

So that you can specify --read-rate=1M --read-burst=4M
This commit is contained in:
Tatsuhiro Tsujikawa 2015-01-13 21:54:53 +09:00
parent 5e8eb926f2
commit 956c11388c
7 changed files with 142 additions and 26 deletions

View File

@ -129,6 +129,10 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_select_h2", shrpx::test_util_select_h2) || !CU_add_test(pSuite, "util_select_h2", shrpx::test_util_select_h2) ||
!CU_add_test(pSuite, "util_ipv6_numeric_addr", !CU_add_test(pSuite, "util_ipv6_numeric_addr",
shrpx::test_util_ipv6_numeric_addr) || shrpx::test_util_ipv6_numeric_addr) ||
!CU_add_test(pSuite, "util_utos_with_unit",
shrpx::test_util_utos_with_unit) ||
!CU_add_test(pSuite, "util_parse_uint_with_unit",
shrpx::test_util_parse_uint_with_unit) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) || !CU_add_test(pSuite, "ringbuf_write", nghttp2::test_ringbuf_write) ||
!CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) || !CU_add_test(pSuite, "ringbuf_iovec", nghttp2::test_ringbuf_iovec) ||

View File

@ -816,7 +816,7 @@ Performance:
-n, --workers=<CORES> -n, --workers=<CORES>
Set the number of worker threads. Set the number of worker threads.
Default: )" << get_config()->num_worker << R"( Default: )" << get_config()->num_worker << R"(
--read-rate=<RATE> --read-rate=<SIZE>
Set maximum average read rate on frontend Set maximum average read rate on frontend
connection. Setting 0 to this option means read connection. Setting 0 to this option means read
rate is unlimited. rate is unlimited.
@ -826,7 +826,7 @@ Performance:
connection. Setting 0 to this option means read connection. Setting 0 to this option means read
burst size is unlimited. burst size is unlimited.
Default: )" << get_config()->read_burst << R"( Default: )" << get_config()->read_burst << R"(
--write-rate=<RATE> --write-rate=<SIZE>
Set maximum average write rate on frontend Set maximum average write rate on frontend
connection. Setting 0 to this option means write connection. Setting 0 to this option means write
rate is unlimited. rate is unlimited.
@ -836,7 +836,7 @@ Performance:
connection. Setting 0 to this option means write connection. Setting 0 to this option means write
burst size is unlimited. burst size is unlimited.
Default: )" << get_config()->write_burst << R"( Default: )" << get_config()->write_burst << R"(
--worker-read-rate=<RATE> --worker-read-rate=<SIZE>
Set maximum average read rate on frontend Set maximum average read rate on frontend
connection per worker. Setting 0 to this option connection per worker. Setting 0 to this option
means read rate is unlimited. Not implemented means read rate is unlimited. Not implemented
@ -848,7 +848,7 @@ Performance:
means read burst size is unlimited. Not means read burst size is unlimited. Not
implemented yet. implemented yet.
Default: )" << get_config()->worker_read_burst << R"( Default: )" << get_config()->worker_read_burst << R"(
--worker-write-rate=<RATE> --worker-write-rate=<SIZE>
Set maximum average write rate on frontend Set maximum average write rate on frontend
connection per worker. Setting 0 to this option connection per worker. Setting 0 to this option
means write rate is unlimited. Not implemented means write rate is unlimited. Not implemented

View File

@ -356,6 +356,21 @@ int parse_uint(T *dest, const char *opt, const char *optarg) {
return 0; return 0;
} }
namespace {
template <typename T>
int parse_uint_with_unit(T *dest, const char *opt, const char *optarg) {
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
return -1;
}
*dest = n;
return 0;
}
} // namespace
template <typename T> template <typename T>
int parse_int(T *dest, const char *opt, const char *optarg) { int parse_int(T *dest, const char *opt, const char *optarg) {
char *end = nullptr; char *end = nullptr;
@ -879,53 +894,39 @@ int parse_config(const char *opt, const char *optarg) {
} }
if (util::strieq(opt, SHRPX_OPT_READ_RATE)) { if (util::strieq(opt, SHRPX_OPT_READ_RATE)) {
return parse_uint(&mod_config()->read_rate, opt, optarg); return parse_uint_with_unit(&mod_config()->read_rate, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_READ_BURST)) { if (util::strieq(opt, SHRPX_OPT_READ_BURST)) {
int n; return parse_uint_with_unit(&mod_config()->read_burst, opt, optarg);
if (parse_uint(&n, opt, optarg) != 0) {
return -1;
}
if (n == 0) {
LOG(ERROR) << opt << ": specify integer strictly larger than 0";
return -1;
}
mod_config()->read_burst = n;
return 0;
} }
if (util::strieq(opt, SHRPX_OPT_WRITE_RATE)) { if (util::strieq(opt, SHRPX_OPT_WRITE_RATE)) {
return parse_uint(&mod_config()->write_rate, opt, optarg); return parse_uint_with_unit(&mod_config()->write_rate, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_WRITE_BURST)) { if (util::strieq(opt, SHRPX_OPT_WRITE_BURST)) {
return parse_uint(&mod_config()->write_burst, opt, optarg); return parse_uint_with_unit(&mod_config()->write_burst, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_WORKER_READ_RATE)) { if (util::strieq(opt, SHRPX_OPT_WORKER_READ_RATE)) {
LOG(WARN) << opt << ": not implemented yet"; LOG(WARN) << opt << ": not implemented yet";
return parse_uint(&mod_config()->worker_read_rate, opt, optarg); return parse_uint_with_unit(&mod_config()->worker_read_rate, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_WORKER_READ_BURST)) { if (util::strieq(opt, SHRPX_OPT_WORKER_READ_BURST)) {
LOG(WARN) << opt << ": not implemented yet"; LOG(WARN) << opt << ": not implemented yet";
return parse_uint(&mod_config()->worker_read_burst, opt, optarg); return parse_uint_with_unit(&mod_config()->worker_read_burst, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_WORKER_WRITE_RATE)) { if (util::strieq(opt, SHRPX_OPT_WORKER_WRITE_RATE)) {
LOG(WARN) << opt << ": not implemented yet"; LOG(WARN) << opt << ": not implemented yet";
return parse_uint(&mod_config()->worker_write_rate, opt, optarg); return parse_uint_with_unit(&mod_config()->worker_write_rate, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_WORKER_WRITE_BURST)) { if (util::strieq(opt, SHRPX_OPT_WORKER_WRITE_BURST)) {
LOG(WARN) << opt << ": not implemented yet"; LOG(WARN) << opt << ": not implemented yet";
return parse_uint(&mod_config()->worker_write_burst, opt, optarg); return parse_uint_with_unit(&mod_config()->worker_write_burst, opt, optarg);
} }
if (util::strieq(opt, SHRPX_OPT_NPN_LIST)) { if (util::strieq(opt, SHRPX_OPT_NPN_LIST)) {

View File

@ -899,6 +899,57 @@ bool ipv6_numeric_addr(const char *host) {
return inet_pton(AF_INET6, host, dst) == 1; return inet_pton(AF_INET6, host, dst) == 1;
} }
int64_t parse_uint_with_unit(const char *s) {
int64_t n = 0;
size_t i;
auto len = strlen(s);
if (len == 0) {
return -1;
}
constexpr int64_t max = std::numeric_limits<int64_t>::max();
for (i = 0; i < len; ++i) {
if ('0' <= s[i] && s[i] <= '9') {
if (n > max / 10) {
return -1;
}
n *= 10;
if (n > max - (s[i] - '0')) {
return -1;
}
n += s[i] - '0';
continue;
}
break;
}
if (i == len) {
return n;
}
if (i == 0 || i + 1 != len) {
return -1;
}
int mul = 1;
switch (s[i]) {
case 'K':
case 'k':
mul = 1 << 10;
break;
case 'M':
case 'm':
mul = 1 << 20;
break;
case 'G':
case 'g':
mul = 1 << 30;
break;
default:
return -1;
}
if (n > max / mul) {
return -1;
}
return n * mul;
}
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2

View File

@ -341,6 +341,24 @@ template <typename T> std::string utos(T n) {
return res; return res;
} }
template <typename T> std::string utos_with_unit(T n) {
char u = 0;
if (n >= (1 << 30)) {
u = 'G';
n /= (1 << 30);
} else if (n >= (1 << 20)) {
u = 'M';
n /= (1 << 20);
} else if (n >= (1 << 10)) {
u = 'K';
n /= (1 << 10);
}
if (u == 0) {
return utos(n);
}
return utos(n) + u;
}
extern const char UPPER_XDIGITS[]; extern const char UPPER_XDIGITS[];
template <typename T> std::string utox(T n) { template <typename T> std::string utox(T n) {
@ -477,6 +495,13 @@ bool check_socket_connected(int fd);
// Returns true if |host| is IPv6 numeric address (e.g., ::1) // Returns true if |host| is IPv6 numeric address (e.g., ::1)
bool ipv6_numeric_addr(const char *host); bool ipv6_numeric_addr(const char *host);
// Parses NULL terminated string |s| as unsigned integer and returns
// the parsed integer. Additionally, if |s| ends with 'k', 'm', 'g'
// and its upper case characters, multiply the integer by 1024, 1024 *
// 1024 and 1024 * 1024 respectively. If there is an error, returns
// -1.
int64_t parse_uint_with_unit(const char *s);
} // namespace util } // namespace util
} // namespace nghttp2 } // namespace nghttp2

View File

@ -174,4 +174,37 @@ void test_util_ipv6_numeric_addr(void) {
CU_ASSERT(!util::ipv6_numeric_addr("localhost")); CU_ASSERT(!util::ipv6_numeric_addr("localhost"));
} }
void test_util_utos_with_unit(void) {
CU_ASSERT("0" == util::utos_with_unit(0));
CU_ASSERT("1023" == util::utos_with_unit(1023));
CU_ASSERT("1K" == util::utos_with_unit(1024));
CU_ASSERT("1K" == util::utos_with_unit(1025));
CU_ASSERT("1M" == util::utos_with_unit(1 << 20));
CU_ASSERT("1G" == util::utos_with_unit(1 << 30));
CU_ASSERT("1024G" == util::utos_with_unit(1LL << 40));
}
void test_util_parse_uint_with_unit(void) {
CU_ASSERT(0 == util::parse_uint_with_unit("0"));
CU_ASSERT(1023 == util::parse_uint_with_unit("1023"));
CU_ASSERT(1024 == util::parse_uint_with_unit("1k"));
CU_ASSERT(2048 == util::parse_uint_with_unit("2K"));
CU_ASSERT(1 << 20 == util::parse_uint_with_unit("1m"));
CU_ASSERT(1 << 21 == util::parse_uint_with_unit("2M"));
CU_ASSERT(1 << 30 == util::parse_uint_with_unit("1g"));
CU_ASSERT(1LL << 31 == util::parse_uint_with_unit("2G"));
CU_ASSERT(9223372036854775807LL ==
util::parse_uint_with_unit("9223372036854775807"));
// check overflow case
CU_ASSERT(-1 == util::parse_uint_with_unit("9223372036854775808"));
CU_ASSERT(-1 == util::parse_uint_with_unit("10000000000000000000"));
CU_ASSERT(-1 == util::parse_uint_with_unit("9223372036854775807G"));
// bad characters
CU_ASSERT(-1 == util::parse_uint_with_unit("1.1"));
CU_ASSERT(-1 == util::parse_uint_with_unit("1a"));
CU_ASSERT(-1 == util::parse_uint_with_unit("a1"));
CU_ASSERT(-1 == util::parse_uint_with_unit("1T"));
CU_ASSERT(-1 == util::parse_uint_with_unit(""));
}
} // namespace shrpx } // namespace shrpx

View File

@ -37,6 +37,8 @@ void test_util_utox(void);
void test_util_http_date(void); void test_util_http_date(void);
void test_util_select_h2(void); void test_util_select_h2(void);
void test_util_ipv6_numeric_addr(void); void test_util_ipv6_numeric_addr(void);
void test_util_utos_with_unit(void);
void test_util_parse_uint_with_unit(void);
} // namespace shrpx } // namespace shrpx