
org.zoodb.jdo.internal.model1p.DataDeleteSink1P Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parent Show documentation
Show all versions of parent Show documentation
ZooDB Java JDO Object Database.
The newest version!
/*
* Copyright 2009-2013 Tilmann Zaeschke. All rights reserved.
*
* This file is part of ZooDB.
*
* ZooDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ZooDB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ZooDB. If not, see .
*
* See the README and COPYING files for further information.
*/
package org.zoodb.jdo.internal.model1p;
import java.lang.reflect.Field;
import java.util.Arrays;
import javax.jdo.JDOFatalDataStoreException;
import javax.jdo.JDOObjectNotFoundException;
import org.zoodb.api.impl.ZooPCImpl;
import org.zoodb.jdo.internal.DataDeleteSink;
import org.zoodb.jdo.internal.GenericObject;
import org.zoodb.jdo.internal.SerializerTools;
import org.zoodb.jdo.internal.ZooClassDef;
import org.zoodb.jdo.internal.ZooFieldDef;
import org.zoodb.jdo.internal.client.AbstractCache;
import org.zoodb.jdo.internal.server.index.AbstractPagedIndex.LongLongIndex;
import org.zoodb.jdo.internal.server.index.BitTools;
import org.zoodb.jdo.internal.server.index.PagedOidIndex;
import org.zoodb.jdo.internal.server.index.PagedPosIndex;
import org.zoodb.jdo.internal.server.index.SchemaIndex.SchemaIndexEntry;
import org.zoodb.jdo.internal.util.Util;
/**
* A data sink deletes objects of a given class. It can be backed either by a file- or
* in-memory-storage, or in future by a network channel through which data is sent to a server.
*
* Each sink handles objects of one class only. Therefore sinks can be associated with
* ZooClassDefs and PCContext instances.
*
* @author ztilmann
*/
public class DataDeleteSink1P implements DataDeleteSink {
private static final int BUFFER_SIZE = 1000;
private final Node1P node;
private final ZooClassDef cls;
private final PagedOidIndex oidIndex;
private SchemaIndexEntry sie;
private final ZooPCImpl[] buffer = new ZooPCImpl[BUFFER_SIZE];
private int bufferCnt = 0;
private final GenericObject[] bufferGO = new GenericObject[BUFFER_SIZE];
private int bufferGOCnt = 0;
private boolean isStarted = false;
public DataDeleteSink1P(Node1P node, AbstractCache cache, ZooClassDef cls,
PagedOidIndex oidIndex) {
this.node = node;
this.cls = cls;
this.oidIndex = oidIndex;
this.sie = node.getSchemaIE(cls);
}
/* (non-Javadoc)
* @see org.zoodb.jdo.internal.model1p.DataSink#write(org.zoodb.api.impl.ZooPCImpl)
*/
@Override
public void delete(ZooPCImpl obj) {
if (!isStarted) {
this.sie = node.getSchemaIE(cls);
isStarted = true;
}
//updated index
//This is buffered to reduce look-ups to find field indices.
buffer[bufferCnt++] = obj;
if (bufferCnt == BUFFER_SIZE) {
flushBuffer();
}
}
@Override
public void deleteGeneric(GenericObject obj) {
if (!isStarted) {
this.sie = node.getSchemaIE(cls);
isStarted = true;
}
//updated index
//This is buffered to reduce look-ups to find field indices.
bufferGO[bufferGOCnt++] = obj;
if (bufferGOCnt == BUFFER_SIZE) {
flushBuffer();
}
}
@Override
public void reset() {
if (isStarted) {
Arrays.fill(buffer, null);
bufferCnt = 0;
if (bufferGOCnt > 0) {
Arrays.fill(bufferGO, null);
bufferGOCnt = 0;
}
isStarted = false;
}
}
/* (non-Javadoc)
* @see org.zoodb.jdo.internal.model1p.DataSink#flush()
*/
@Override
public void flush() {
if (isStarted) {
flushBuffer();
//To avoid memory leaks...
Arrays.fill(buffer, null);
isStarted = false;
}
}
private void flushBuffer() {
updateFieldIndices();
bufferCnt = 0;
if (bufferGOCnt > 0) {
updateFieldIndicesGO();
bufferGOCnt = 0;
}
}
private void updateFieldIndices() {
final ZooPCImpl[] buffer = this.buffer;
final int bufferCnt = this.bufferCnt;
//remove field index entries
int iInd = -1;
for (ZooFieldDef field: cls.getAllFields()) {
if (!field.isIndexed()) {
continue;
}
iInd++;
//TODO?
//For now we define that an index is shared by all classes and sub-classes that have
//a matching field. So there is only one index which is defined in the top-most class
SchemaIndexEntry schemaTop = node.getSchemaIE(field.getDeclaringType());
LongLongIndex fieldInd = (LongLongIndex) schemaTop.getIndex(field);
try {
Field jField = field.getJavaField();
for (int i = 0; i < bufferCnt; i++) {
ZooPCImpl co = buffer[i];
//new and clean objects do not have a backup
if (!co.jdoZooIsNew()) {
//this can be null for objects that get deleted.
//These are still dirty, because of the deletion
if (co.jdoZooGetBackup()!=null) {
//TODO It is bad that we update ALL indices here, even if the value didn't
//change... -> Field-wise dirty!
long l = co.jdoZooGetBackup()[iInd];
fieldInd.removeLong(l, co.jdoZooGetOid());
continue;
}
}
long l;
if (field.isString()) {
if (co.zooIsHollow()) {
//We need to activate it to get the values!
//But only for String, the primitives should be fine.
co.jdoZooGetContext().getNode().refreshObject(co);
}
String str = (String)jField.get(co);
l = BitTools.toSortableLong(str);
} else {
l = SerializerTools.primitiveFieldToLong(co, jField,
field.getPrimitiveType());
}
fieldInd.removeLong(l, co.jdoZooGetOid());
}
} catch (SecurityException e) {
throw new JDOFatalDataStoreException(
"Error accessing field: " + field.getName(), e);
} catch (IllegalArgumentException e) {
throw new JDOFatalDataStoreException(
"Error accessing field: " + field.getName(), e);
} catch (IllegalAccessException e) {
throw new JDOFatalDataStoreException(
"Error accessing field: " + field.getName(), e);
}
}
//now delete the object
PagedPosIndex ois = sie.getObjectIndexLatestSchemaVersion();
for (int i = 0; i < bufferCnt; i++) {
long oid = buffer[i].jdoZooGetOid();
delete(oid, ois);
}
}
private void updateFieldIndicesGO() {
final GenericObject[] buffer = this.bufferGO;
final int bufferCnt = this.bufferGOCnt;
//remove field index entries
int iInd = -1;
for (ZooFieldDef field: cls.getAllFields()) {
if (!field.isIndexed()) {
continue;
}
iInd++;
//TODO?
//For now we define that an index is shared by all classes and sub-classes that have
//a matching field. So there is only one index which is defined in the top-most class
SchemaIndexEntry schemaTop = node.getSchemaIE(field.getDeclaringType());
LongLongIndex fieldInd = (LongLongIndex) schemaTop.getIndex(field);
try {
for (int i = 0; i < bufferCnt; i++) {
GenericObject co = buffer[i];
//new and clean objects do not have a backup
if (!co.isNew()) {
//this can be null for objects that get deleted.
//These are still dirty, because of the deletion
if (co.jdoZooGetBackup()!=null) {
//TODO It is bad that we update ALL indices here, even if the value didn't
//change... -> Field-wise dirty!
long l = co.jdoZooGetBackup()[iInd];
fieldInd.removeLong(l, co.getOid());
continue;
}
}
long l;
if (field.isString()) {
if (co.isHollow()) {
//We need to activate it to get the values!
//But only for String, the primitives should be fine.
throw new UnsupportedOperationException();
//TODO do we really need this?
//co.getContext().getNode().refreshObject(co);
}
l = (Long)co.getFieldRaw(field.getFieldPos());
} else {
Object primO = co.getFieldRaw(field.getFieldPos());
l = SerializerTools.primitiveToLong(primO, field.getPrimitiveType());
}
fieldInd.removeLong(l, co.getOid());
}
} catch (IllegalArgumentException e) {
throw new JDOFatalDataStoreException(
"Error accessing field: " + field.getName(), e);
}
}
//now delete the object
PagedPosIndex ois = sie.getObjectIndexLatestSchemaVersion();
for (int i = 0; i < bufferCnt; i++) {
long oid = buffer[i].getOid();
delete(oid, ois);
}
}
private void delete(long oid, PagedPosIndex ois) {
long pos = oidIndex.removeOidNoFail(oid, -1); //value=long with 32=page + 32=offs
if (pos == -1) {
throw new JDOObjectNotFoundException("Object not found: " + Util.oidToString(oid));
}
//update class index and
//tell the FSM about the free page (if we have one)
//prevPos.getValue() returns > 0, so the loop is performed at least once.
do {
//remove and report to FSM if applicable
long nextPos = ois.removePosLongAndCheck(pos);
//use mark for secondary pages
nextPos = nextPos | PagedPosIndex.MARK_SECONDARY;
pos = nextPos;
} while (pos != PagedPosIndex.MARK_SECONDARY);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy