1414import org .elasticsearch .action .OriginalIndices ;
1515import org .elasticsearch .common .Strings ;
1616import org .elasticsearch .common .bytes .BytesReference ;
17- import org .elasticsearch .common .collect .Iterators ;
1817import org .elasticsearch .common .io .stream .DelayableWriteable ;
1918import org .elasticsearch .common .io .stream .StreamInput ;
2019import org .elasticsearch .common .io .stream .StreamOutput ;
2524import org .elasticsearch .common .xcontent .ChunkedToXContentObject ;
2625import org .elasticsearch .core .Nullable ;
2726import org .elasticsearch .core .RefCounted ;
27+ import org .elasticsearch .core .Releasable ;
28+ import org .elasticsearch .core .Releasables ;
2829import org .elasticsearch .core .SimpleRefCounted ;
2930import org .elasticsearch .core .TimeValue ;
3031import org .elasticsearch .rest .RestStatus ;
4243import org .elasticsearch .xcontent .XContentBuilder ;
4344
4445import java .io .IOException ;
46+ import java .util .ArrayDeque ;
4547import java .util .Base64 ;
4648import java .util .Collections ;
4749import java .util .Iterator ;
@@ -389,7 +391,7 @@ public Clusters getClusters() {
389391 }
390392
391393 @ Override
392- public Iterator <? extends ToXContent > toXContentChunked (ToXContent .Params params ) {
394+ public ReleasableIterator <? extends ToXContent > toXContentChunked (ToXContent .Params params ) {
393395 assert hasReferences ();
394396 return getToXContentIterator (true , params );
395397 }
@@ -398,17 +400,68 @@ public Iterator<? extends ToXContent> innerToXContentChunked(ToXContent.Params p
398400 return getToXContentIterator (false , params );
399401 }
400402
401- private Iterator <ToXContent > getToXContentIterator (boolean wrapInObject , ToXContent .Params params ) {
402- return Iterators .concat (
403- wrapInObject ? ChunkedToXContentHelper .startObject () : Collections .emptyIterator (),
404- ChunkedToXContentHelper .chunk (SearchResponse .this ::headerToXContent ),
405- Iterators .single (clusters ),
406- hits .toXContentChunked (params ),
407- aggregations == null ? Collections .emptyIterator () : ChunkedToXContentHelper .chunk (aggregations ),
408- suggest == null ? Collections .emptyIterator () : ChunkedToXContentHelper .chunk (suggest ),
409- profileResults == null ? Collections .emptyIterator () : ChunkedToXContentHelper .chunk (profileResults ),
410- wrapInObject ? ChunkedToXContentHelper .endObject () : Collections .emptyIterator ()
411- );
403+ private ReleasableIterator <ToXContent > getToXContentIterator (boolean wrapInObject , ToXContent .Params params ) {
404+ final ArrayDeque <Iterator <? extends ToXContent >> iters = new ArrayDeque <>(7 );
405+ if (wrapInObject ) {
406+ iters .addLast (ChunkedToXContentHelper .startObject ());
407+ }
408+ iters .addLast (ChunkedToXContentHelper .chunk (SearchResponse .this ::headerToXContent ));
409+ iters .addLast (ChunkedToXContentHelper .chunk (clusters ));
410+ var hits = this .hits ;
411+ hits .incRef ();
412+ iters .addLast (hits .toXContentChunked (params ));
413+ final Releasable releaseHits = Releasables .releaseOnce (hits ::decRef );
414+ iters .addLast (ChunkedToXContentHelper .chunk ((b , p ) -> {
415+ releaseHits .close ();
416+ return b ;
417+ }));
418+ var aggregations = this .aggregations ;
419+ if (aggregations != null ) {
420+ iters .addLast (ChunkedToXContentHelper .chunk (aggregations ));
421+ }
422+ var suggest = this .suggest ;
423+ if (suggest != null ) {
424+ iters .addLast (ChunkedToXContentHelper .chunk (suggest ));
425+ }
426+ var profileResults = this .profileResults ;
427+ if (profileResults != null ) {
428+ iters .addLast (ChunkedToXContentHelper .chunk (profileResults ));
429+ }
430+ if (wrapInObject ) {
431+ iters .addLast (ChunkedToXContentHelper .endObject ());
432+ }
433+ return new ReleasableIterator <>() {
434+
435+ @ Override
436+ public void close () {
437+ releaseHits .close ();
438+ }
439+
440+ Iterator <? extends ToXContent > current = iters .pollFirst ();
441+
442+ @ Override
443+ public boolean hasNext () {
444+ while (true ) {
445+ if (current .hasNext ()) {
446+ return true ;
447+ }
448+ var c = current = iters .pollFirst ();
449+ if (c == null ) {
450+ current = Collections .emptyIterator ();
451+ return false ;
452+ }
453+ }
454+ }
455+
456+ @ Override
457+ public ToXContent next () {
458+ while (current .hasNext () == false ) {
459+ current = iters .pollFirst ();
460+ }
461+ var res = current .next ();
462+ return res ;
463+ }
464+ };
412465 }
413466
414467 public XContentBuilder headerToXContent (XContentBuilder builder , ToXContent .Params params ) throws IOException {
0 commit comments