com.torodb.torod.db.backends.meta.routines.DeleteDocuments.java Source code

Java tutorial

Introduction

Here is the source code for com.torodb.torod.db.backends.meta.routines.DeleteDocuments.java

Source

/*
 *     This file is part of ToroDB.
 *
 *     ToroDB is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     ToroDB is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with ToroDB. If not, see <http://www.gnu.org/licenses/>.
 *
 *     Copyright (c) 2014, 8Kdata Technology
 *     
 */
package com.torodb.torod.db.backends.meta.routines;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nonnull;

import org.jooq.Configuration;
import org.jooq.ConnectionProvider;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Schema;
import org.jooq.Table;
import org.jooq.impl.DSL;

import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.Sets;
import com.torodb.torod.core.connection.exceptions.RetryTransactionException;
import com.torodb.torod.core.subdocument.structure.ArrayStructure;
import com.torodb.torod.core.subdocument.structure.DocStructure;
import com.torodb.torod.core.subdocument.structure.StructureElement;
import com.torodb.torod.core.subdocument.structure.StructureElementVisitor;
import com.torodb.torod.db.backends.DatabaseInterface;
import com.torodb.torod.db.backends.meta.CollectionSchema;
import com.torodb.torod.db.backends.tables.SubDocTable;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 *
 */
public class DeleteDocuments {

    public static int execute(Configuration configuration, CollectionSchema colSchema,
            Multimap<DocStructure, Integer> didsByStructure, boolean justOne,
            @Nonnull DatabaseInterface databaseInterface) throws RetryTransactionException {
        Multimap<DocStructure, Integer> didsByStructureToDelete;
        if (didsByStructure.isEmpty()) {
            return 0;
        }

        if (justOne) {
            didsByStructureToDelete = MultimapBuilder.hashKeys(1).arrayListValues(1).build();

            Map.Entry<DocStructure, Integer> aEntry = didsByStructure.entries().iterator().next();

            didsByStructureToDelete.put(aEntry.getKey(), aEntry.getValue());
        } else {
            didsByStructureToDelete = didsByStructure;
        }

        try {
            return execute(configuration, colSchema, didsByStructureToDelete, databaseInterface);
        } catch (SQLException ex) {
            throw new RuntimeException(ex);
        }
    }

    public static int execute(Configuration configuration, CollectionSchema colSchema,
            Multimap<DocStructure, Integer> didsByStructure, @Nonnull DatabaseInterface databaseInterface)
            throws SQLException, RetryTransactionException {
        TableProvider tableProvider = new TableProvider(colSchema);

        DSLContext dsl = DSL.using(configuration);

        Set<SubDocTable> tables = Sets.newHashSet();
        for (DocStructure structure : didsByStructure.keySet()) {
            tables.clear();
            structure.accept(tableProvider, tables);

            executeDeleteSubDocuments(dsl, tables, didsByStructure.get(structure), databaseInterface);
        }

        Set<Integer> dids = Sets.newHashSet(didsByStructure.values());
        return executeDeleteRoots(dsl, colSchema, dids, databaseInterface);
    }

    private static void executeDeleteSubDocuments(DSLContext dsl, Set<SubDocTable> tables, Collection<Integer> dids,
            @Nonnull DatabaseInterface databaseInterface) throws RetryTransactionException {

        ConnectionProvider connectionProvider = dsl.configuration().connectionProvider();
        Connection connection = connectionProvider.acquire();
        try {
            for (SubDocTable table : tables) {
                delete(connection, table.getSchema(), table, dids, databaseInterface);
            }
        } catch (SQLException ex) {
            //TODO: change exceptions
            throw new RuntimeException(ex);
        } finally {
            connectionProvider.release(connection);
        }
    }

    private static int executeDeleteRoots(DSLContext dsl, CollectionSchema colSchema, Collection<Integer> dids,
            @Nonnull DatabaseInterface databaseInterface) throws SQLException, RetryTransactionException {
        ConnectionProvider connectionProvider = dsl.configuration().connectionProvider();
        Connection connection = connectionProvider.acquire();

        try {
            Table<Record> rootTable = DSL.tableByName(colSchema.getName(), "root");

            return delete(connection, colSchema, rootTable, dids, databaseInterface);
        } finally {
            connectionProvider.release(connection);
        }
    }

    @SuppressFBWarnings("SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING")
    private static int delete(Connection connection, Schema schema, Table table, Collection<Integer> dids,
            @Nonnull DatabaseInterface databaseInterface) throws SQLException, RetryTransactionException {
        try (PreparedStatement ps = connection.prepareStatement(databaseInterface
                .deleteDidsStatement(schema.getName(), table.getName(), SubDocTable.DID_COLUMN_NAME))) {

            databaseInterface.setDeleteDidsStatementParameters(ps, dids);

            int[] executeResult = ps.executeBatch();
            int result = 0;
            for (int i = 0; i < executeResult.length; i++) {
                int iestResult = executeResult[i];
                if (iestResult >= 0) {
                    result += iestResult;
                }
            }
            return result;
        } catch (SQLException sqlException) {
            databaseInterface.handleRetryException(sqlException);

            throw sqlException;
        }
    }

    private static class TableProvider implements StructureElementVisitor<Void, Collection<SubDocTable>> {

        private final CollectionSchema colSchema;

        public TableProvider(CollectionSchema colSchema) {
            this.colSchema = colSchema;
        }

        @Override
        public Void visit(DocStructure structure, Collection<SubDocTable> arg) {
            arg.add(colSchema.getSubDocTable(structure.getType()));

            for (StructureElement child : structure.getElements().values()) {
                child.accept(this, arg);
            }

            return null;
        }

        @Override
        public Void visit(ArrayStructure structure, Collection<SubDocTable> arg) {
            for (StructureElement child : structure.getElements().values()) {
                child.accept(this, arg);
            }

            return null;
        }
    }
}