summaryrefslogtreecommitdiff
path: root/src/stream_base.cc
diff options
context:
space:
mode:
authorBrian White <mscdex@mscdex.net>2017-05-23 23:42:41 -0400
committerBrian White <mscdex@mscdex.net>2017-05-26 04:29:07 -0400
commit01a1022857ac29d2dae3eba288fb14ff4815f4d8 (patch)
treea5e7d957fcb3a1471ed20697135f5ccf4b9a42a8 /src/stream_base.cc
parent112ef23bba80c947799f3cc85c407543acb6c703 (diff)
downloadandroid-node-v8-01a1022857ac29d2dae3eba288fb14ff4815f4d8.tar.gz
android-node-v8-01a1022857ac29d2dae3eba288fb14ff4815f4d8.tar.bz2
android-node-v8-01a1022857ac29d2dae3eba288fb14ff4815f4d8.zip
lib,src: improve writev() performance for Buffers
PR-URL: https://github.com/nodejs/node/pull/13187 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'src/stream_base.cc')
-rw-r--r--src/stream_base.cc150
1 files changed, 87 insertions, 63 deletions
diff --git a/src/stream_base.cc b/src/stream_base.cc
index c4b59ee5ca..51bad94a4f 100644
--- a/src/stream_base.cc
+++ b/src/stream_base.cc
@@ -100,92 +100,116 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
Local<Object> req_wrap_obj = args[0].As<Object>();
Local<Array> chunks = args[1].As<Array>();
+ bool all_buffers = args[2]->IsTrue();
- size_t count = chunks->Length() >> 1;
+ size_t count;
+ if (all_buffers)
+ count = chunks->Length();
+ else
+ count = chunks->Length() >> 1;
MaybeStackBuffer<uv_buf_t, 16> bufs(count);
+ uv_buf_t* buf_list = *bufs;
- // Determine storage size first
size_t storage_size = 0;
- for (size_t i = 0; i < count; i++) {
- storage_size = ROUND_UP(storage_size, WriteWrap::kAlignSize);
-
- Local<Value> chunk = chunks->Get(i * 2);
-
- if (Buffer::HasInstance(chunk))
- continue;
- // Buffer chunk, no additional storage required
-
- // String chunk
- Local<String> string = chunk->ToString(env->isolate());
- enum encoding encoding = ParseEncoding(env->isolate(),
- chunks->Get(i * 2 + 1));
- size_t chunk_size;
- if (encoding == UTF8 && string->Length() > 65535)
- chunk_size = StringBytes::Size(env->isolate(), string, encoding);
- else
- chunk_size = StringBytes::StorageSize(env->isolate(), string, encoding);
-
- storage_size += chunk_size;
- }
+ uint32_t bytes = 0;
+ size_t offset;
+ AsyncWrap* wrap;
+ WriteWrap* req_wrap;
+ int err;
- if (storage_size > INT_MAX)
- return UV_ENOBUFS;
+ if (!all_buffers) {
+ // Determine storage size first
+ for (size_t i = 0; i < count; i++) {
+ storage_size = ROUND_UP(storage_size, WriteWrap::kAlignSize);
- AsyncWrap* wrap = GetAsyncWrap();
- CHECK_NE(wrap, nullptr);
- env->set_init_trigger_id(wrap->get_id());
- WriteWrap* req_wrap = WriteWrap::New(env,
- req_wrap_obj,
- this,
- AfterWrite,
- storage_size);
+ Local<Value> chunk = chunks->Get(i * 2);
- uint32_t bytes = 0;
- size_t offset = 0;
- for (size_t i = 0; i < count; i++) {
- Local<Value> chunk = chunks->Get(i * 2);
+ if (Buffer::HasInstance(chunk))
+ continue;
+ // Buffer chunk, no additional storage required
+
+ // String chunk
+ Local<String> string = chunk->ToString(env->isolate());
+ enum encoding encoding = ParseEncoding(env->isolate(),
+ chunks->Get(i * 2 + 1));
+ size_t chunk_size;
+ if (encoding == UTF8 && string->Length() > 65535)
+ chunk_size = StringBytes::Size(env->isolate(), string, encoding);
+ else
+ chunk_size = StringBytes::StorageSize(env->isolate(), string, encoding);
- // Write buffer
- if (Buffer::HasInstance(chunk)) {
+ storage_size += chunk_size;
+ }
+
+ if (storage_size > INT_MAX)
+ return UV_ENOBUFS;
+ } else {
+ for (size_t i = 0; i < count; i++) {
+ Local<Value> chunk = chunks->Get(i);
bufs[i].base = Buffer::Data(chunk);
bufs[i].len = Buffer::Length(chunk);
bytes += bufs[i].len;
- continue;
}
- // Write string
- offset = ROUND_UP(offset, WriteWrap::kAlignSize);
- CHECK_LE(offset, storage_size);
- char* str_storage = req_wrap->Extra(offset);
- size_t str_size = storage_size - offset;
-
- Local<String> string = chunk->ToString(env->isolate());
- enum encoding encoding = ParseEncoding(env->isolate(),
- chunks->Get(i * 2 + 1));
- str_size = StringBytes::Write(env->isolate(),
- str_storage,
- str_size,
- string,
- encoding);
- bufs[i].base = str_storage;
- bufs[i].len = str_size;
- offset += str_size;
- bytes += str_size;
+ // Try writing immediately without allocation
+ err = DoTryWrite(&buf_list, &count);
+ if (err != 0 || count == 0)
+ goto done;
}
- int err = DoWrite(req_wrap, *bufs, count, nullptr);
+ wrap = GetAsyncWrap();
+ CHECK_NE(wrap, nullptr);
+ env->set_init_trigger_id(wrap->get_id());
+ req_wrap = WriteWrap::New(env, req_wrap_obj, this, AfterWrite, storage_size);
+ offset = 0;
+ if (!all_buffers) {
+ for (size_t i = 0; i < count; i++) {
+ Local<Value> chunk = chunks->Get(i * 2);
+
+ // Write buffer
+ if (Buffer::HasInstance(chunk)) {
+ bufs[i].base = Buffer::Data(chunk);
+ bufs[i].len = Buffer::Length(chunk);
+ bytes += bufs[i].len;
+ continue;
+ }
+
+ // Write string
+ offset = ROUND_UP(offset, WriteWrap::kAlignSize);
+ CHECK_LE(offset, storage_size);
+ char* str_storage = req_wrap->Extra(offset);
+ size_t str_size = storage_size - offset;
+
+ Local<String> string = chunk->ToString(env->isolate());
+ enum encoding encoding = ParseEncoding(env->isolate(),
+ chunks->Get(i * 2 + 1));
+ str_size = StringBytes::Write(env->isolate(),
+ str_storage,
+ str_size,
+ string,
+ encoding);
+ bufs[i].base = str_storage;
+ bufs[i].len = str_size;
+ offset += str_size;
+ bytes += str_size;
+ }
+ }
+
+ err = DoWrite(req_wrap, buf_list, count, nullptr);
req_wrap_obj->Set(env->async(), True(env->isolate()));
- req_wrap_obj->Set(env->bytes_string(), Number::New(env->isolate(), bytes));
+
+ if (err)
+ req_wrap->Dispose();
+
+ done:
const char* msg = Error();
if (msg != nullptr) {
req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg));
ClearError();
}
-
- if (err)
- req_wrap->Dispose();
+ req_wrap_obj->Set(env->bytes_string(), Number::New(env->isolate(), bytes));
return err;
}