Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rocksdbjni: Transaction#multiGetForUpdate returns null for large key counts #9006

Open
DaMatrix opened this issue Oct 9, 2021 · 1 comment
Labels
bug Confirmed RocksDB bugs java-api up-for-grabs Up for grabs

Comments

@DaMatrix
Copy link
Contributor

DaMatrix commented Oct 9, 2021

Note: Please use Issues only for bug reports. For questions, discussions, feature requests, etc. post to dev group: https://groups.google.com/forum/#!forum/rocksdb or https://www.facebook.com/groups/rocksdb.dev

Expected behavior

Transaction#multiGetForUpdate should never return null.

Actual behavior

Transaction#multiGetForUpdate (the version which accepts a List<ColumnFamilyHandle>) returns null when called with a large number of keys (>= 65537 keys, according to my test code).

Upon further investigation, this seems to affect other methods as well: the standard RocksDB#multiGetAsList(List<byte[]>) throws a NullPointerException when called with >= 65537 keys.

Steps to reproduce the behavior

Here's a minimum reproducible example

If I'm not mistaken, the root cause is in from the following code:

if (env->EnsureLocalCapacity(len_cols) != 0) {
// out of memory
*has_exception = JNI_TRUE;
return std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*>();
}

To the best of my knowledge, EnsureLocalCapacity is for ensuring that the requested number of local object references can be held by the current stack frame. It therefore makes very little sense to check it with the length of a primitive array (long[] in this case).

Here are all the instances I could find of EnsureLocalCapacity being used with the length of a primitive array:

if (env->EnsureLocalCapacity(jcf_name_len) != 0) {

if (env->EnsureLocalCapacity(jcf_name_len) != 0) {

if (env->EnsureLocalCapacity(len_cols) != 0) {

if (env->EnsureLocalCapacity(len_key) != 0) {

if (env->EnsureLocalCapacity(jkey_part_len) != 0) {

if (env->EnsureLocalCapacity(jvalue_part_len) != 0) {

if (env->EnsureLocalCapacity(jkey_part_len) != 0) {

I'm pretty sure these are also wrong (they're not referencing primitive arrays, but object arrays whose references seem to be safely cleaned up - one of them is even commented regarding the same issue!):

if (env->EnsureLocalCapacity(len_cols) != 0) {

if (env->EnsureLocalCapacity(len_cols) != 0) {

if (env->EnsureLocalCapacity(len_key_parts) != 0) {

if (env->EnsureLocalCapacity(len_keys) != 0) {

// TODO(AR) it is not clear to me why EnsureLocalCapacity is needed for the
// loop as we cleanup references with env->DeleteLocalRef(jentry_value);
if (env->EnsureLocalCapacity(static_cast<jint>(s.size())) != 0) {

@ajkr ajkr added java-api bug Confirmed RocksDB bugs up-for-grabs Up for grabs labels Oct 11, 2021
DaMatrix added a commit to PorkStudios/FarPlaneTwo that referenced this issue Oct 27, 2021
alanpaxton added a commit to alanpaxton/rocksdb that referenced this issue Oct 17, 2022
@see facebook#9006

Instances of RocksJava API JNI code appear to have misunderstood the reason for JNIEnv->EnsureLocalCapacity() and are carrying out bogus checks which happen to fail with some larger parameter values (many column familes in a single call, very long key names or values). Remove these checks and add some regression tests for the previous failures.

Add/update tests to ensure that methods with EnsureLocalCapacity() removed still work; testing was perhaps a bit thin in places.
facebook-github-bot pushed a commit that referenced this issue Oct 27, 2022
…nsureLocalCapacity() calls (#10674)

Summary:
Resolves see #9006

Fixes 2 related issues with JNI local references in the RocksJava API.

1. Some instances of RocksJava API JNI code appear to have misunderstood the reason for `JNIEnv->EnsureLocalCapacity()` and are carrying out bogus checks which happen to fail with some larger parameter values (many column families in a single call, very long key names or values). Remove these checks and add some regression tests for the previous failures.

2. The helper for Transaction multiGet operations (`multiGet()`, `multiGetForUpdate()`,...) is limited in the number of keys it can `get()` for because it requires a corresponding number of live local references. Refactor the helper slightly, copying out the key contents within a loop so that the references don't have to exist at the same time.

Pull Request resolved: #10674

Reviewed By: ajkr

Differential Revision: D40515361

Pulled By: jay-zhuang

fbshipit-source-id: f1be0126181a698b3ad27c0945a39c54d950aa25
@alanpaxton
Copy link
Contributor

Hi @DaMatrix just reviewing PRs/issues, this should all be resolved, working and regression tested. Could you close ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Confirmed RocksDB bugs java-api up-for-grabs Up for grabs
Projects
None yet
Development

No branches or pull requests

3 participants