>From Ian Maxon <[email protected]>:

Ian Maxon has uploaded this change for review. ( 
https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17601 )


Change subject: [ASTERIXDB-3204][SQL][MTD] ANALYZE DATASET *
......................................................................

[ASTERIXDB-3204][SQL][MTD] ANALYZE DATASET *

- user model changes: yes
- storage format changes: no
- interface changes: no

Details:
Introduce the syntax in the title that allows one
to collect samples of all datasets in a dataverse
without specifying them all.

Furthermore, modify the test harness for running
all execution tests with samples to use this in
lieu of regexes to determine which datasets to
analyze.

Change-Id: Ib5e1b2efefe38332ea1f8f7328c63ace12ac9ceb
---
M 
asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
M 
asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/fulltext/stopwords-full-text-filter-1/stopwords-full-text-filter-1.7.adm
M 
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/AnalyzingTestExecutor.java
M 
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
M 
asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
6 files changed, 325 insertions(+), 195 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/01/17601/1

diff --git 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index 28a6d2d..0b171c3 100644
--- 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -275,6 +275,8 @@
     private static final Logger LOGGER = LogManager.getLogger();

     public static final boolean IS_DEBUG_MODE = false;// true
+    public static final String STAR = "*";
+
     protected final List<Statement> statements;
     protected final ICcApplicationContext appCtx;
     protected final SessionOutput sessionOutput;
@@ -4075,17 +4077,213 @@
         }
     }

+    //TODO:make this a record when we require jdk17
+    private final class PreparedSampleIndexInfo {
+        final String newIndexName;
+        final Index existingIndex;
+        final Index newIndexPendingAdd;
+        final JobSpecification sampleIdxToCreate;
+
+        public PreparedSampleIndexInfo(String newIndexName, Index 
existingIndex, Index newIndexPendingAdd,
+                JobSpecification sampleIdxToCreate) {
+            this.newIndexName = newIndexName;
+            this.existingIndex = existingIndex;
+            this.newIndexPendingAdd = newIndexPendingAdd;
+            this.sampleIdxToCreate = sampleIdxToCreate;
+        }
+    }
+
+    private PreparedSampleIndexInfo createAndPrepareSampleIdx(Dataset ds, 
DataverseName dataverseName,
+            MetadataProvider metadataProvider, SourceLocation sourceLoc, int 
sampleCardinalityTarget, long sampleSeed)
+            throws Exception {
+        if (ds == null) {
+            throw new 
CompilationException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, 
ds.getDatasetName(),
+                    dataverseName);
+        }
+        if (ds.getDatasetType() == DatasetType.INTERNAL) {
+            validateDatasetState(metadataProvider, ds, sourceLoc);
+        } else {
+            throw new CompilationException(ErrorCode.OPERATION_NOT_SUPPORTED, 
sourceLoc);
+        }
+
+        IndexType sampleIndexType = IndexType.SAMPLE;
+        Pair<String, String> sampleIndexNames = 
IndexUtil.getSampleIndexNames(ds.getDatasetName());
+        String newIndexName;
+        Index existingIndex = 
MetadataManager.INSTANCE.getIndex(metadataProvider.getMetadataTxnContext(), 
dataverseName,
+                ds.getDatasetName(), sampleIndexNames.first);
+        if (existingIndex != null) {
+            newIndexName = sampleIndexNames.second;
+        } else {
+            existingIndex = 
MetadataManager.INSTANCE.getIndex(metadataProvider.getMetadataTxnContext(), 
dataverseName,
+                    ds.getDatasetName(), sampleIndexNames.second);
+            newIndexName = sampleIndexNames.first;
+        }
+
+        InternalDatasetDetails dsDetails = (InternalDatasetDetails) 
ds.getDatasetDetails();
+
+        Index.SampleIndexDetails newIndexDetailsPendingAdd = new 
Index.SampleIndexDetails(dsDetails.getPrimaryKey(),
+                dsDetails.getKeySourceIndicator(), 
dsDetails.getPrimaryKeyType(), sampleCardinalityTarget, 0, 0,
+                sampleSeed, Collections.emptyMap());
+        Index newIndexPendingAdd = new Index(dataverseName, 
ds.getDatasetName(), newIndexName, sampleIndexType,
+                newIndexDetailsPendingAdd, false, false, 
MetadataUtil.PENDING_ADD_OP);
+
+        // #. add a new index with PendingAddOp
+        
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(), 
newIndexPendingAdd);
+        // #. prepare to create the index artifact in NC.
+        JobSpecification spec =
+                IndexUtil.buildSecondaryIndexCreationJobSpec(ds, 
newIndexPendingAdd, metadataProvider, sourceLoc);
+        if (spec == null) {
+            throw new CompilationException(ErrorCode.COMPILATION_ERROR, 
sourceLoc,
+                    "Failed to create job spec for creating index '" + 
ds.getDatasetName() + "."
+                            + newIndexPendingAdd.getIndexName() + "'");
+        }
+        return new PreparedSampleIndexInfo(newIndexName, existingIndex, 
newIndexPendingAdd, spec);
+    }
+
+    private Index runLoadJobAndFinalizeIndex(Dataset ds, DataverseName 
dataverseName, String newIndexName,
+            JobSpecification spec, IHyracksClientConnection hcc, 
SourceLocation sourceLoc, int sampleCardinalityTarget,
+            long sampleSeed) throws Exception {
+        List<IOperatorStats> opStats = runJob(hcc, spec, jobFlags,
+                
Collections.singletonList(SampleOperationsHelper.DATASET_STATS_OPERATOR_NAME));
+        if (opStats == null || opStats.size() == 0) {
+            throw new 
CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, "", sourceLoc);
+        }
+        DatasetStreamStats stats = new DatasetStreamStats(opStats.get(0));
+        InternalDatasetDetails dsDetails = (InternalDatasetDetails) 
ds.getDatasetDetails();
+        Index.SampleIndexDetails newIndexDetailsFinal = new 
Index.SampleIndexDetails(dsDetails.getPrimaryKey(),
+                dsDetails.getKeySourceIndicator(), 
dsDetails.getPrimaryKeyType(), sampleCardinalityTarget,
+                stats.getCardinality(), stats.getAvgTupleSize(), sampleSeed, 
stats.getIndexesStats());
+        Index newIndexFinal = new Index(dataverseName, ds.getDatasetName(), 
newIndexName, IndexType.SAMPLE,
+                newIndexDetailsFinal, false, false, 
MetadataUtil.PENDING_NO_OP);
+        return newIndexFinal;
+    }
+
+    private void dropExistingSamples(Map<Dataset, PreparedSampleIndexInfo> 
preparedIndexes,
+            Map<Dataset, JobSpecification> existingIndexDropSpecs,
+            Map<Dataset, ProgressState> progressExistingIndexDrop, 
IHyracksClientConnection hcc,
+            MetadataProvider metadataProvider, MetadataTransactionContext 
mdTxnCtx, MutableBoolean bActiveTxn,
+            SourceLocation sourceLoc) throws Exception {
+        mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        bActiveTxn.setTrue();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        Map<Dataset, PreparedSampleIndexInfo> indexesToReplace =
+                preparedIndexes.entrySet().stream().filter(e -> 
e.getValue().existingIndex != null)
+                        .collect(Collectors.toMap(e -> e.getKey(), e -> 
e.getValue()));
+        for (Map.Entry<Dataset, PreparedSampleIndexInfo> info : 
indexesToReplace.entrySet()) {
+            Index existingIndex = info.getValue().existingIndex;
+            Dataset ds = info.getKey();
+            
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
+                    existingIndex.getDataverseName(), 
existingIndex.getDatasetName(), existingIndex.getIndexName());
+            existingIndex.setPendingOp(MetadataUtil.PENDING_DROP_OP);
+            
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(), 
existingIndex);
+            JobSpecification existingIndexDropSpec =
+                    IndexUtil.buildDropIndexJobSpec(existingIndex, 
metadataProvider, ds, sourceLoc);
+            existingIndexDropSpecs.put(info.getKey(), existingIndexDropSpec);
+        }
+        MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+        bActiveTxn.setFalse();
+
+        // #. set existing index to PendingDropOp because we'll be dropping it 
next
+        indexesToReplace.keySet().stream()
+                .map(ds -> progressExistingIndexDrop.put(ds, 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA));
+
+        // #. drop existing index on NCs
+        for (JobSpecification existingIndexDropSpec : 
existingIndexDropSpecs.values()) {
+            runJob(hcc, existingIndexDropSpec);
+        }
+
+        // #. drop existing index metadata
+        mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        bActiveTxn.setTrue();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        for (Map.Entry<Dataset, PreparedSampleIndexInfo> info : 
indexesToReplace.entrySet()) {
+            Index existingIndex = info.getValue().existingIndex;
+            Dataset ds = info.getKey();
+            
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
+                    existingIndex.getDataverseName(), 
existingIndex.getDatasetName(), existingIndex.getIndexName());
+            progressExistingIndexDrop.put(ds, ProgressState.NO_PROGRESS);
+        }
+        MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+        bActiveTxn.setFalse();
+        indexesToReplace.keySet().stream().map(ds -> 
progressExistingIndexDrop.put(ds, ProgressState.NO_PROGRESS));
+    }
+
+    private void abortPendingSampleDrop(Dataset ds, Index existingIndex, 
JobSpecification dropSpec, Exception e,
+            IHyracksClientConnection hcc, MetadataProvider metadataProvider, 
MetadataTransactionContext mdTxnCtx)
+            throws RemoteException {
+        // #. execute compensation operations remove the index in NCs
+        try {
+            runJob(hcc, dropSpec);
+        } catch (Exception e2) {
+            // do no throw exception since still the metadata needs to be 
compensated.
+            e.addSuppressed(e2);
+        }
+        // #. remove the record from the metadata.
+        mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        try {
+            
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
+                    existingIndex.getDataverseName(), 
existingIndex.getDatasetName(), existingIndex.getIndexName());
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+        } catch (Exception e2) {
+            e.addSuppressed(e2);
+            abort(e, e2, mdTxnCtx);
+            throw new IllegalStateException("System is inconsistent state: 
pending index("
+                    + existingIndex.getDataverseName() + "." + 
existingIndex.getDatasetName() + "."
+                    + existingIndex.getIndexName() + ") couldn't be removed 
from the metadata", e);
+        }
+    }
+
+    private void abortPendingSampleCreate(Dataset ds, Index 
newIndexPendingAdd, MetadataProvider metadataProvider,
+            MetadataTransactionContext mdTxnCtx, MutableBoolean bActiveTxn, 
IHyracksClientConnection hcc,
+            SourceLocation sourceLoc, Exception e) throws RemoteException {
+        // #. execute compensation operations remove the index in NCs
+        mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        bActiveTxn.setTrue();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        try {
+            JobSpecification jobSpec =
+                    IndexUtil.buildDropIndexJobSpec(newIndexPendingAdd, 
metadataProvider, ds, sourceLoc);
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+            bActiveTxn.setFalse();
+            runJob(hcc, jobSpec);
+        } catch (Exception e2) {
+            e.addSuppressed(e2);
+            if (bActiveTxn.booleanValue()) {
+                abort(e, e2, mdTxnCtx);
+            }
+        }
+        // #. remove the record from the metadata.
+        mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
+        metadataProvider.setMetadataTxnContext(mdTxnCtx);
+        try {
+            
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
+                    newIndexPendingAdd.getDataverseName(), 
newIndexPendingAdd.getDatasetName(),
+                    newIndexPendingAdd.getIndexName());
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+        } catch (Exception e2) {
+            e.addSuppressed(e2);
+            abort(e, e2, mdTxnCtx);
+            throw new IllegalStateException("System is in inconsistent state: 
pending index("
+                    + newIndexPendingAdd.getDataverseName() + "." + 
newIndexPendingAdd.getDatasetName() + "."
+                    + newIndexPendingAdd.getIndexName() + ") couldn't be 
removed from the metadata", e);
+        }
+    }
+
     protected void doAnalyzeDataset(MetadataProvider metadataProvider, 
AnalyzeStatement stmtAnalyze,
-            DataverseName dataverseName, String datasetName, 
IHyracksClientConnection hcc,
+            DataverseName dataverseName, String datasetNameOrStar, 
IHyracksClientConnection hcc,
             IRequestParameters requestParameters) throws Exception {
         SourceLocation sourceLoc = stmtAnalyze.getSourceLocation();
-        ProgressState progressNewIndexCreate = ProgressState.NO_PROGRESS;
-        ProgressState progressExistingIndexDrop = ProgressState.NO_PROGRESS;
-        Dataset ds = null;
-        Index existingIndex = null, newIndexPendingAdd = null;
-        JobSpecification existingIndexDropSpec = null;
+        Map<Dataset, ProgressState> progressNewIndexCreate = new HashMap<>(),
+                progressExistingIndexDrop = new HashMap<>();
+        List<Dataset> dses = null;
+        Map<Dataset, Index> newIndexesPendingAdd = new HashMap<>(), 
newFinalizedIndexes = new HashMap<>();
+        Map<Dataset, JobSpecification> existingIndexDropSpecs = new 
HashMap<>(), sampleLoadSpecs = new HashMap<>();
+        Map<Dataset, PreparedSampleIndexInfo> preparedIndexes = new 
HashMap<>();
+        int sampleCardinalityTarget = stmtAnalyze.getSampleSize();
+        long sampleSeed = stmtAnalyze.getOrCreateSampleSeed();
         MetadataTransactionContext mdTxnCtx = 
MetadataManager.INSTANCE.beginTransaction();
-        boolean bActiveTxn = true;
+        MutableBoolean bActiveTxn = new MutableBoolean(true);
         metadataProvider.setMetadataTxnContext(mdTxnCtx);
         try {
             // Check if the dataverse exists
@@ -4093,187 +4291,98 @@
             if (dv == null) {
                 throw new CompilationException(ErrorCode.UNKNOWN_DATAVERSE, 
sourceLoc, dataverseName);
             }
-            // Check if the dataset exists
-            ds = metadataProvider.findDataset(dataverseName, datasetName);
-            if (ds == null) {
-                throw new 
CompilationException(ErrorCode.UNKNOWN_DATASET_IN_DATAVERSE, sourceLoc, 
datasetName,
-                        dataverseName);
-            }
-            if (ds.getDatasetType() == DatasetType.INTERNAL) {
-                validateDatasetState(metadataProvider, ds, sourceLoc);
+            if (STAR.equals(datasetNameOrStar)) {
+                //Get all datasets, and only take the internal ones to be 
sampled.
+                dses = MetadataManager.INSTANCE.getDataverseDatasets(mdTxnCtx, 
dataverseName);
+                dses = dses.stream().filter(dataset -> 
dataset.getDatasetType() == DatasetType.INTERNAL)
+                        .collect(Collectors.toList());
             } else {
-                throw new 
CompilationException(ErrorCode.OPERATION_NOT_SUPPORTED, sourceLoc);
+                // Check if the dataset exists, and if it does, make it a list 
of one value.
+                dses = List.of(MetadataManager.INSTANCE.getDataset(mdTxnCtx, 
dataverseName, datasetNameOrStar));
             }
-
-            IndexType sampleIndexType = IndexType.SAMPLE;
-            Pair<String, String> sampleIndexNames = 
IndexUtil.getSampleIndexNames(datasetName);
-            String newIndexName;
-            existingIndex = 
MetadataManager.INSTANCE.getIndex(metadataProvider.getMetadataTxnContext(), 
dataverseName,
-                    datasetName, sampleIndexNames.first);
-            if (existingIndex != null) {
-                newIndexName = sampleIndexNames.second;
-            } else {
-                existingIndex = 
MetadataManager.INSTANCE.getIndex(metadataProvider.getMetadataTxnContext(),
-                        dataverseName, datasetName, sampleIndexNames.second);
-                newIndexName = sampleIndexNames.first;
-            }
-
-            InternalDatasetDetails dsDetails = (InternalDatasetDetails) 
ds.getDatasetDetails();
-            int sampleCardinalityTarget = stmtAnalyze.getSampleSize();
-            long sampleSeed = stmtAnalyze.getOrCreateSampleSeed();
-
-            Index.SampleIndexDetails newIndexDetailsPendingAdd = new 
Index.SampleIndexDetails(dsDetails.getPrimaryKey(),
-                    dsDetails.getKeySourceIndicator(), 
dsDetails.getPrimaryKeyType(), sampleCardinalityTarget, 0, 0,
-                    sampleSeed, Collections.emptyMap());
-            newIndexPendingAdd = new Index(dataverseName, datasetName, 
newIndexName, sampleIndexType,
-                    newIndexDetailsPendingAdd, false, false, 
MetadataUtil.PENDING_ADD_OP);
-
-            // #. add a new index with PendingAddOp
-            
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(), 
newIndexPendingAdd);
-            // #. prepare to create the index artifact in NC.
-            JobSpecification spec =
-                    IndexUtil.buildSecondaryIndexCreationJobSpec(ds, 
newIndexPendingAdd, metadataProvider, sourceLoc);
-            if (spec == null) {
-                throw new CompilationException(ErrorCode.COMPILATION_ERROR, 
sourceLoc,
-                        "Failed to create job spec for creating index '" + 
ds.getDatasetName() + "."
-                                + newIndexPendingAdd.getIndexName() + "'");
+            //Add the pending index to metadata, and prepare the sample index 
creation job
+            for (Dataset ds : dses) {
+                PreparedSampleIndexInfo info = createAndPrepareSampleIdx(ds, 
dataverseName, metadataProvider, sourceLoc,
+                        sampleCardinalityTarget, sampleSeed);
+                preparedIndexes.put(ds, info);
+                progressNewIndexCreate.put(ds, 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA);
             }
             MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-            bActiveTxn = false;
-            progressNewIndexCreate = 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA;
+            bActiveTxn.setFalse();

             // #. create the index artifact in NC.
-            runJob(hcc, spec);
+            for (PreparedSampleIndexInfo info : preparedIndexes.values()) {
+                runJob(hcc, info.sampleIdxToCreate);
+            }

-            // #. flush dataset
-            FlushDatasetUtil.flushDataset(hcc, metadataProvider, 
dataverseName, datasetName);
+            // #. flush datasets
+            for (Dataset ds : dses) {
+                FlushDatasetUtil.flushDataset(hcc, metadataProvider, 
dataverseName, ds.getDatasetName());
+            }

             mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-            bActiveTxn = true;
+            bActiveTxn.setTrue();
             metadataProvider.setMetadataTxnContext(mdTxnCtx);
-
-            // #. load data into the index in NC.
-            spec = IndexUtil.buildSecondaryIndexLoadingJobSpec(ds, 
newIndexPendingAdd, metadataProvider, sourceLoc);
-            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-            bActiveTxn = false;
-
-            List<IOperatorStats> opStats = runJob(hcc, spec, jobFlags,
-                    
Collections.singletonList(SampleOperationsHelper.DATASET_STATS_OPERATOR_NAME));
-            if (opStats == null || opStats.size() == 0) {
-                throw new 
CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, "", sourceLoc);
+            for (Dataset ds : dses) {
+                // #. load data into the index in NC.
+                JobSpecification spec = 
IndexUtil.buildSecondaryIndexLoadingJobSpec(ds,
+                        preparedIndexes.get(ds).newIndexPendingAdd, 
metadataProvider, sourceLoc);
+                sampleLoadSpecs.put(ds, spec);
             }
-            DatasetStreamStats stats = new DatasetStreamStats(opStats.get(0));
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+            bActiveTxn.setFalse();

-            Index.SampleIndexDetails newIndexDetailsFinal = new 
Index.SampleIndexDetails(dsDetails.getPrimaryKey(),
-                    dsDetails.getKeySourceIndicator(), 
dsDetails.getPrimaryKeyType(), sampleCardinalityTarget,
-                    stats.getCardinality(), stats.getAvgTupleSize(), 
sampleSeed, stats.getIndexesStats());
-            Index newIndexFinal = new Index(dataverseName, datasetName, 
newIndexName, sampleIndexType,
-                    newIndexDetailsFinal, false, false, 
MetadataUtil.PENDING_NO_OP);
-
+            //load the indexes, and finalize the entries in metadata
+            for (Map.Entry<Dataset, JobSpecification> finalSpecs : 
sampleLoadSpecs.entrySet()) {
+                Dataset ds = finalSpecs.getKey();
+                JobSpecification spec = finalSpecs.getValue();
+                Index finalizedIndex =
+                        runLoadJobAndFinalizeIndex(ds, dataverseName, 
preparedIndexes.get(ds).newIndexName, spec, hcc,
+                                sourceLoc, sampleCardinalityTarget, 
sampleSeed);
+                newFinalizedIndexes.put(ds, finalizedIndex);
+            }
             // #. begin new metadataTxn
             mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-            bActiveTxn = true;
+            bActiveTxn.setTrue();
             metadataProvider.setMetadataTxnContext(mdTxnCtx);
             // #. add same new index with PendingNoOp after deleting its entry 
with PendingAddOp
-            
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
-                    newIndexPendingAdd.getDataverseName(), 
newIndexPendingAdd.getDatasetName(),
-                    newIndexPendingAdd.getIndexName());
-            
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(), 
newIndexFinal);
-            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-            bActiveTxn = false;
-            progressNewIndexCreate = ProgressState.NO_PROGRESS;
-
-            if (existingIndex != null) {
-                // #. set existing index to PendingDropOp because we'll be 
dropping it next
-                mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-                bActiveTxn = true;
-                metadataProvider.setMetadataTxnContext(mdTxnCtx);
+            for (Map.Entry<Dataset, PreparedSampleIndexInfo> e : 
preparedIndexes.entrySet()) {
+                Index newIndexPendingAdd = e.getValue().newIndexPendingAdd;
                 
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
-                        existingIndex.getDataverseName(), 
existingIndex.getDatasetName(), existingIndex.getIndexName());
-                existingIndex.setPendingOp(MetadataUtil.PENDING_DROP_OP);
-                
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(), 
existingIndex);
-                existingIndexDropSpec = 
IndexUtil.buildDropIndexJobSpec(existingIndex, metadataProvider, ds, sourceLoc);
-                MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-                progressExistingIndexDrop = 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA;
-                bActiveTxn = false;
-
-                // #. drop existing index on NCs
-                runJob(hcc, existingIndexDropSpec);
-
-                // #. drop existing index metadata
-                mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-                bActiveTxn = true;
-                metadataProvider.setMetadataTxnContext(mdTxnCtx);
-                
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
-                        existingIndex.getDataverseName(), 
existingIndex.getDatasetName(), existingIndex.getIndexName());
-                MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-                bActiveTxn = false;
-                progressExistingIndexDrop = ProgressState.NO_PROGRESS;
+                        newIndexPendingAdd.getDataverseName(), 
newIndexPendingAdd.getDatasetName(),
+                        newIndexPendingAdd.getIndexName());
+                
MetadataManager.INSTANCE.addIndex(metadataProvider.getMetadataTxnContext(),
+                        newFinalizedIndexes.get(e.getKey()));
+                progressNewIndexCreate.put(e.getKey(), 
ProgressState.NO_PROGRESS);
             }
+            MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
+            bActiveTxn.setFalse();

+            //now, drop all the old samples
+            dropExistingSamples(preparedIndexes, existingIndexDropSpecs, 
progressExistingIndexDrop, hcc,
+                    metadataProvider, mdTxnCtx, bActiveTxn, sourceLoc);
         } catch (Exception e) {
             LOGGER.error("failed to analyze dataset; executing compensating 
operations", e);
-            if (bActiveTxn) {
+            //abort the open transaction, if there is one
+            if (bActiveTxn.booleanValue()) {
                 abort(e, e, mdTxnCtx);
             }
-
-            if (progressExistingIndexDrop == 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA) {
-                // #. execute compensation operations remove the index in NCs
-                try {
-                    runJob(hcc, existingIndexDropSpec);
-                } catch (Exception e2) {
-                    // do no throw exception since still the metadata needs to 
be compensated.
-                    e.addSuppressed(e2);
-                }
-                // #. remove the record from the metadata.
-                mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-                metadataProvider.setMetadataTxnContext(mdTxnCtx);
-                try {
-                    
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
-                            existingIndex.getDataverseName(), 
existingIndex.getDatasetName(),
-                            existingIndex.getIndexName());
-                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-                } catch (Exception e2) {
-                    e.addSuppressed(e2);
-                    abort(e, e2, mdTxnCtx);
-                    throw new IllegalStateException("System is inconsistent 
state: pending index("
-                            + existingIndex.getDataverseName() + "." + 
existingIndex.getDatasetName() + "."
-                            + existingIndex.getIndexName() + ") couldn't be 
removed from the metadata", e);
-                }
-            } else if (progressNewIndexCreate == 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA) {
-                // #. execute compensation operations remove the index in NCs
-                mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-                bActiveTxn = true;
-                metadataProvider.setMetadataTxnContext(mdTxnCtx);
-                try {
-                    JobSpecification jobSpec =
-                            
IndexUtil.buildDropIndexJobSpec(newIndexPendingAdd, metadataProvider, ds, 
sourceLoc);
-                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-                    bActiveTxn = false;
-                    runJob(hcc, jobSpec);
-                } catch (Exception e2) {
-                    e.addSuppressed(e2);
-                    if (bActiveTxn) {
-                        abort(e, e2, mdTxnCtx);
-                    }
-                }
-                // #. remove the record from the metadata.
-                mdTxnCtx = MetadataManager.INSTANCE.beginTransaction();
-                metadataProvider.setMetadataTxnContext(mdTxnCtx);
-                try {
-                    
MetadataManager.INSTANCE.dropIndex(metadataProvider.getMetadataTxnContext(),
-                            newIndexPendingAdd.getDataverseName(), 
newIndexPendingAdd.getDatasetName(),
-                            newIndexPendingAdd.getIndexName());
-                    MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
-                } catch (Exception e2) {
-                    e.addSuppressed(e2);
-                    abort(e, e2, mdTxnCtx);
-                    throw new IllegalStateException("System is in inconsistent 
state: pending index("
-                            + newIndexPendingAdd.getDataverseName() + "." + 
newIndexPendingAdd.getDatasetName() + "."
-                            + newIndexPendingAdd.getIndexName() + ") couldn't 
be removed from the metadata", e);
+            //compensate all in-progress index drops
+            for (Map.Entry<Dataset, ProgressState> dropInFlight : 
progressExistingIndexDrop.entrySet()) {
+                if (dropInFlight.getValue() == 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA) {
+                    Dataset ds = dropInFlight.getKey();
+                    abortPendingSampleDrop(ds, 
preparedIndexes.get(ds).existingIndex, existingIndexDropSpecs.get(ds), e,
+                            hcc, metadataProvider, mdTxnCtx);
                 }
             }
-
+            //compensate all in-progress creates
+            for (Map.Entry<Dataset, ProgressState> createInFlight : 
progressNewIndexCreate.entrySet()) {
+                if (createInFlight.getValue() == 
ProgressState.ADDED_PENDINGOP_RECORD_TO_METADATA) {
+                    Index newIndexPendingAdd = 
newIndexesPendingAdd.get(createInFlight.getKey());
+                    abortPendingSampleCreate(createInFlight.getKey(), 
newIndexPendingAdd, metadataProvider, mdTxnCtx,
+                            bActiveTxn, hcc, sourceLoc, e);
+                }
+            }
             throw e;
         }
     }
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/AnalyzingTestExecutor.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/AnalyzingTestExecutor.java
index 2658804..0618da2 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/AnalyzingTestExecutor.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/AnalyzingTestExecutor.java
@@ -32,9 +32,7 @@

 public class AnalyzingTestExecutor extends TestExecutor {

-    private Pattern loadPattern = 
Pattern.compile("(load)\\s+(dataset|collection)\\s+([a-zA-z0-9\\.`]+)\\s+using",
-            Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
-    private Pattern upsertPattern = 
Pattern.compile("^(upsert|insert)\\s+into\\s+([a-zA-z0-9\\.`]+)\\s*(\\(|as)?",
+    private Pattern connectFeedPattern = 
Pattern.compile("(connect|start)\\s+(feed)\\s+([a-zA-z0-9\\.`]+)",
             Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
     private Pattern usePattern = 
Pattern.compile("use\\s+(dataverse\\s+)?([a-zA-z0-9\\.`]+)\\s*;",
             Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
@@ -49,35 +47,31 @@
         Matcher dvMatcher = usePattern.matcher(statement);
         String dv = "";
         if (dvMatcher.find()) {
-            dv = dvMatcher.group(2) + ".";
+            dv = dvMatcher.group(2);
         }
-        Matcher dsMatcher = loadPattern.matcher(statement);
-        Matcher upsertMatcher = upsertPattern.matcher(statement);
         ExtractedResult res = super.executeUpdateOrDdl(statement, 
outputFormat, getQueryServiceUri(SQLPP));
-        analyzeFromRegex(dsMatcher, dv, 3);
-        analyzeFromRegex(upsertMatcher, dv, 2);
+        Matcher connectFeedMatcher = connectFeedPattern.matcher(statement);
+        if (!connectFeedMatcher.find()) {
+            analyzeEverything(dv);
+        }
         return res;
     }

-    private void analyzeFromRegex(Matcher m, String dv, int pos) throws 
Exception {
-        while (m.find()) {
-            String ds = m.group(pos);
-            StringBuilder analyzeStmt = new StringBuilder();
-            analyzeStmt.append("ANALYZE DATASET ");
-            if (!ds.contains(".")) {
-                analyzeStmt.append(dv);
-            }
-            analyzeStmt.append(ds);
-            analyzeStmt.append(" WITH {\"sample-seed\": \"1000\"}");
-            analyzeStmt.append(";");
-            InputStream resultStream = 
executeQueryService(analyzeStmt.toString(), getQueryServiceUri(SQLPP),
-                    TestCaseContext.OutputFormat.CLEAN_JSON);
-            String resultStr = IOUtils.toString(resultStream, UTF_8);
-            JsonNode result = RESULT_NODE_READER.<ObjectNode> 
readValue(resultStr).get("status");
-            if (!"success".equals(result.asText())) {
-                JsonNode error = RESULT_NODE_READER.<ObjectNode> 
readValue(resultStr).get("errors");
-                throw new IllegalStateException("ANALYZE DATASET failed with 
error: " + error);
-            }
+    private void analyzeEverything(String dv) throws Exception {
+        StringBuilder analyzeStmt = new StringBuilder();
+        if (!"".equals(dv)) {
+            analyzeStmt.append("USE " + dv + ";");
+        }
+        analyzeStmt.append("ANALYZE DATASET *");
+        analyzeStmt.append(" WITH {\"sample-seed\": \"1000\"}");
+        analyzeStmt.append(";");
+        InputStream resultStream = executeQueryService(analyzeStmt.toString(), 
getQueryServiceUri(SQLPP),
+                TestCaseContext.OutputFormat.CLEAN_JSON);
+        String resultStr = IOUtils.toString(resultStream, UTF_8);
+        JsonNode result = RESULT_NODE_READER.<ObjectNode> 
readValue(resultStr).get("status");
+        if (!"success".equals(result.asText())) {
+            JsonNode error = RESULT_NODE_READER.<ObjectNode> 
readValue(resultStr).get("errors");
+            throw new IllegalStateException("ANALYZE DATASET failed with 
error: " + error);
         }
     }

diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
index 10a22b4..be97bcb 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/SqlppAnalyzedExecutionTest.java
@@ -44,7 +44,7 @@
 public class SqlppAnalyzedExecutionTest {
     protected static final String TEST_CONFIG_FILE_NAME = 
"src/test/resources/cc-analyze.conf";
     private final String[] denyList = { "synonym: synonym-01", "ddl: 
analyze-dataset-1", "misc: dump_index",
-            "array-index: composite-index-queries", "filters: upsert", 
"column: analyze-dataset",
+            "array-index: composite-index-queries", "filters: upsert", 
"filters: delete", "column: analyze-dataset",
             "ddl: analyze-dataset-with-indexes", "warnings: 
cardinality-hint-warning" };

     @BeforeClass
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/fulltext/stopwords-full-text-filter-1/stopwords-full-text-filter-1.7.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/fulltext/stopwords-full-text-filter-1/stopwords-full-text-filter-1.7.adm
index 16635ef..38b9409 100644
--- 
a/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/fulltext/stopwords-full-text-filter-1/stopwords-full-text-filter-1.7.adm
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results_cbo/fulltext/stopwords-full-text-filter-1/stopwords-full-text-filter-1.7.adm
@@ -2,4 +2,4 @@
 { "DataverseName": "MyDataVerse", "DatasetName": "MyMessageDataset", 
"IndexName": "message_ft_index_0", "IndexStructure": 
"SINGLE_PARTITION_WORD_INVIX", "SearchKey": [ [ "myMessageBody" ] ], 
"IsPrimary": false, "Timestamp": "Wed Mar 08 15:49:09 PST 2023", "PendingOp": 0 
}
 { "DataverseName": "MyDataVerse", "DatasetName": "MyMessageDataset", 
"IndexName": "message_ft_index_1", "IndexStructure": 
"SINGLE_PARTITION_WORD_INVIX", "SearchKey": [ [ "myMessageBody" ] ], 
"IsPrimary": false, "Timestamp": "Wed Mar 08 15:49:10 PST 2023", "PendingOp": 
0, "FullTextConfig": "my_first_stopword_config" }
 { "DataverseName": "MyDataVerse", "DatasetName": "MyMessageDataset", 
"IndexName": "message_ft_index_2", "IndexStructure": 
"SINGLE_PARTITION_WORD_INVIX", "SearchKey": [ [ "myMessageBody" ] ], 
"IsPrimary": false, "Timestamp": "Wed Mar 08 15:49:10 PST 2023", "PendingOp": 
0, "FullTextConfig": "my_second_stopword_config" }
-{ "DataverseName": "MyDataVerse", "DatasetName": "MyMessageDataset", 
"IndexName": "sample_idx_2_MyMessageDataset", "IndexStructure": "SAMPLE", 
"SearchKey": [ [ "myMessageId" ] ], "IsPrimary": false, "Timestamp": "Wed Mar 
08 15:49:09 PST 2023", "PendingOp": 0, "SampleCardinalityTarget": 1063, 
"SourceCardinality": 2, "SourceAvgItemSize": 62 }
+{ "DataverseName": "MyDataVerse", "DatasetName": "MyMessageDataset", 
"IndexName": "sample_idx_1_MyMessageDataset", "IndexStructure": "SAMPLE", 
"SearchKey": [ [ "myMessageId" ] ], "IsPrimary": false, "Timestamp": "Wed Mar 
08 15:49:09 PST 2023", "PendingOp": 0, "SampleCardinalityTarget": 1063, 
"SourceCardinality": 2, "SourceAvgItemSize": 62 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj 
b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index 9e3dea4..5fcfb64 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -2802,7 +2802,7 @@
   Pair<DataverseName,Identifier> nameComponents = null;
 }
 {
-  <ANALYZE> { startToken = token; } DatasetToken() nameComponents = 
QualifiedName()
+  <ANALYZE> { startToken = token; } DatasetToken() (nameComponents = 
QualifiedName() | <MUL> { nameComponents = new Pair(null,new Identifier("*")); 
})
   (
     stmt = AnalyzeDatasetDropStatement(startToken, nameComponents.first, 
nameComponents.second)
     | stmt = AnalyzeDatasetStatement(startToken, nameComponents.first, 
nameComponents.second)
diff --git 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
index 8ee8f11..4156777 100644
--- 
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
+++ 
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/MetadataLockUtil.java
@@ -313,8 +313,12 @@
     @Override
     public void analyzeDatasetBegin(IMetadataLockManager lockMgr, LockList 
locks, DataverseName dataverseName,
             String datasetName) throws AlgebricksException {
-        lockMgr.acquireDataverseReadLock(locks, dataverseName);
-        lockMgr.acquireDatasetCreateIndexLock(locks, dataverseName, 
datasetName);
+        if ("*".equals(datasetName)) {
+            lockMgr.acquireDataverseWriteLock(locks, dataverseName);
+        } else {
+            lockMgr.acquireDataverseReadLock(locks, dataverseName);
+            lockMgr.acquireDatasetCreateIndexLock(locks, dataverseName, 
datasetName);
+        }
     }

     @Override

--
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17601
To unsubscribe, or for help writing mail filters, visit 
https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: Ib5e1b2efefe38332ea1f8f7328c63ace12ac9ceb
Gerrit-Change-Number: 17601
Gerrit-PatchSet: 1
Gerrit-Owner: Ian Maxon <[email protected]>
Gerrit-MessageType: newchange

Reply via email to