@@ -651,6 +651,9 @@ private void storeSelectedIndexField(IndexLabel indexLabel,
651651
652652 @ Watched (prefix = "index" )
653653 private IdHolder doIndexQuery (IndexLabel indexLabel , ConditionQuery query ) {
654+ if (this .needHstoreRangeIndexOrder (indexLabel )) {
655+ return this .doHstoreRangeIndexQuery (indexLabel , query );
656+ }
654657 if (!query .paging ()) {
655658 return this .doIndexQueryBatch (indexLabel , query );
656659 } else {
@@ -660,6 +663,184 @@ private IdHolder doIndexQuery(IndexLabel indexLabel, ConditionQuery query) {
660663 }
661664 }
662665
666+ private boolean needHstoreRangeIndexOrder (IndexLabel indexLabel ) {
667+ return this .store ().provider ().isHstore () &&
668+ indexLabel .indexType ().isRange ();
669+ }
670+
671+ private IdHolder doHstoreRangeIndexQuery (IndexLabel indexLabel ,
672+ ConditionQuery query ) {
673+ if (!query .paging ()) {
674+ if (query .noLimitAndOffset ()) {
675+ return this .doIndexQueryBatch (indexLabel , query );
676+ }
677+ Set <Id > ids = this .querySortedRangeIndexIds (indexLabel , query );
678+ return this .newSortedRangeIndexBatchHolder (query , ids );
679+ }
680+ return new PagingIdHolder (query , q -> {
681+ return this .querySortedRangeIndexPage (indexLabel , q );
682+ });
683+ }
684+
685+ private BatchIdHolder newSortedRangeIndexBatchHolder (ConditionQuery query ,
686+ Set <Id > ids ) {
687+ List <Id > idList = new ArrayList <>(ids );
688+ return new BatchIdHolder (query , Collections .emptyIterator (), batch -> {
689+ throw new IllegalStateException ("Unexpected sorted index fetcher" );
690+ }) {
691+ private int offset = 0 ;
692+
693+ @ Override
694+ public boolean hasNext () {
695+ return this .offset < idList .size ();
696+ }
697+
698+ @ Override
699+ public IdHolder next () {
700+ if (!this .hasNext ()) {
701+ throw new java .util .NoSuchElementException ();
702+ }
703+ return this ;
704+ }
705+
706+ @ Override
707+ public PageIds fetchNext (String page , long batchSize ) {
708+ E .checkArgument (page == null ,
709+ "Not support page parameter by BatchIdHolder" );
710+ if (!this .hasNext ()) {
711+ return PageIds .EMPTY ;
712+ }
713+
714+ int end ;
715+ if (batchSize == Query .NO_LIMIT ) {
716+ end = idList .size ();
717+ } else {
718+ end = (int ) Math .min ((long ) idList .size (),
719+ this .offset + batchSize );
720+ }
721+ Set <Id > batchIds = InsertionOrderUtil .newSet ();
722+ batchIds .addAll (idList .subList (this .offset , end ));
723+ this .offset = end ;
724+ return new PageIds (batchIds , PageState .EMPTY );
725+ }
726+
727+ @ Override
728+ public Set <Id > all () {
729+ Set <Id > allIds = InsertionOrderUtil .newSet ();
730+ allIds .addAll (idList );
731+ return allIds ;
732+ }
733+
734+ @ Override
735+ public void close () {
736+ this .offset = idList .size ();
737+ }
738+ };
739+ }
740+
741+ private Set <Id > querySortedRangeIndexIds (IndexLabel indexLabel ,
742+ ConditionQuery query ) {
743+ List <HugeIndex > indexes = this .querySortedRangeIndexes (indexLabel ,
744+ query );
745+ Set <Id > ids = InsertionOrderUtil .newSet ();
746+ for (HugeIndex index : indexes ) {
747+ ids .addAll (index .elementIds ());
748+ Query .checkForceCapacity (ids .size ());
749+ }
750+ return ids ;
751+ }
752+
753+ private PageIds querySortedRangeIndexPage (IndexLabel indexLabel ,
754+ ConditionQuery query ) {
755+ List <HugeIndex > indexes = this .querySortedRangeIndexes (indexLabel ,
756+ query );
757+ Set <Id > allIds = InsertionOrderUtil .newSet ();
758+ for (HugeIndex index : indexes ) {
759+ allIds .addAll (index .elementIds ());
760+ Query .checkForceCapacity (allIds .size ());
761+ }
762+ if (allIds .isEmpty ()) {
763+ return PageIds .EMPTY ;
764+ }
765+
766+ int start = 0 ;
767+ if (!query .page ().isEmpty ()) {
768+ start = PageState .fromString (query .page ()).offset ();
769+ }
770+ if (start >= allIds .size ()) {
771+ return PageIds .EMPTY ;
772+ }
773+
774+ long total = allIds .size ();
775+ long end = query .noLimit () ? total :
776+ Math .min (total , (long ) start + query .limit ());
777+ Set <Id > pageIds = CollectionUtil .subSet (allIds , start , (int ) end );
778+ if (pageIds .isEmpty ()) {
779+ return PageIds .EMPTY ;
780+ }
781+
782+ int next = (int ) end ;
783+ PageState pageState ;
784+ if (next < total ) {
785+ pageState = new PageState (new byte []{1 }, next , pageIds .size ());
786+ } else {
787+ pageState = new PageState (PageState .EMPTY_BYTES , 0 ,
788+ pageIds .size ());
789+ }
790+ return new PageIds (pageIds , pageState );
791+ }
792+
793+ private List <HugeIndex > querySortedRangeIndexes (IndexLabel indexLabel ,
794+ ConditionQuery query ) {
795+ List <HugeIndex > indexes = new ArrayList <>();
796+ Iterator <BackendEntry > entries = null ;
797+ String spaceGraph = this .params ()
798+ .graph ().spaceGraphName ();
799+ LockUtil .Locks locks = new LockUtil .Locks (spaceGraph );
800+ ConditionQuery scanQuery = query .copy ();
801+ scanQuery .page (null );
802+ scanQuery .limit (Query .NO_LIMIT );
803+ try {
804+ locks .lockReads (LockUtil .INDEX_LABEL_DELETE , indexLabel .id ());
805+ locks .lockReads (LockUtil .INDEX_LABEL_REBUILD , indexLabel .id ());
806+ if (!indexLabel .system ()) {
807+ graph ().indexLabel (indexLabel .id ());
808+ }
809+
810+ entries = super .query (scanQuery ).iterator ();
811+ while (entries .hasNext ()) {
812+ HugeIndex index = this .readMatchedIndex (indexLabel , scanQuery ,
813+ entries .next ());
814+ if (index == null ) {
815+ continue ;
816+ }
817+ this .removeExpiredIndexIfNeeded (index , scanQuery .showExpired ());
818+ this .recordIndexValue (scanQuery , index );
819+ indexes .add (index );
820+ Query .checkForceCapacity (indexes .size ());
821+ }
822+ } finally {
823+ locks .unlock ();
824+ CloseableIterator .closeIterator (entries );
825+ }
826+
827+ Collections .sort (indexes , (a , b ) -> {
828+ return this .compareRangeIndexValues (a , b );
829+ });
830+ return indexes ;
831+ }
832+
833+ @ SuppressWarnings ({"rawtypes" , "unchecked" })
834+ private int compareRangeIndexValues (HugeIndex left , HugeIndex right ) {
835+ Object leftValue = left .fieldValues ();
836+ Object rightValue = right .fieldValues ();
837+ E .checkArgument (leftValue instanceof Comparable ,
838+ "Invalid range index value '%s'" , leftValue );
839+ E .checkArgument (rightValue instanceof Comparable ,
840+ "Invalid range index value '%s'" , rightValue );
841+ return ((Comparable ) leftValue ).compareTo (rightValue );
842+ }
843+
663844 @ Watched (prefix = "index" )
664845 private IdHolder doIndexQueryBatch (IndexLabel indexLabel ,
665846 ConditionQuery query ) {
@@ -772,8 +953,8 @@ private HugeIndex readMatchedIndex(IndexLabel indexLabel,
772953 if (!missingIndexLabel (e )) {
773954 throw e ;
774955 }
775- LOG .debug ("Skip stale index entry with missing index label while " +
776- "querying index label '{}'" , indexLabel .id (), e );
956+ LOG .debug ("Skip stale index entry with missing index label " +
957+ "while querying index label '{}'" , indexLabel .id (), e );
777958 return null ;
778959 }
779960 if (!Objects .equals (index .indexLabelId (), indexLabel .id ())) {
0 commit comments