/* Copyright (c) 2013 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * David Winslow (Boundless) - initial implementation */ package org.locationtech.geogig.storage.bdbje; import java.util.Iterator; import java.util.List; import org.locationtech.geogig.api.ObjectId; import org.locationtech.geogig.storage.Deduplicator; import com.sleepycat.je.Database; import com.sleepycat.je.DatabaseEntry; import com.sleepycat.je.LockMode; import com.sleepycat.je.OperationStatus; /** * A {@link Deduplicator} that utilizes a BDB JE {@link Database} as an index of object ids. * * @see BDBJEDeduplicationService */ public class BDBJEDeduplicator implements Deduplicator { private static final DatabaseEntry DUMMY_DATA = new DatabaseEntry(new byte[0]); private Database objectDb; private final BDBJEDeduplicationService service; /** * @param database the database that represents the index of object ids * @param service used by {@link #reset()} and {@link #release()} */ public BDBJEDeduplicator(Database database, BDBJEDeduplicationService service) { this.objectDb = database; this.service = service; } @Override public boolean isDuplicate(ObjectId id) { return safeTest(id); } @Override public void removeDuplicates(List<ObjectId> ids) { Iterator<ObjectId> iterator = ids.iterator(); while (iterator.hasNext()) { if (safeTest(iterator.next())) { iterator.remove(); } } } @Override public void reset() { objectDb.close(); service.reset(this); } @Override public void release() { objectDb.close(); service.deregister(this); } /** * Assigns a new database to this deduplicator, only to be called by * {@link BDBJEDeduplicationService#reset(BDBJEDeduplicator)}. * * @param db the database that replaces the current one. */ protected void setDatabase(Database db) { this.objectDb = db; } private boolean destructiveTest(final ObjectId id) { OperationStatus status = objectDb.putNoOverwrite(null, asDatabaseEntry(id), DUMMY_DATA); return status == OperationStatus.KEYEXIST; } private boolean safeTest(final ObjectId id) { OperationStatus status = objectDb.getSearchBoth(null, asDatabaseEntry(id), DUMMY_DATA, LockMode.DEFAULT); return status == OperationStatus.SUCCESS; } private DatabaseEntry asDatabaseEntry(final ObjectId id) { return new DatabaseEntry(id.getRawValue()); } @Override public boolean visit(ObjectId id) { return destructiveTest(id); } }