|
12 | 12 | import org.apache.lucene.store.AlreadyClosedException; |
13 | 13 | import org.elasticsearch.Assertions; |
14 | 14 | import org.elasticsearch.action.ActionListener; |
15 | | -import org.elasticsearch.action.StepListener; |
| 15 | +import org.elasticsearch.action.support.PlainActionFuture; |
| 16 | +import org.elasticsearch.action.support.RefCountingListener; |
16 | 17 | import org.elasticsearch.blobcache.BlobCacheUtils; |
17 | 18 | import org.elasticsearch.blobcache.common.ByteRange; |
18 | 19 | import org.elasticsearch.blobcache.common.SparseFileTracker; |
|
50 | 51 | import java.util.concurrent.ConcurrentLinkedQueue; |
51 | 52 | import java.util.concurrent.Executor; |
52 | 53 | import java.util.concurrent.atomic.AtomicBoolean; |
| 54 | +import java.util.concurrent.atomic.AtomicInteger; |
53 | 55 | import java.util.concurrent.atomic.AtomicReference; |
54 | 56 | import java.util.concurrent.atomic.LongAdder; |
55 | 57 | import java.util.function.LongConsumer; |
@@ -703,26 +705,31 @@ private static void throwAlreadyEvicted() { |
703 | 705 | throw new AlreadyClosedException("File chunk is evicted"); |
704 | 706 | } |
705 | 707 |
|
706 | | - StepListener<Integer> populateAndRead( |
| 708 | + void populateAndRead( |
707 | 709 | final ByteRange rangeToWrite, |
708 | 710 | final ByteRange rangeToRead, |
709 | 711 | final RangeAvailableHandler reader, |
710 | 712 | final RangeMissingHandler writer, |
711 | | - final Executor executor |
| 713 | + final Executor executor, |
| 714 | + final ActionListener<Integer> listener |
712 | 715 | ) { |
713 | 716 | assert rangeToRead.length() > 0; |
714 | | - final StepListener<Integer> listener = new StepListener<>(); |
715 | | - Releasable decrementRef = null; |
| 717 | + final Releasable[] resources = new Releasable[2]; |
716 | 718 | try { |
717 | 719 | ensureOpen(); |
718 | 720 | incRef(); |
719 | | - decrementRef = Releasables.releaseOnce(this::decRef); |
| 721 | + resources[1] = Releasables.releaseOnce(this::decRef); |
| 722 | + |
720 | 723 | ensureOpen(); |
721 | | - Releasable finalDecrementRef = decrementRef; |
722 | | - listener.whenComplete(integer -> finalDecrementRef.close(), throwable -> finalDecrementRef.close()); |
723 | 724 | final SharedBytes.IO fileChannel = sharedBytes.getFileChannel(sharedBytesPos); |
724 | | - listener.whenComplete(integer -> fileChannel.decRef(), e -> fileChannel.decRef()); |
725 | | - final ActionListener<Void> rangeListener = rangeListener(rangeToRead, reader, listener, fileChannel); |
| 725 | + resources[0] = Releasables.releaseOnce(fileChannel::decRef); |
| 726 | + |
| 727 | + final ActionListener<Void> rangeListener = rangeListener( |
| 728 | + rangeToRead, |
| 729 | + reader, |
| 730 | + ActionListener.runBefore(listener, () -> Releasables.close(resources)), |
| 731 | + fileChannel |
| 732 | + ); |
726 | 733 | final List<SparseFileTracker.Gap> gaps = tracker.waitForRange(rangeToWrite, rangeToRead, rangeListener); |
727 | 734 |
|
728 | 735 | for (SparseFileTracker.Gap gap : gaps) { |
@@ -758,9 +765,8 @@ public void onFailure(Exception e) { |
758 | 765 | }); |
759 | 766 | } |
760 | 767 | } catch (Exception e) { |
761 | | - releaseAndFail(listener, decrementRef, e); |
| 768 | + releaseAndFail(listener, Releasables.wrap(resources), e); |
762 | 769 | } |
763 | | - return listener; |
764 | 770 | } |
765 | 771 |
|
766 | 772 | private ActionListener<Void> rangeListener( |
@@ -831,48 +837,35 @@ public int populateAndRead( |
831 | 837 | final RangeMissingHandler writer, |
832 | 838 | final String executor |
833 | 839 | ) throws Exception { |
834 | | - StepListener<Integer> stepListener = null; |
835 | | - final long writeStart = rangeToWrite.start(); |
836 | | - final long readStart = rangeToRead.start(); |
837 | | - for (int region = getRegion(rangeToWrite.start()); region <= getEndingRegion(rangeToWrite.end()); region++) { |
838 | | - final ByteRange subRangeToWrite = mapSubRangeToRegion(rangeToWrite, region); |
839 | | - final ByteRange subRangeToRead = mapSubRangeToRegion(rangeToRead, region); |
840 | | - if (subRangeToRead.length() == 0L) { |
841 | | - // nothing to read, skip |
842 | | - if (stepListener == null) { |
843 | | - stepListener = new StepListener<>(); |
844 | | - stepListener.onResponse(0); |
| 840 | + final PlainActionFuture<Void> readsComplete = new PlainActionFuture<>(); |
| 841 | + final AtomicInteger bytesRead = new AtomicInteger(); |
| 842 | + try (var listeners = new RefCountingListener(1, readsComplete)) { |
| 843 | + final long writeStart = rangeToWrite.start(); |
| 844 | + final long readStart = rangeToRead.start(); |
| 845 | + for (int region = getRegion(rangeToWrite.start()); region <= getEndingRegion(rangeToWrite.end()); region++) { |
| 846 | + final ByteRange subRangeToWrite = mapSubRangeToRegion(rangeToWrite, region); |
| 847 | + final ByteRange subRangeToRead = mapSubRangeToRegion(rangeToRead, region); |
| 848 | + if (subRangeToRead.length() == 0L) { |
| 849 | + // nothing to read, skip |
| 850 | + continue; |
845 | 851 | } |
846 | | - continue; |
847 | | - } |
848 | | - final CacheFileRegion fileRegion = get(cacheKey, length, region); |
849 | | - final long regionStart = getRegionStart(region); |
850 | | - final long writeOffset = writeStart - regionStart; |
851 | | - final long readOffset = readStart - regionStart; |
852 | | - final StepListener<Integer> lis = fileRegion.populateAndRead( |
853 | | - subRangeToWrite, |
854 | | - subRangeToRead, |
855 | | - (channel, channelPos, relativePos, len) -> { |
| 852 | + final CacheFileRegion fileRegion = get(cacheKey, length, region); |
| 853 | + final long regionStart = getRegionStart(region); |
| 854 | + final long writeOffset = writeStart - regionStart; |
| 855 | + final long readOffset = readStart - regionStart; |
| 856 | + fileRegion.populateAndRead(subRangeToWrite, subRangeToRead, (channel, channelPos, relativePos, len) -> { |
856 | 857 | assert regionOwners[fileRegion.sharedBytesPos].get() == fileRegion; |
857 | 858 | assert channelPos >= fileRegion.physicalStartOffset() && channelPos + len <= fileRegion.physicalEndOffset(); |
858 | 859 | return reader.onRangeAvailable(channel, channelPos, relativePos - readOffset, len); |
859 | | - }, |
860 | | - (channel, channelPos, relativePos, len, progressUpdater) -> { |
| 860 | + }, (channel, channelPos, relativePos, len, progressUpdater) -> { |
861 | 861 | assert regionOwners[fileRegion.sharedBytesPos].get() == fileRegion; |
862 | 862 | assert channelPos >= fileRegion.physicalStartOffset() && channelPos + len <= fileRegion.physicalEndOffset(); |
863 | 863 | writer.fillCacheRange(channel, channelPos, relativePos - writeOffset, len, progressUpdater); |
864 | | - }, |
865 | | - threadPool.executor(executor) |
866 | | - ); |
867 | | - assert lis != null; |
868 | | - if (stepListener == null) { |
869 | | - stepListener = lis; |
870 | | - } else { |
871 | | - stepListener = stepListener.thenCombine(lis, Math::addExact); |
| 864 | + }, threadPool.executor(executor), listeners.acquire(i -> bytesRead.updateAndGet(j -> Math.addExact(i, j)))); |
872 | 865 | } |
873 | | - |
874 | 866 | } |
875 | | - return stepListener.asFuture().get(); |
| 867 | + readsComplete.get(); |
| 868 | + return bytesRead.get(); |
876 | 869 | } |
877 | 870 |
|
878 | 871 | @Override |
|
0 commit comments