/**
* Copyright (c) 2012, Thilo Planz. All rights reserved.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package v7db.files.mongodb;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import v7db.files.spi.ContentPointer;
import v7db.files.spi.ContentSHA;
import v7db.files.spi.InlineContent;
import v7db.files.spi.ReferenceTracking;
import v7db.files.spi.StoredContent;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;
/**
* References are stored in a collection, with a document for each owner.
*
* <ul>
* <li> <code>_id</code>: The ownerId as given by the application.
* <li> <code>refs</code>: The sha hashes used by the ContentPointers from the
* last updates in an array.
* <li> <code>refHistory</code>: The sum of all previous and current entries in
* <code>ref</code>.
* <li><code>purge</code>: This field is added when the object is to be purged.
* It contains the timestamp of that event.
* </ul>
*
*
*/
public class MongoReferenceTracking implements ReferenceTracking {
private final DBCollection refCollection;
public final static String DEFAULT_REFERENCE_COLLECTION_NAME = "v7files.refs";
public MongoReferenceTracking(DB db) {
this(db.getCollection(DEFAULT_REFERENCE_COLLECTION_NAME));
}
public MongoReferenceTracking(DBCollection refCollection) {
this.refCollection = refCollection;
}
public void purge(Object ownerId) throws IOException {
refCollection.update(new BasicDBObject("_id", ownerId),
new BasicDBObject("$set",
new BasicDBObject("purge", new Date())));
}
public void updateReferences(Object ownerId, ContentPointer... contents)
throws IOException {
List<byte[]> content = new ArrayList<byte[]>();
for (ContentPointer cp : contents) {
if (cp instanceof InlineContent)
continue;
if (cp instanceof StoredContent)
content.add(((StoredContent) cp).getBaseSHA());
else if (cp instanceof ContentSHA)
content.add(((ContentSHA) cp).getSHA());
else
throw new IllegalArgumentException(cp.getClass().getName());
}
WriteResult r = refCollection.update(new BasicDBObject("_id", ownerId),
new BasicDBObject("$set", new BasicDBObject("refs", content))
.append("$addToSet", new BasicDBObject("refHistory",
new BasicDBObject("$each", content))), false,
false, WriteConcern.SAFE);
if (r.getN() == 1)
return;
if (r.getN() != 0)
throw new IllegalStateException();
refCollection.insert(WriteConcern.SAFE, new BasicDBObject("_id",
ownerId).append("refs", content).append("refHistory", content));
}
}