@@ -290,9 +290,17 @@ abstract static class StatefulOperation implements Operation {
290290 */
291291 public LmdbSailStore (File dataDir , StoreProperties properties , LmdbStoreConfig config )
292292 throws IOException , SailException {
293+ this (dataDir , properties , config , true );
294+ }
295+
296+ public LmdbSailStore (File dataDir , StoreProperties properties , LmdbStoreConfig config ,
297+ boolean sketchBasedJoinEstimatorEnabled )
298+ throws IOException , SailException {
293299 this .setFactory = new PersistentSetFactory <>(dataDir );
294300 this .bulkOperationSize = config .getBulkOperationSize ();
295- this .sketchBasedJoinEstimator = new SketchBasedJoinEstimator (this , sketchEstimatorConfig (config ));
301+ this .sketchBasedJoinEstimator = sketchBasedJoinEstimatorEnabled
302+ ? new SketchBasedJoinEstimator (this , sketchEstimatorConfig (config ))
303+ : null ;
296304 Function <Long , byte []> encode = element -> {
297305 ByteBuffer bb = ByteBuffer .allocate (Long .BYTES ).order (ByteOrder .BIG_ENDIAN );
298306 bb .putLong (element );
@@ -310,18 +318,20 @@ public LmdbSailStore(File dataDir, StoreProperties properties, LmdbStoreConfig c
310318 statementPatternCardinalitySource = new LmdbStatementPatternCardinalitySource (valueStore , tripleStore );
311319 mayHaveInferred = tripleStore .hasTriples (false );
312320 initialized = true ;
313- Path estimatorPath = new File (dataDir , JOIN_ESTIMATOR_FILE_NAME ).toPath ();
314- boolean snapshotExists = Files .isRegularFile (estimatorPath .resolve ("metadata.bin" ));
315- filterSelectivityStats = new LmdbFilterSelectivityStats (estimatorPath , tripleStore , valueStore );
316- sketchBasedJoinEstimator .setRebuildAllowedSupplier (() -> !storeTxnStarted .get ());
317- sketchBasedJoinEstimator .setLearnedStatsProvider (filterSelectivityStats );
318- sketchBasedJoinEstimator .setPatternFilterSamplingEstimator (filterSelectivityStats );
319- sketchBasedJoinEstimator .setPatternCardinalityProvider (statementPatternCardinalitySource ::estimate );
320- sketchBasedJoinEstimator .configurePersistence (estimatorPath , snapshotExists );
321- if (!snapshotExists ) {
322- sketchBasedJoinEstimator .rebuild ();
321+ if (sketchBasedJoinEstimator != null ) {
322+ Path estimatorPath = new File (dataDir , JOIN_ESTIMATOR_FILE_NAME ).toPath ();
323+ boolean snapshotExists = Files .isRegularFile (estimatorPath .resolve ("metadata.bin" ));
324+ filterSelectivityStats = new LmdbFilterSelectivityStats (estimatorPath , tripleStore , valueStore );
325+ sketchBasedJoinEstimator .setRebuildAllowedSupplier (() -> !storeTxnStarted .get ());
326+ sketchBasedJoinEstimator .setLearnedStatsProvider (filterSelectivityStats );
327+ sketchBasedJoinEstimator .setPatternFilterSamplingEstimator (filterSelectivityStats );
328+ sketchBasedJoinEstimator .setPatternCardinalityProvider (statementPatternCardinalitySource ::estimate );
329+ sketchBasedJoinEstimator .configurePersistence (estimatorPath , snapshotExists );
330+ if (!snapshotExists ) {
331+ sketchBasedJoinEstimator .rebuild ();
332+ }
333+ sketchBasedJoinEstimator .startBackgroundRefresh (3 );
323334 }
324- sketchBasedJoinEstimator .startBackgroundRefresh (3 );
325335 } finally {
326336 if (!initialized ) {
327337 close ();
@@ -392,7 +402,9 @@ public void close() throws SailException {
392402 try {
393403 cancelAndDrainScheduledEstimatorPersist ();
394404 persistEstimatorState ();
395- sketchBasedJoinEstimator .close ();
405+ if (sketchBasedJoinEstimator != null ) {
406+ sketchBasedJoinEstimator .close ();
407+ }
396408 } finally {
397409 try {
398410 if (namespaceStore != null ) {
@@ -466,7 +478,9 @@ private void cancelAndDrainScheduledEstimatorPersist() {
466478 }
467479
468480 private void persistEstimatorState () {
469- sketchBasedJoinEstimator .persistIfDirty ();
481+ if (sketchBasedJoinEstimator != null ) {
482+ sketchBasedJoinEstimator .persistIfDirty ();
483+ }
470484 if (filterSelectivityStats != null ) {
471485 filterSelectivityStats .persistIfDirty ();
472486 }
@@ -624,8 +638,8 @@ public SailSink sink(IsolationLevel level) throws SailException {
624638
625639 @ Override
626640 public LmdbSailDataset dataset (IsolationLevel level ) throws SailException {
627- boolean isEstimatorRefresh = SketchBasedJoinEstimator . REFRESH_THREAD_NAME
628- .equals (Thread .currentThread ().getName ());
641+ boolean isEstimatorRefresh = sketchBasedJoinEstimator != null
642+ && SketchBasedJoinEstimator . REFRESH_THREAD_NAME .equals (Thread .currentThread ().getName ());
629643 // Refresh reader transactions can remain open across write commits and must not
630644 // participate in the active txn reset/renew cycle.
631645 boolean trackActive = !isEstimatorRefresh ;
@@ -647,7 +661,7 @@ public LmdbSailSink(boolean explicit, IsolationLevel level) throws SailException
647661 }
648662
649663 private void queueEstimatorAdd (Statement st ) {
650- if (!explicit ) {
664+ if (!explicit || sketchBasedJoinEstimator == null ) {
651665 return ;
652666 }
653667 if (nonIsolated ) {
@@ -665,7 +679,7 @@ private void queueEstimatorAdd(Statement st) {
665679 }
666680
667681 private void queueEstimatorRemove (Statement st ) {
668- if (!explicit ) {
682+ if (!explicit || sketchBasedJoinEstimator == null ) {
669683 return ;
670684 }
671685 if (nonIsolated ) {
@@ -705,7 +719,7 @@ private void clearEstimatorUpdates() {
705719 if (nonIsolated ) {
706720 // In NONE isolation updates are applied eagerly; rollback cannot replay inverse deltas safely.
707721 // Discard the derived state and rebuild it from authoritative store data.
708- if (nonIsolatedUpdatesApplied ) {
722+ if (nonIsolatedUpdatesApplied && sketchBasedJoinEstimator != null ) {
709723 sketchBasedJoinEstimator .discardAndMarkForRebuild ();
710724 nonIsolatedUpdatesApplied = false ;
711725 }
@@ -720,7 +734,9 @@ private void recoverEstimatorAfterFailure(String action, RuntimeException e) {
720734 synchronized (pendingEstimatorUpdates ) {
721735 pendingEstimatorUpdates .clear ();
722736 }
723- sketchBasedJoinEstimator .discardAndMarkForRebuild ();
737+ if (sketchBasedJoinEstimator != null ) {
738+ sketchBasedJoinEstimator .discardAndMarkForRebuild ();
739+ }
724740 nonIsolatedUpdatesApplied = false ;
725741 logger .warn ("Discarded join estimator state after failure while {}; store data remains authoritative" ,
726742 action ,
@@ -808,12 +824,16 @@ public void flush() throws SailException {
808824 // The triple/value stores are authoritative once both commits succeed.
809825 storeTxnStarted .set (false );
810826 applyEstimatorUpdates ();
811- filterSelectivityStats .recordStoreMutation ();
827+ if (filterSelectivityStats != null ) {
828+ filterSelectivityStats .recordStoreMutation ();
829+ }
812830 nonIsolatedUpdatesApplied = false ;
813- try {
814- scheduleEstimatorPersist ();
815- } catch (RuntimeException e ) {
816- logger .warn ("Failed to schedule join estimator persistence after commit" , e );
831+ if (sketchBasedJoinEstimator != null || filterSelectivityStats != null ) {
832+ try {
833+ scheduleEstimatorPersist ();
834+ } catch (RuntimeException e ) {
835+ logger .warn ("Failed to schedule join estimator persistence after commit" , e );
836+ }
817837 }
818838 }
819839 }
0 commit comments