Package com.mobixess.jodb.core.transaction

Source Code of com.mobixess.jodb.core.transaction.TransactionUtils$DataContainersCache

/*
Copyright (C) 2007  Mobixess Inc. http://www.java-objects-database.com

This file is part of the JODB (Java Objects Database) open source project.

JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.

JODB 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, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package com.mobixess.jodb.core.transaction;

import java.io.DataOutput;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Vector;
import java.util.WeakHashMap;

import com.mobixess.jodb.core.JODBConfig;
import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.index.IndexingRecord;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IOTicket;
import com.mobixess.jodb.core.io.IRandomAccessDataBuffer;
import com.mobixess.jodb.core.io.JODBIOBase;
import com.mobixess.jodb.core.io.ObjectDataContainer;
import com.mobixess.jodb.core.io.ObjectDataContainer.FieldsIterator;
import com.mobixess.jodb.core.plugin.IClassProcessor;
import com.mobixess.jodb.core.plugin.JODBPluginRegistry;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.util.ArrayUtils;
import com.mobixess.jodb.util.Utils;

/**
* @author Mobixess
*
*/
public class TransactionUtils{
   
   
    private final static int MAX_DATA_CONTAINERS_CACHE = 100;
   
//    private static class LaunchObjectsLevelsCache{
//        private Vector<WeakReference<Vector<FieldRecord>>> _cache = new Vector<WeakReference<Vector<FieldRecord>>>();
//       
//        public Vector<FieldRecord> getFieldRecordCache(int level){
//            if(level >= _cache.size()){
//                _cache.setSize(level+1);
//            }
//            WeakReference<Vector<FieldRecord>> weakReference = _cache.elementAt(level);
//            Vector<FieldRecord> result = null;
//            if(weakReference == null || (result = weakReference.get()) == null){
//                result = new Vector<FieldRecord>();
//                weakReference = new WeakReference<Vector<FieldRecord>>(result);
//                _cache.setElementAt(weakReference, level);
//            }
//            result.setSize(0);
//            return result;
//        }
//    }
   
    @SuppressWarnings("unchecked")
    public static class DataContainersCache{
       
        private WeakRefObjectDataContainerCache _objectDataContainerCache = new WeakRefObjectDataContainerCache();
        private WeakRefIndexContainerCache _weakRefIndexContainerCache = new WeakRefIndexContainerCache();
        private WeakRefVectorCache _weakRefVectorCache = new WeakRefVectorCache();
       
        private DataContainersCache() {
        }
       
        public ObjectDataContainer pullObjectDataContainer(){
            return _objectDataContainerCache.pull();
        }
       
        public void pushObjectDataContainer(ObjectDataContainer container){
            _objectDataContainerCache.push(container);
        }
       
        public IndexingRecord pullIndexRecord(){
            return _weakRefIndexContainerCache.pull();
        }
       
        public void pushIndexRecord(IndexingRecord byteBuffer){
            _weakRefIndexContainerCache.push(byteBuffer);
        }
       
        public void pushVector(Vector container){
            _weakRefVectorCache.push(container);
        }
       
        public Vector pullVector(){
            return _weakRefVectorCache.pull();
        }
       
    }
   
    private static class  WeakRefObjectDataContainerCache extends WeakRefDataContainerCache<ObjectDataContainer> {

        public WeakRefObjectDataContainerCache() {
            super(MAX_DATA_CONTAINERS_CACHE);
        }
       
        @Override
        public ObjectDataContainer pull()
        {
            ObjectDataContainer result = super.pull();
            if(result == null){
                result = new ObjectDataContainer();
            }
            return result;
        }
       
        @Override
        public void push(ObjectDataContainer container)
        {
            container.reset();
            super.push(container);
        }
    }
   
    private static class  WeakRefVectorCache extends WeakRefDataContainerCache<Vector> {

        public WeakRefVectorCache() {
            super(10);
        }
       
        @Override
        public Vector pull()
        {
            Vector result = super.pull();
            if(result == null){
                result = new Vector(2);
            }
            return result;
        }
       
        @Override
        public void push(Vector container)
        {
            container.clear();
            super.push(container);
        }
       
    }
   
    private static class  WeakRefIndexContainerCache extends WeakRefDataContainerCache<IndexingRecord> {
        public WeakRefIndexContainerCache() {
            super(4);
        }
       
        @Override
        public IndexingRecord pull()
        {
            IndexingRecord indexingRecord = super.pull();
            if(indexingRecord == null){
                indexingRecord = new IndexingRecord();
            }
            indexingRecord.reset();
            return indexingRecord;
        }
    }
   
    private static class  WeakRefDataContainerCache <ContainerType> {
        private WeakReference<ContainerType>[] _pull;
        private int _index;
       
        @SuppressWarnings("unchecked")
        public WeakRefDataContainerCache(int size) {
            _pull = new WeakReference[size];
        }
       
        public ContainerType pull(){
            WeakReference<ContainerType> reference;
            for (; _index>=0; _index--) {
                reference = _pull[_index];
                if (reference!=null) {
                    ContainerType result = reference.get();
                    _pull[_index] = null;
                    if (result != null) {
                        return result;
                    }
                }               
            }
            return null;
        }
       
        public void push(ContainerType container){
            if(_index==_pull.length-1){
                return;
            }
            _pull[++_index]=new WeakReference<ContainerType>(container);
        }
    }

//    private static ThreadLocal<WeakReference<LaunchObjectsLevelsCache>> _launchObjectCache = new ThreadLocal<WeakReference<LaunchObjectsLevelsCache>>() {
//        @Override
//        protected WeakReference<LaunchObjectsLevelsCache> initialValue()
//        {
//            return new WeakReference<LaunchObjectsLevelsCache>(new LaunchObjectsLevelsCache());
//        }
//    };
   
    private static ThreadLocal<WeakReference<DataContainersCache>> _objectDataContainerCacheWeakRef = new ThreadLocal<WeakReference<DataContainersCache>>(){
        @Override
        protected WeakReference<DataContainersCache> initialValue()
        {
            return new WeakReference<DataContainersCache>(new DataContainersCache());
        }
    };
   
    private static ThreadLocal<OperationContextTicketCache> _threadLocalTicketCacheHolder = new ThreadLocal<OperationContextTicketCache>(){
        @Override
        protected OperationContextTicketCache initialValue()
        {
            return new OperationContextTicketCache();
        }
    };
   
    public static boolean compareToPersistentValues(JODBSession session, Field[] fields, int[] fieldsIDs, Object currentObject, IOTicket ioTicket, ObjectDataContainer headerData ) throws IOException{
        boolean[] processedFields = new boolean[fieldsIDs.length];
        IRandomAccessDataBuffer in = ioTicket.getRandomAccessBuffer();
        short classNameIDs = in.readShort();
        for (int i = 0; i < classNameIDs; i++) {
            in.readShort();
        }
       
        //null fields no longer persisted
//        if(headerData.hasNullFields()){
//            int nullFieldsTotal = in.readShort()&0xffff;
//            for (int i = 0; i < nullFieldsTotal; i++) {
//                int id = in.readShort()&0xffff;
//                int index = ArrayUtils.indexOf(fieldsIDs, id);
//                if(index == -1){
//                    continue;
//                }
//                Field field = fields[index];
//                try {
//                    if(field.get(currentObject)!=null){//TODO may need additional check if object is in transaction, rare case though
//                        return false;
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    throw new IOException(e.getMessage());
//                }
//                processedFields[index] = true;
//            }
//        }

        if(headerData.hasDirectlyAddressedFields()){
            boolean result = verifyLinks(session, false, fields, fieldsIDs, processedFields, currentObject, ioTicket);
            if(!result){
                return false;
            }
        }
       
        if(headerData.hasRelativelyAddressedFields()){
            boolean result = verifyLinks(session, true, fields, fieldsIDs, processedFields, currentObject, ioTicket);
            if(!result){
                return false;
            }
        }
       
        //long endOffset = headerData.getOffset() + headerData.getTotalLength();
       
        if (headerData.hasPrimitiveFields()) {
            int total = in.readShort()&0xFFFF;
            for (int i = 0; i < total; i++) {
                int id = in.readShort() & 0xffff;
                int index = ArrayUtils.indexOf(fieldsIDs, id);
                Field field = fields[index];
                if (index == -1) {
                    Utils.skipPrimitive(field, ioTicket.getRandomAccessBuffer());
                    continue;
                }
                if (!Utils.readPrimitiveAndCompare(currentObject, field,in)){
                    return false;
                }
                processedFields[index] = true;
            }
        }       
        for (int i = 0; i < fieldsIDs.length; i++) {//cheking if remaining not found fields have default values
            if(fieldsIDs[i]==-1||processedFields[i]){
                continue;
            }
            Field field = fields[i];
            if(field.getType().isPrimitive()){
                if(!Utils.primitiveEquals(field, currentObject, 0)){
                    return false;
                }
            }else{
                Object value;
                try {
                    value = field.get(currentObject);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new JodbIOException(e);
                }
                if(value!=null){
                    return false;
                }
            }
        }
           
        return true;
    }
   
    public static void writeEmptyObjectEntry(DataOutput dataOutput,long len) throws IOException{
        if(len<=0xff){
            dataOutput.writeShort(JODBIOBase.ENTRY_EMPTY_ID|JODBIOBase.LEN_MODIFIER_BYTE);
            dataOutput.write((int) len);
        }else if(len <= 0xffff){
            dataOutput.writeShort(JODBIOBase.ENTRY_EMPTY_ID);
            dataOutput.writeShort((int) len);
        }else{
            dataOutput.writeShort(JODBIOBase.ENTRY_EMPTY_ID|JODBIOBase.LEN_MODIFIER_LONG);
            dataOutput.writeLong(len);
        }
    }
   
    public static void writeRedirectionEntry(DataOutput dataOutput,long len, long offset, boolean skipLength) throws IOException{
        if(len<=0xff){
            dataOutput.write(JODBIOBase.ENTRY_REDIRECTOR_ID|JODBIOBase.LEN_MODIFIER_BYTE);
            dataOutput.write((int) len);
        }else if(len <= 0xffff){
            dataOutput.writeShort(JODBIOBase.ENTRY_REDIRECTOR_ID);
            dataOutput.writeShort((int) len);
        }else{
            dataOutput.writeShort(JODBIOBase.ENTRY_REDIRECTOR_ID|JODBIOBase.LEN_MODIFIER_LONG);
            dataOutput.writeLong(len);
        }
        dataOutput.writeLong(offset);
    }
   
    private static boolean verifyLinks(JODBSession session, boolean isRelativeAddr, Field[] fields, int[] fieldsIDs, boolean[] processedFields, Object currentObject, IOTicket ioTicket) throws IOException{
        IRandomAccessDataBuffer in = ioTicket.getRandomAccessBuffer();
        int directlyAddressedFieldsTotal = in.readShort()&0xffff;
        for (int i = 0; i < directlyAddressedFieldsTotal; i++) {
            int id = in.readShort()&0xffff;
            long offset;
            if(isRelativeAddr){
                offset = in.readInt()+ in.getCursorOffset();
            }else{
                offset = in.readLong();
            }
            int index = ArrayUtils.indexOf(fieldsIDs, id);
            if(index == -1){
                continue;
            }
            Field field = fields[index];
            try {
                Object value = field.get(currentObject);
                if(value == null){//this field can't be null
                    return false;
                }
                PersistentObjectHandle handle = session.getHandleForActiveObject(value);
                if(handle == null){//this field must contain known object
                    return false;
                }
                if(handle.getObjectEntryOffset() == offset){//same offset - object verified
                    processedFields[index] = true;
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new JodbIOException(e);
            }
        }
        return true;
    }

    public static Object launchObject(JODBSession session, long offset, Object activationInstance, int remainingDepth) throws IOException{
        if(remainingDepth < 0 || offset == 0){
            return null;
        }
        IOBase base = session.getBase();
        boolean delayedActivation = activationInstance != null;
        Object instance;
        if (!delayedActivation) {//this is user's requested activation call, instance already exist
            instance = session.getObjectFromCache(offset);
            if (instance != null) {
                return instance;
            }
        }else{
            instance = activationInstance;
        }
        OperationContextTicketCache contextTicketCache = _threadLocalTicketCacheHolder.get();
        IOTicket ioTicket = contextTicketCache.getTicketForRead(base);//base.getIOTicket(true, false);
        try{
            ioTicket.lock(false);
            DataContainersCache dataContainersCache = getObjectDataContainerCache();
            ObjectDataContainer objectDataContainer = dataContainersCache.pullObjectDataContainer();
            FieldsIterator fieldsIterator = objectDataContainer.readObject(ioTicket.getRandomAccessBuffer(),base, session, offset, true);
            ClassDescriptor classDescriptor = objectDataContainer.getClassDescriptorForPersistedObject();
            if (classDescriptor == null || fieldsIterator == null) {
                // basically same as >>objectDataContainer.isDeleted()<< or no class available for persistent copy
                return null;
            }
            IClassProcessor processor;
            if (!delayedActivation) {
                int classTypeId = objectDataContainer.getOriginalClassType();
                String className = base.getClassTypeForID(classTypeId);
                Class clazz;
                try {
                    clazz = session.resolveClassForName(className);
                } catch (ClassNotFoundException e) {
                    return null;
                }
                processor = JODBPluginRegistry.getInstance().getClassProcessor(clazz);
                instance = processor.composeInstance(clazz, objectDataContainer, session);
            }else{
                processor = JODBPluginRegistry.getInstance().getClassProcessor(instance.getClass());
            }
            PersistentObjectHandle handle = session.createHandleForObject(instance, offset, objectDataContainer);
            synchronized (handle) {//TODO "get object" must obey this lock or incompletely initialized object could become accessible
                if(!delayedActivation){
                    synchronized (session.getActivationSynchObject()) {//put object into cache to prevent potential recursion
                        //check if some other thread already instantiated the object
                        Object candidate = session.getObjectFromCache(offset);
                        if (candidate != null) {
                            dataContainersCache.pushObjectDataContainer(objectDataContainer);//return container to cache
                            return candidate;
                        }
                        session.putObject(instance, handle);
                    }
                }
   
                processor.activate(instance, objectDataContainer, session, remainingDepth, delayedActivation);
                dataContainersCache.pushObjectDataContainer(objectDataContainer);//return container to cache
                objectDataContainer = null;
            }
        }finally{
            ioTicket.unlock();
            contextTicketCache.putToCache(ioTicket);
        }
        return instance;
    }
   
   
   
    public void deactivate(ClassDescriptor classDescriptor, Object obj, int depth) throws IOException {
        deactivate0(classDescriptor, obj, depth, 0);
    }
   
    private void deactivate0(ClassDescriptor classDescriptor, Object obj, int depth, int level) throws IOException {
        //Vector<FieldRecord> records = getFieldsContainerForLevel(level);
        //TODO
    }
   
    public static DataContainersCache getObjectDataContainerCache(){
        WeakReference<DataContainersCache> reference = _objectDataContainerCacheWeakRef.get();
        DataContainersCache cache = reference.get();
        if(cache == null){
            cache = new DataContainersCache();
            _objectDataContainerCacheWeakRef.set(new WeakReference<DataContainersCache>(cache));
        }
        return cache;
    }
   
    public static OperationContextTicketCache getContextTicketCache(){
        return _threadLocalTicketCacheHolder.get();
    }
   

//    private static Vector<FieldRecord> getFieldsContainerForLevel(int level){
//        WeakReference<LaunchObjectsLevelsCache> launchObjectsLevelsCache = _launchObjectCache.get();
//        LaunchObjectsLevelsCache cache = launchObjectsLevelsCache.get();
//        if(cache == null){
//            cache = new LaunchObjectsLevelsCache();
//            launchObjectsLevelsCache = new WeakReference<LaunchObjectsLevelsCache>(cache);
//            _launchObjectCache.set(launchObjectsLevelsCache);
//        }
//        return cache.getFieldRecordCache(level);
//    }

    public static class OperationContextTicketCache{//this class safe for threadlocal context only
        private Vector<IOTicket> _ioTicketsCache;
       
        public void resetCache() {
            _ioTicketsCache = null;
        }
       
        public void setIoTicketsCache(Vector<IOTicket> ioTicketsCache) {
            _ioTicketsCache = ioTicketsCache;
        }
       
        IOTicket getTicketForRead(IOBase base) throws IOException{
            if(_ioTicketsCache!=null && _ioTicketsCache.size() > 0){
                int index = _ioTicketsCache.size()-1;
                IOTicket result = _ioTicketsCache.elementAt(index);
                if(result.getBase() != base){
                    if(JODBConfig.DEBUG){
                        throw new IOException("Illegal Cache Content");
                    }
                    _ioTicketsCache = null;// clean cache
                }else{
                    _ioTicketsCache.setSize(index);
                    return result;
                }
            }
            return base.getIOTicket(true, false);
        }
       
        void putToCache(IOTicket ticket) throws IOException{
            if(_ioTicketsCache!=null){
                _ioTicketsCache.add(ticket);
            }else{
                ticket.close();
            }
        }
    }
}
TOP

Related Classes of com.mobixess.jodb.core.transaction.TransactionUtils$DataContainersCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.