All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arcadedb.query.sql.parser.RebuildIndexStatement Maven / Gradle / Ivy

There is a newer version: 24.11.1
Show newest version
/*
 * Copyright © 2021-present Arcade Data Ltd ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-FileCopyrightText: 2021-present Arcade Data Ltd ([email protected])
 * SPDX-License-Identifier: Apache-2.0
 */
/* Generated By:JJTree: Do not edit this line. ORebuildIndexStatement.java Version 4.3 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=O,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_USERTYPE_VISIBILITY_PUBLIC=true */
package com.arcadedb.query.sql.parser;

import com.arcadedb.database.Database;
import com.arcadedb.database.DatabaseInternal;
import com.arcadedb.exception.CommandExecutionException;
import com.arcadedb.exception.CommandSQLParsingException;
import com.arcadedb.exception.NeedRetryException;
import com.arcadedb.index.Index;
import com.arcadedb.index.IndexException;
import com.arcadedb.index.IndexInternal;
import com.arcadedb.index.TypeIndex;
import com.arcadedb.index.lsm.LSMTreeIndexAbstract;
import com.arcadedb.log.LogManager;
import com.arcadedb.query.sql.executor.CommandContext;
import com.arcadedb.query.sql.executor.InternalResultSet;
import com.arcadedb.query.sql.executor.ResultInternal;
import com.arcadedb.query.sql.executor.ResultSet;
import com.arcadedb.schema.IndexBuilder;
import com.arcadedb.schema.Schema;

import java.util.*;
import java.util.concurrent.atomic.*;
import java.util.logging.*;

public class RebuildIndexStatement extends DDLStatement {
  private static final int                         MAX_ATTEMPTS = 5;
  protected            boolean                     all          = false;
  protected            Identifier                  name;
  protected            Expression                  key;
  protected            Expression                  value;
  protected final      Map settings     = new HashMap<>();

  public RebuildIndexStatement(final int id) {
    super(id);
  }

  @Override
  public ResultSet executeDDL(final CommandContext context) {
    final ResultInternal result = new ResultInternal();
    result.setProperty("operation", "rebuild index");

    int batchSize = IndexBuilder.BUILD_BATCH_SIZE;
    int maxAttempts = MAX_ATTEMPTS;
    if (!settings.isEmpty()) {
      for (Map.Entry entry : settings.entrySet()) {
        if (entry.getKey().toString().equalsIgnoreCase("batchSize"))
          batchSize = Integer.parseInt(entry.getValue().value.toString());
        else if (entry.getKey().toString().equalsIgnoreCase("maxAttempts"))
          maxAttempts = Integer.parseInt(entry.getValue().value.toString());
        else
          throw new CommandSQLParsingException("Unrecognized setting '" + entry.getKey() + "' in rebuild index statement");
      }
    }

    final AtomicLong total = new AtomicLong();

    final Database database = context.getDatabase();

    final Index.BuildIndexCallback callback = (document, totalIndexed) -> {
      total.incrementAndGet();

      if (totalIndexed % 100000 == 0) {
        System.out.print(".");
        System.out.flush();
      }
    };

    String indexName = null;
    try {
      final List indexList = new ArrayList<>();

      if (all) {
        for (final Index idx : database.getSchema().getIndexes()) {
          if (idx.isAutomatic() && !(idx instanceof TypeIndex)) {
            indexName = idx.getName();
            buildIndex(maxAttempts, database, callback, idx, batchSize);
            indexList.add(idx.getName());
          }
        }
      } else {
        final Index idx = database.getSchema().getIndexByName(name.getValue());
        indexName = idx.getName();
        buildIndex(maxAttempts, database, callback, idx, batchSize);
        indexList.add(idx.getName());
      }
      result.setProperty("indexes", indexList);
      result.setProperty("totalIndexed", total.get());

    } catch (Exception e) {
      LogManager.instance().log(this, Level.SEVERE, "Error on rebuilding index '%s'", e, indexName);
      throw new IndexException("Error on rebuilding index '" + indexName + "'", e);
    }

    // SUCCESS
    final InternalResultSet rs = new InternalResultSet();
    rs.add(result);
    return rs;
  }

  private static void buildIndex(final int maxAttempts, Database database, Index.BuildIndexCallback callback, Index idx,
      final int batchSize) {
    if (idx == null)
      throw new CommandExecutionException("Index name is null");

    if (!idx.isAutomatic())
      throw new CommandExecutionException(
          "Cannot rebuild index '" + idx.getName() + "' because it's manual and there aren't indications of what to index");

    for (int attempt = 1; attempt <= maxAttempts; attempt++) {
      try {
        if (!((IndexInternal) idx).isValid()) {
          LogManager.instance()
              .log(RebuildIndexStatement.class, Level.SEVERE, "Error on rebuild invalid index '%s'. The index will be removed",
                  idx.getName());
          return;
        }

        if (((IndexInternal) idx).isCompacting())
          throw new NeedRetryException("Cannot rebuild the index '" + idx.getName() + "' while is compacting");

        final Schema.INDEX_TYPE type = idx.getType();
        final String typeName = idx.getTypeName();
        final boolean unique = idx.isUnique();
        final List propertyNames = idx.getPropertyNames();
        final int pageSize = ((IndexInternal) idx).getPageSize();
        final LSMTreeIndexAbstract.NULL_STRATEGY nullStrategy = idx.getNullStrategy();

        ((DatabaseInternal) database).executeLockingFiles(((IndexInternal) idx).getFileIds(), () -> {
          database.getSchema().dropIndex(idx.getName());

          if (typeName != null && idx instanceof TypeIndex) {
            database.getSchema().buildTypeIndex(typeName, propertyNames.toArray(new String[propertyNames.size()])).withType(type)
                .withUnique(unique).withPageSize(pageSize).withCallback(callback).withBatchSize(batchSize)
                .withMaxAttempts(maxAttempts).withNullStrategy(nullStrategy)//
                .create();

          } else {
            database.getSchema()
                .buildBucketIndex(typeName, database.getSchema().getBucketById(idx.getAssociatedBucketId()).getName(),
                    propertyNames.toArray(new String[propertyNames.size()])).withType(type).withUnique(unique)
                .withPageSize(pageSize).withCallback(callback).withBatchSize(batchSize).withMaxAttempts(maxAttempts)
                .withNullStrategy(nullStrategy)//
                .create();
          }
          return null;
        });

        // OK
        return;

      } catch (NeedRetryException e) {
        try {
          Thread.sleep(200 + 200 * attempt);
        } catch (InterruptedException ex) {
          throw e;
        }
      }
    }
  }

  @Override
  public void toString(final Map params, final StringBuilder builder) {
    builder.append("REBUILD INDEX ");
    if (all) {
      builder.append("*");
    } else {
      name.toString(params, builder);
    }
  }

  @Override
  public RebuildIndexStatement copy() {
    final RebuildIndexStatement result = new RebuildIndexStatement(-1);
    result.all = all;
    result.name = name == null ? null : name.copy();
    return result;
  }

  @Override
  public boolean equals(final Object o) {
    if (this == o)
      return true;
    if (o == null || getClass() != o.getClass())
      return false;

    final RebuildIndexStatement that = (RebuildIndexStatement) o;

    if (all != that.all)
      return false;
    return Objects.equals(name, that.name);
  }

  @Override
  public int hashCode() {
    int result = (all ? 1 : 0);
    result = 31 * result + (name != null ? name.hashCode() : 0);
    return result;
  }
}
/* JavaCC - OriginalChecksum=baca3c54112f1c08700ebdb691fa85bd (do not edit this line) */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy