Skip to content

napi_create_external_buffer is super slow #53804

Closed
@ronag

Description

@ronag

Given the following example:

NAPI_METHOD(db_get_many) {
  NAPI_ARGV(2);

  Database* database;
  NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], reinterpret_cast<void**>(&database)));

  // TODO (fix): Ensure lifetime of buffer?
  std::vector<rocksdb::Slice> keys;
  {
    uint32_t length;
    NAPI_STATUS_THROWS(napi_get_array_length(env, argv[1], &length));

    keys.reserve(length);
    for (uint32_t n = 0; n < length; n++) {
      napi_value element;
      char* buf;
      size_t length;
      NAPI_STATUS_THROWS(napi_get_element(env, argv[1], n, &element));
      NAPI_STATUS_THROWS(napi_get_buffer_info(env, element, reinterpret_cast<void**>(&buf), &length));
      keys.emplace_back(rocksdb::Slice{buf, length});
    }
  }

  rocksdb::ColumnFamilyHandle* column = database->db->DefaultColumnFamily();
  rocksdb::ReadOptions readOptions;;

  const auto size = keys.size();

  std::vector<rocksdb::Status> statuses;
  std::vector<rocksdb::PinnableSlice> values;

  statuses.resize(size);
  values.resize(size);

  database->db->MultiGet(readOptions, column, size, keys.data(), values.data(), statuses.data());

  for (size_t idx = 0; idx < size; idx++) {
    if (statuses[idx].IsNotFound()) {
      values[idx] = rocksdb::PinnableSlice(nullptr);
    } else {
      ROCKS_STATUS_THROWS_NAPI(statuses[idx]);
    }
  }

  napi_value ret;
  NAPI_STATUS_THROWS(napi_create_array_with_length(env, values.size(), &ret));

  for (size_t idx = 0; idx < values.size(); idx++) {
    napi_value element;
    if (values[idx].GetSelf()) {
      auto ptr = new rocksdb::PinnableSlice(std::move(values[idx]));
      NAPI_STATUS_THROWS(napi_create_external_buffer(env, ptr->size(), const_cast<char*>(ptr->data()), Finalize<rocksdb::PinnableSlice>, ptr, &element));
    } else {
      NAPI_STATUS_THROWS(napi_get_undefined(env, &element));
    }
    NAPI_STATUS_THROWS(napi_set_element(env, ret, static_cast<uint32_t>(idx), element));
  }

  return ret;
}

more than 50% of the time is spent with napi_create_external_buffer which I would assume should be a rather fast operation...

Metadata

Metadata

Assignees

No one assigned

    Labels

    node-apiIssues and PRs related to the Node-API.

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions