/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o 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 this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal.slots; import com.db4o.*; import com.db4o.internal.*; import com.db4o.internal.freespace.*; import com.db4o.internal.ids.*; /** * @exclude */ public class SlotChange extends TreeInt { private static class SlotChangeOperation { private final String _type; public SlotChangeOperation(String type) { _type = type; } static final SlotChangeOperation create = new SlotChangeOperation("create"); static final SlotChangeOperation update = new SlotChangeOperation("update"); static final SlotChangeOperation delete = new SlotChangeOperation("delete"); @Override public String toString() { return _type; } } private SlotChangeOperation _firstOperation; private SlotChangeOperation _currentOperation; protected Slot _newSlot; public SlotChange(int id) { super(id); } public Object shallowClone() { SlotChange sc = new SlotChange(0); sc.newSlot(_newSlot); return super.shallowCloneInternal(sc); } public void accumulateFreeSlot(TransactionalIdSystemImpl idSystem, FreespaceCommitter freespaceCommitter, boolean forFreespace) { if( forFreespace() != forFreespace){ return; } if(_firstOperation == SlotChangeOperation.create){ return; } if(_currentOperation == SlotChangeOperation.update || _currentOperation == SlotChangeOperation.delete){ Slot slot = modifiedSlotInParentIdSystem(idSystem); if(Slot.isNull(slot)){ slot = idSystem.committedSlot(_key); } // No old slot at all can be the case if the object // has been deleted by another transaction and we add it again. if(! Slot.isNull(slot)){ freespaceCommitter.delayedFree(slot, freeToSystemFreespaceSystem()); } } } protected boolean forFreespace() { return false; } protected Slot modifiedSlotInParentIdSystem(TransactionalIdSystemImpl idSystem) { return idSystem.modifiedSlotInParentIdSystem(_key); } public boolean isDeleted() { return slotModified() && _newSlot.isNull(); } public boolean isNew() { return _firstOperation == SlotChangeOperation.create; } private final boolean isFreeOnRollback() { return ! Slot.isNull(_newSlot); } public final boolean slotModified() { return _newSlot != null; } /** * FIXME: Check where pointers should be freed on commit. * This should be triggered in this class. */ // private final boolean isFreePointerOnCommit() { // return isBitSet(FREE_POINTER_ON_COMMIT_BIT); // } public Slot newSlot() { return _newSlot; } public Object read(ByteArrayBuffer reader) { SlotChange change = new SlotChange(reader.readInt()); Slot newSlot = new Slot(reader.readInt(), reader.readInt()); change.newSlot(newSlot); return change; } public void rollback(FreespaceManager freespaceManager) { if (isFreeOnRollback()) { freespaceManager.free(_newSlot); } } public void write(ByteArrayBuffer writer) { if (slotModified()) { writer.writeInt(_key); writer.writeInt(_newSlot.address()); writer.writeInt(_newSlot.length()); } } public final void writePointer(LocalObjectContainer container) { if (slotModified()) { container.writePointer(_key, _newSlot); } } private void newSlot(Slot slot){ _newSlot = slot; } public void notifySlotUpdated(FreespaceManager freespaceManager, Slot slot) { if(DTrace.enabled){ DTrace.NOTIFY_SLOT_UPDATED.logLength(_key, slot); } freePreviouslyModifiedSlot(freespaceManager); _newSlot = slot; operation(SlotChangeOperation.update); } protected void freePreviouslyModifiedSlot(FreespaceManager freespaceManager) { if(Slot.isNull(_newSlot)){ return; } free(freespaceManager, _newSlot); _newSlot = null; } protected void free(FreespaceManager freespaceManager, Slot slot) { if(slot.isNull()){ return; } if(freespaceManager == null){ return; } freespaceManager.free(slot); } private void operation(SlotChangeOperation operation) { if(_firstOperation == null){ _firstOperation = operation; } _currentOperation = operation; } public void notifySlotCreated(Slot slot) { if(DTrace.enabled){ DTrace.NOTIFY_SLOT_CREATED.log(_key); DTrace.NOTIFY_SLOT_CREATED.logLength(slot); } operation(SlotChangeOperation.create); _newSlot = slot; } public void notifyDeleted(FreespaceManager freespaceManager) { if(DTrace.enabled){ DTrace.NOTIFY_SLOT_DELETED.log(_key); } operation(SlotChangeOperation.delete); freePreviouslyModifiedSlot(freespaceManager); _newSlot = Slot.ZERO; } public boolean removeId(){ return false; } @Override public String toString() { String str = "id: " + _key; if(_newSlot != null){ str += " newSlot: " + _newSlot; } return str; } protected boolean freeToSystemFreespaceSystem(){ return false; } }