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

org.apache.jackrabbit.oak.plugins.document.SplitDocumentCleanUp Maven / Gradle / Ivy

There is a newer version: 1.62.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
package org.apache.jackrabbit.oak.plugins.document;

import java.io.Closeable;
import java.io.IOException;
import java.util.List;

import com.google.common.collect.Lists;

import org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType.INTERMEDIATE;
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType.NONE;

/**
 * Implements a split document cleanup.
 */
public class SplitDocumentCleanUp implements Closeable {

    private static final Logger LOG = LoggerFactory.getLogger(SplitDocumentCleanUp.class);

    // number of document IDs to collect before removing them in a single call
    private static final int DELETE_BATCH_SIZE = 100;

    protected final DocumentStore store;
    protected final Iterable splitDocGarbage;
    protected final VersionGCStats stats;
    protected final List idsToBeDeleted = Lists.newArrayList();
    protected int deleteCount;

    protected SplitDocumentCleanUp(DocumentStore store,
                                   VersionGCStats stats,
                                   Iterable splitDocGarbage) {
        this.store = store;
        this.stats = stats;
        this.splitDocGarbage = splitDocGarbage;
    }

    protected SplitDocumentCleanUp disconnect() {
        for (NodeDocument splitDoc : splitDocGarbage) {
            disconnect(splitDoc);
            collectIdToBeDeleted(splitDoc.getId());
        }
        return this;
    }

    /**
     * Collects document IDs for subsequent deletion.
     * 

* Implementations that override * {@link SplitDocumentCleanUp#deleteSplitDocuments()} should override this * method as well. */ protected void collectIdToBeDeleted(String id) { idsToBeDeleted.add(id); // proceed to delete early if we reach DELETE_BATCH_SIZE if (idsToBeDeleted.size() >= DELETE_BATCH_SIZE) { store.remove(NODES, idsToBeDeleted); deleteCount += idsToBeDeleted.size(); idsToBeDeleted.clear(); } } protected int deleteSplitDocuments() { store.remove(NODES, idsToBeDeleted); return idsToBeDeleted.size() + deleteCount; } private void disconnect(NodeDocument splitDoc) { String splitId = splitDoc.getId(); String mainId = Utils.getIdFromPath(splitDoc.getMainPath()); NodeDocument doc = store.find(NODES, mainId); if (doc == null) { LOG.warn("Main document {} already removed. Split document is {}", mainId, splitId); return; } String splitDocPath = splitDoc.getPath(); int slashIdx = splitDocPath.lastIndexOf('/'); int height = Integer.parseInt(splitDocPath.substring(slashIdx + 1)); Revision rev = Revision.fromString( splitDocPath.substring(splitDocPath.lastIndexOf('/', slashIdx - 1) + 1, slashIdx)); doc = doc.findPrevReferencingDoc(rev, height); if (doc == null) { LOG.warn("Split document {} for path {} not referenced anymore. Main document is {}", splitId, splitDocPath, mainId); return; } // remove reference if (doc.getSplitDocType() == INTERMEDIATE) { disconnectFromIntermediate(doc, rev); } else { markStaleOnMain(doc, rev, height); } } private void disconnectFromIntermediate(NodeDocument splitDoc, Revision rev) { checkArgument(splitDoc.getSplitDocType() == INTERMEDIATE, "Illegal type: %s", splitDoc.getSplitDocType()); UpdateOp update = new UpdateOp(splitDoc.getId(), false); NodeDocument.removePrevious(update, rev); NodeDocument old = store.findAndUpdate(NODES, update); if (old != null && old.getPreviousRanges().size() == 1 && old.getPreviousRanges().containsKey(rev)) { // this was the last reference on an intermediate split doc disconnect(old); store.remove(NODES, old.getId()); stats.intermediateSplitDocGCCount++; } } final void markStaleOnMain(NodeDocument main, Revision rev, int height) { checkArgument(main.getSplitDocType() == NONE, "Illegal type: %s", main.getSplitDocType()); UpdateOp update = new UpdateOp(main.getId(), false); NodeDocument.setStalePrevious(update, rev, height); store.findAndUpdate(NODES, update); } @Override public void close() throws IOException { Utils.closeIfCloseable(splitDocGarbage); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy