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

Aggregate files from the same segment into a single Arena #13570

Merged
merged 32 commits into from
Jul 25, 2024

Conversation

ChrisHegarty
Copy link
Contributor

@ChrisHegarty ChrisHegarty commented Jul 14, 2024

This commit adds a ref counted shared arena to support aggregating segment files into a single Arena.

@ChrisHegarty ChrisHegarty changed the title Add RefCountedSharedArena Aggregate files from the same segment into a single Arena Jul 14, 2024
Copy link
Contributor

@uschindler uschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the code much more:

  • the attachment is a good idea for the meantime to clearly separate compilation units
  • the refocunting looks much better here - thanks. That was my main problem with the previous approach by @magibney

Copy link
Contributor

@magibney magibney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good (sorry about the lack of write access to the original PR -- institutional repo, not an option).

attachment() is quite nice.

Unless I'm mistaken, this PR has ended up with refcounting that's nearly identical to the current state of #13555 (though it fixes a bug in the other PR's acquire, where CAS must be used in place of getAndIncrement())? It's a small point, but I think CAS is not necessary for release() here.

My only other concern applies here equally as to my earlier PR:

      // TODO: what if the associated Directory is used for some purpose other than Lucene
      //  index files, and some of the filenames happen to be patterned so that a "segment"
      //  can be parsed from them? That could result in files being spuriously grouped
      //  together in the same arena. This would only practically be a problem if such a
      //  "segment" was never closed (refCt never 0), _and_ enough files associated with that
      //  "segment" were opened and closed (without ever closing the associated Arena)
      //  to exhaust virtual memory space.

Copy link
Contributor

@uschindler uschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK from my side, only the missing final (maybe it should be private, too) should be fixed.

The Generics are in fact a bit strange, but due to the MethodHandle and casting after ctor it works woth Object as type. I would have wished to get rid of the generic type. Maybe the field in MMapDirectory should use "?" as type, not "Object"? Just an idea.

Let me think ab bit about it, but it is a workaround for something that could be fixed later when the whole provider gets obsolete (Java 24 or 25 LTS).

@uschindler
Copy link
Contributor

uschindler commented Jul 15, 2024

Hi,
we also get Updates on the JDK fixes: openjdk/jdk#20158 (see issue about more details and some improvements Solr and/or Elasticsearch/Opensearch should do).

@magibney
Copy link
Contributor

To expand a bit on the concern I raised above:

IIUC, in order for this to work properly (guaranteed to not potentially leak virtual memory address space) it depends on segment filename usage patterns and segment lifecycle. I think we may either need to:

  1. provide a way to configure specific MMapDirectory instances to bypass this Arena pooling, or
  2. disallow use of MMapDirectory for anything other than Lucene index files (because of the potential for collision of filename patterns that could be parsed as "segments", potentially allowing an Arena to live forever, accumulating an unlimited number of associated files.

Am I missing something -- is this not a concern?

@uschindler
Copy link
Contributor

To expand a bit on the concern I raised above:

IIUC, in order for this to work properly (guaranteed to not potentially leak virtual memory address space) it depends on segment filename usage patterns and segment lifecycle. I think we may either need to:

  1. provide a way to configure specific MMapDirectory instances to bypass this Arena pooling, or
  2. disallow use of MMapDirectory for anything other than Lucene index files (because of the potential for collision of filename patterns that could be parsed as "segments", potentially allowing an Arena to live forever, accumulating an unlimited number of associated files.

Am I missing something -- is this not a concern?

In addition we could add a separate ctor option to disable grouping.

In addition I would go for option #2: Like for the segment main file it should also not use grouped segments for any other file that is not a correct segment number (it could validate the filename using the base32 hash starting with "_" or whatever this is).

Maybe add a protected method to MMapDirectory that checks if a filename is a segement file) and pass this one as Predicate<String> to the provider interface.

@uschindler
Copy link
Contributor

uschindler commented Jul 15, 2024

We may need some other logic: We have some files that can change without the segment name changing? How do we handle *.del, softdelete or docValues in-place update files? If they correspond to the same segment, they would only be closed when actually the whole segment is closed after full refresh.

This should be easily testable on windows: Files that have mmapped areas can't be deleted, so we may cause issues when closing deletion files.

But on the other hand: Aren't ".del" files not READONCE!?

Copy link
Contributor

@uschindler uschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed to request changes, because we should confirm the deletion/softdeletes and docvalues updates.

Maybe the file pattern should really be a Predicate to separate the implementation. Maybe add a method to return protected Optional<String> getArenaGroupingKey(String filename) (or as Function<String,Optional<String>>), which returns empty optional if no grouping allowed or the segment number otherwise as key.

@uschindler
Copy link
Contributor

I changed to request changes, because we should confirm the deletion/softdeletes and docvalues updates.

Maybe the file pattern should really be a Predicate to separate the implementation. Maybe add a method to return protected Optional<String> getArenaGroupingKey(String filename) (or as Function<String,Optional<String>>), which returns empty optional if no grouping allowed or the segment number otherwise as key.

This could be similarily implemented like the setPreload(BiPredicate<String,IOContext>) method.

@magibney
Copy link
Contributor

heh, was just writing to suggest something similar (Function<String,Optional<String>>). SGTM.

@uschindler
Copy link
Contributor

uschindler commented Jul 15, 2024

It could even be simpler by passing the grouping key to the provider method directly in addition to filename. Then the code that figures out which group is used can reside in MMapDirectory only.

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coincidentally I'm working on a similar ref-counting in a ConcurrentHashMap thing in Solr for something else (not for Arena) so it's nice to review this; bit of deja-vu.

Copy link
Contributor

@dsmiley dsmiley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can someone take a stab at summarizing this for CHANGES.txt, thus avoiding details a reader is unlikely to know about? Like me :-). How will a user of Lucene benefit?

