001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo
016 */
017
018package org.nuxeo.ecm.blob;
019
020import java.util.HashSet;
021import java.util.Set;
022
023import org.nuxeo.ecm.core.blob.binary.BinaryGarbageCollector;
024import org.nuxeo.ecm.core.blob.binary.BinaryManagerStatus;
025import org.nuxeo.ecm.core.blob.binary.CachingBinaryManager;
026
027/**
028 * @author <a href="mailto:ak@nuxeo.com">Arnaud Kervern</a>
029 * @since 7.10
030 */
031public abstract class AbstractBinaryGarbageCollector<T extends CachingBinaryManager> implements BinaryGarbageCollector {
032
033    protected T binaryManager;
034
035    protected BinaryManagerStatus status;
036
037    protected volatile long startTime;
038
039    protected Set<String> marked;
040
041    protected AbstractBinaryGarbageCollector(T binaryManager) {
042        this.binaryManager = binaryManager;
043    }
044
045    @Override
046    public void start() {
047        if (startTime != 0) {
048            throw new RuntimeException("Already started");
049        }
050        startTime = System.currentTimeMillis();
051        status = new BinaryManagerStatus();
052        marked = new HashSet<>();
053
054        // XXX : we should be able to do better
055        // and only remove the cache entry that will be removed from S3
056        binaryManager.fileCache.clear();
057    }
058
059    @Override
060    public void stop(boolean delete) {
061        if (startTime == 0) {
062            throw new RuntimeException("Not started");
063        }
064        try {
065            Set<String> unmarked = getUnmarkedBlobs();
066            marked = null;
067
068            if (delete) {
069                binaryManager.removeBinaries(unmarked);
070            }
071        } finally {
072            status.gcDuration = System.currentTimeMillis() - startTime;
073            startTime = 0;
074        }
075    }
076
077    public abstract Set<String> getUnmarkedBlobs();
078
079    @Override
080    public void mark(String digest) {
081        marked.add(digest);
082    }
083
084    @Override
085    public BinaryManagerStatus getStatus() {
086        return status;
087    }
088
089    @Override
090    public boolean isInProgress() {
091        // volatile as this is designed to be called from another thread
092        return startTime != 0;
093    }
094}