Package com.orientechnologies.orient.server.tx

Source Code of com.orientechnologies.orient.server.tx.OTransactionOptimisticProxy

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  *  you may not use this file except in compliance with the License.
  *  *  You may obtain a copy of the License at
  *  *
  *  *       http://www.apache.org/licenses/LICENSE-2.0
  *  *
  *  *  Unless required by applicable law or agreed to in writing, software
  *  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  *  See the License for the specific language governing permissions and
  *  *  limitations under the License.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.orient.server.tx;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.orientechnologies.orient.core.db.record.ODatabaseRecordTx;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.ORecordLazyList;
import com.orientechnologies.orient.core.db.record.ORecordOperation;
import com.orientechnologies.orient.core.db.record.ridbag.ORidBag;
import com.orientechnologies.orient.core.exception.ORecordNotFoundException;
import com.orientechnologies.orient.core.exception.OSerializationException;
import com.orientechnologies.orient.core.exception.OTransactionAbortedException;
import com.orientechnologies.orient.core.exception.OTransactionException;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.index.OCompositeKey;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.ORecordInternal;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.serialization.serializer.OStringSerializerHelper;
import com.orientechnologies.orient.core.serialization.serializer.record.string.ORecordSerializerSchemaAware2CSV;
import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializerAnyStreamable;
import com.orientechnologies.orient.core.tx.OTransactionIndexChanges;
import com.orientechnologies.orient.core.tx.OTransactionOptimistic;
import com.orientechnologies.orient.core.tx.OTransactionRealAbstract;
import com.orientechnologies.orient.core.version.ORecordVersion;
import com.orientechnologies.orient.core.version.OVersionFactory;
import com.orientechnologies.orient.enterprise.channel.binary.OChannelBinary;
import com.orientechnologies.orient.enterprise.channel.binary.OChannelBinaryProtocol;
import com.orientechnologies.orient.server.network.protocol.binary.ONetworkProtocolBinary;

public class OTransactionOptimisticProxy extends OTransactionOptimistic {
  private final Map<ORID, ORecordOperation> tempEntries    = new LinkedHashMap<ORID, ORecordOperation>();
  private final Map<ORecordId, ORecord>     createdRecords = new HashMap<ORecordId, ORecord>();
  private final Map<ORecordId, ORecord>     updatedRecords = new HashMap<ORecordId, ORecord>();
  @Deprecated
  private final int                         clientTxId;
  private final OChannelBinary              channel;
  private final short                       protocolVersion;
  private ONetworkProtocolBinary            oNetworkProtocolBinary;

  public OTransactionOptimisticProxy(final ODatabaseRecordTx iDatabase, final OChannelBinary iChannel, short protocolVersion,
      ONetworkProtocolBinary oNetworkProtocolBinary) throws IOException {
    super(iDatabase);
    channel = iChannel;
    clientTxId = iChannel.readInt();
    this.protocolVersion = protocolVersion;
    this.oNetworkProtocolBinary = oNetworkProtocolBinary;
  }

  @Override
  public void begin() {
    super.begin();

    try {
      setUsingLog(channel.readByte() == 1);

      byte lastTxStatus;
      for (lastTxStatus = channel.readByte(); lastTxStatus == 1; lastTxStatus = channel.readByte()) {
        final byte recordStatus = channel.readByte();

        final ORecordId rid = channel.readRID();

        final byte recordType = channel.readByte();
        final ORecordOperation entry = new OTransactionEntryProxy(recordType);
        entry.type = recordStatus;

        switch (recordStatus) {
        case ORecordOperation.CREATED:
          oNetworkProtocolBinary.fillRecord(rid, channel.readBytes(), OVersionFactory.instance().createVersion(),
              entry.getRecord(), database);

          // SAVE THE RECORD TO RETRIEVE THEM FOR THE NEW RID TO SEND BACK TO THE REQUESTER
          createdRecords.put(rid.copy(), entry.getRecord());
          break;

        case ORecordOperation.UPDATED:
          ORecordVersion version = channel.readVersion();
          byte[] bytes = channel.readBytes();
          oNetworkProtocolBinary.fillRecord(rid, bytes, version, entry.getRecord(), database);
          if (protocolVersion >= 23)
            ORecordInternal.setContentChanged(entry.getRecord(), channel.readBoolean());
          break;

        case ORecordOperation.DELETED:
          ORecordInternal.fill(entry.getRecord(), rid, channel.readVersion(), null, false);
          break;

        default:
          throw new OTransactionException("Unrecognized tx command: " + recordStatus);
        }

        // PUT IN TEMPORARY LIST TO GET FETCHED AFTER ALL FOR CACHE
        tempEntries.put(entry.getRecord().getIdentity(), entry);
      }

      if (lastTxStatus == -1)
        // ABORT TX
        throw new OTransactionAbortedException("Transaction aborted by the client");

      final ODocument remoteIndexEntries = new ODocument(channel.readBytes());
      fillIndexOperations(remoteIndexEntries);

      // FIRE THE TRIGGERS ONLY AFTER HAVING PARSED THE REQUEST
      for (Entry<ORID, ORecordOperation> entry : tempEntries.entrySet()) {

        if (entry.getValue().type == ORecordOperation.UPDATED) {
          // SPECIAL CASE FOR UPDATE: WE NEED TO LOAD THE RECORD AND APPLY CHANGES TO GET WORKING HOOKS (LIKE INDEXES)

          final ORecord record = entry.getValue().record.getRecord();
          final ORecord loadedRecord = record.getIdentity().copy().getRecord();
          if (loadedRecord == null)
            throw new ORecordNotFoundException(record.getIdentity().toString());

          if (ORecordInternal.getRecordType(loadedRecord) == ODocument.RECORD_TYPE
              && ORecordInternal.getRecordType(loadedRecord) == ORecordInternal.getRecordType(record)) {
            ((ODocument) loadedRecord).merge((ODocument) record, false, false);
            loadedRecord.getRecordVersion().copyFrom(record.getRecordVersion());
            entry.getValue().record = loadedRecord;

            // SAVE THE RECORD TO RETRIEVE THEM FOR THE NEW VERSIONS TO SEND BACK TO THE REQUESTER
            updatedRecords.put((ORecordId) entry.getKey(), entry.getValue().getRecord());

          }
        }

        addRecord(entry.getValue().getRecord(), entry.getValue().type, null);
      }
      tempEntries.clear();

      // UNMARSHALL ALL THE RECORD AT THE END TO BE SURE ALL THE RECORD ARE LOADED IN LOCAL TX
      for (ORecord record : createdRecords.values())
        unmarshallRecord(record);
      for (ORecord record : updatedRecords.values())
        unmarshallRecord(record);

    } catch (IOException e) {
      rollback();
      throw new OSerializationException("Cannot read transaction record from the network. Transaction aborted", e);
    }
  }

  @Override
  public ORecord getRecord(final ORID rid) {
    ORecord record = super.getRecord(rid);
    if (record == OTransactionRealAbstract.DELETED_RECORD)
      return record;
    else if (record == null && rid.isNew())
      // SEARCH BETWEEN CREATED RECORDS
      record = createdRecords.get(rid);

    return record;
  }

  private void fillIndexOperations(final ODocument remoteIndexEntries) {
    for (Entry<String, Object> indexEntry : remoteIndexEntries) {
      final String indexName = indexEntry.getKey();
      final ODocument indexDoc = (ODocument) indexEntry.getValue();
      if (indexDoc == null)
        continue;

      OTransactionIndexChanges transactionIndexChanges = indexEntries.get(indexEntry.getKey());

      if (transactionIndexChanges == null) {
        transactionIndexChanges = new OTransactionIndexChanges();
        indexEntries.put(indexEntry.getKey(), transactionIndexChanges);
      }

      final Boolean clearAll = indexDoc.field("clear");
      if (clearAll != null && clearAll)
        transactionIndexChanges.setCleared();

      final Collection<ODocument> entries = indexDoc.field("entries");
      if (entries == null)
        continue;

      for (final ODocument entry : entries) {
        final List<ODocument> operations = entry.field("ops");
        if (operations == null)
          continue;

        final Object key;
        try {
          ODocument keyContainer;
          if (protocolVersion <= OChannelBinaryProtocol.PROTOCOL_VERSION_24) {

            final String serializedKey = OStringSerializerHelper.decode((String) entry.field("k"));
            if (serializedKey.equals("*"))
              keyContainer = null;
            else {
              keyContainer = new ODocument();
              keyContainer.setLazyLoad(false);
              ORecordSerializerSchemaAware2CSV.INSTANCE.fromString(serializedKey, keyContainer, null);
            }
          } else {
            keyContainer = entry.field("k");
          }
          if (keyContainer != null) {
            final Object storedKey = keyContainer.field("key");
            if (storedKey instanceof List)
              key = new OCompositeKey((List<? extends Comparable<?>>) storedKey);
            else if (Boolean.TRUE.equals(keyContainer.field("binary"))) {
              key = OStreamSerializerAnyStreamable.INSTANCE.fromStream((byte[]) storedKey);
            } else
              key = storedKey;
          } else
            key = null;
        } catch (IOException ioe) {
          throw new OTransactionException("Error during index changes deserialization. ", ioe);
        }

        for (final ODocument op : operations) {
          final int operation = (Integer) op.rawField("o");
          final OTransactionIndexChanges.OPERATION indexOperation = OTransactionIndexChanges.OPERATION.values()[operation];
          final OIdentifiable value = op.field("v");

          transactionIndexChanges.getChangesPerKey(key).add(value, indexOperation);

          if (value == null)
            continue;

          final ORID rid = value.getIdentity();
          List<OTransactionRecordIndexOperation> txIndexOperations = recordIndexOperations.get(rid);
          if (txIndexOperations == null) {
            txIndexOperations = new ArrayList<OTransactionRecordIndexOperation>();
            recordIndexOperations.put(rid, txIndexOperations);
          }

          txIndexOperations.add(new OTransactionRecordIndexOperation(indexName, key, indexOperation));
        }
      }
    }
  }

  public Map<ORecordId, ORecord> getCreatedRecords() {
    return createdRecords;
  }

  public Map<ORecordId, ORecord> getUpdatedRecords() {
    return updatedRecords;
  }

  /**
   * Unmarshalls collections. This prevent temporary RIDs remains stored as are.
   */
  private void unmarshallRecord(final ORecord iRecord) {
    if (iRecord instanceof ODocument) {
      ((ODocument) iRecord).deserializeFields();

      for (Entry<String, Object> field : ((ODocument) iRecord)) {
        final Object value = field.getValue();
        if (value instanceof ORecordLazyList)
          ((ORecordLazyList) field.getValue()).lazyLoad(true);
        else if (value instanceof ORidBag)
          ((ORidBag) value).convertLinks2Records();
      }
    }
  }
}
TOP

Related Classes of com.orientechnologies.orient.server.tx.OTransactionOptimisticProxy

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.