Copy link
Contributor

@magibney magibney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good; I left a few comments, but the only one that really has to happen I think is the removal of the ISE in acquire().

Copy link
Contributor

@uschindler uschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine, some suggestions.

To make the javadocs visible the static sysprop name constant should be public.

Copy link
Contributor

@uschindler uschindler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine now.

@ChrisHegarty
Copy link
Contributor Author

ChrisHegarty commented Jul 24, 2024

This looks like it's in good shape now. @magibney Any final comments? Otherwise, I plan to merge tomorrow. And then figure out how to backport!

Copy link
Contributor

@magibney magibney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks! (aside from a javadoc typo that I happened to notice)

@uschindler
Copy link
Contributor

uschindler commented Jul 24, 2024

Otherwise, I plan to merge tomorrow. And then figure out how to backport!

Code duplication with Arena vs. MemorySession hell!

@ChrisHegarty ChrisHegarty merged commit b4fb425 into apache:main Jul 25, 2024
3 checks passed
@ChrisHegarty ChrisHegarty deleted the refCntArena branch July 25, 2024 09:12
@uschindler
Copy link
Contributor

It's finally done. Thanks to all and help while implementing my idea!

@uschindler
Copy link
Contributor

Do we have a backport PR? Should I work on it?

@uschindler
Copy link
Contributor

@ChrisHegarty the PR ist listed in the 9.x section of changes. I could work on a backport (possibly tomorrow). I just want to make sure you haven't started.

I am not yet sure how to handle java 20 and java 19. I may possibly leave those as they are.

@uschindler uschindler added this to the 9.12.0 milestone Aug 22, 2024
@ChrisHegarty
Copy link
Contributor Author

@ChrisHegarty the PR ist listed in the 9.x section of changes. I could work on a backport (possibly tomorrow). I just want to make sure you haven't started.

I am not yet sure how to handle java 20 and java 19. I may possibly leave those as they are.

Yeah, I had the same thought too - to just do this for JDK 21+.

I’ve not started, but it is on my todo list. I’ll raise a PR for it tomorrow, and if you have time maybe you could help review.

@uschindler
Copy link
Contributor

We may need to change the changes entry to tell that to enduser.

ChrisHegarty added a commit that referenced this pull request Aug 23, 2024
Backport of #13570

This commit adds a ref counted shared arena to support aggregating segment files into a single Arena.

The backport only supports the JDK 21 version of the code - JDK 19 and 20 specific versions do not aggregate files so therefore remain the same. The MemorySession/SegmentScope/Arena APIs are different in 19 and 20.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants