Example #1
0
  /**
   * Update the record.
   *
   * @param iForceCreate
   * @param iCallback
   */
  public void saveRecord(
      final ORecordInternal<?> iRecord,
      final String iClusterName,
      final OPERATION_MODE iMode,
      boolean iForceCreate,
      final ORecordCallback<? extends Number> iCallback) {
    try {
      database.executeSaveRecord(
          iRecord,
          iClusterName,
          iRecord.getVersion(),
          iRecord.getRecordType(),
          true,
          iMode,
          iForceCreate,
          iCallback);
    } catch (Exception e) {
      // REMOVE IT FROM THE CACHE TO AVOID DIRTY RECORDS
      final ORecordId rid = (ORecordId) iRecord.getIdentity();
      if (rid.isValid()) database.getLevel1Cache().freeRecord(rid);

      if (e instanceof RuntimeException) throw (RuntimeException) e;
      throw new OException(e);
    }
  }
Example #2
0
  /** Deletes the record. */
  public void deleteRecord(final ORecordInternal<?> iRecord, final OPERATION_MODE iMode) {
    if (!iRecord.getIdentity().isPersistent()) return;

    try {
      database.executeDeleteRecord(iRecord, iRecord.getVersion(), true, true, iMode);
    } catch (Exception e) {
      // REMOVE IT FROM THE CACHE TO AVOID DIRTY RECORDS
      final ORecordId rid = (ORecordId) iRecord.getIdentity();
      if (rid.isValid()) database.getLevel1Cache().freeRecord(rid);

      if (e instanceof RuntimeException) throw (RuntimeException) e;
      throw new OException(e);
    }
  }
Example #3
0
  public long createRecord(
      final ORecordId iRid,
      final byte[] iContent,
      final byte iRecordType,
      final ORecordCallback<Long> iCallback) {
    checkConnection();

    do {
      try {
        final OChannelBinaryClient network =
            beginRequest(OChannelBinaryProtocol.REQUEST_RECORD_CREATE);
        try {
          network.writeShort((short) iRid.clusterId);
          network.writeBytes(iContent);
          network.writeByte(iRecordType);

        } finally {
          endRequest(network);
        }

        if (iCallback == null)
          try {
            beginResponse(network);
            iRid.clusterPosition = network.readLong();
            return iRid.clusterPosition;
          } finally {
            endResponse(network);
          }
        else {
          Callable<Object> response =
              new Callable<Object>() {
                public Object call() throws Exception {
                  final Long result;

                  beginResponse(network);
                  try {
                    result = network.readLong();
                  } finally {
                    endResponse(network);
                  }
                  iCallback.call(result);
                  return null;
                }
              };
          asynchExecutor.submit(new FutureTask<Object>(response));
        }

      } catch (OException e) {
        // PASS THROUGH
        throw e;
      } catch (Exception e) {
        handleException("Error on create record in cluster: " + iRid.clusterId, e);
      }
    } while (true);
  }
    public Map<OIdentifiable, Change> deserializeChanges(final byte[] stream, int offset) {
      final int count = OIntegerSerializer.INSTANCE.deserializeLiteral(stream, offset);
      offset += OIntegerSerializer.INT_SIZE;

      final HashMap<OIdentifiable, Change> res = new HashMap<OIdentifiable, Change>();
      for (int i = 0; i < count; i++) {
        ORecordId rid = OLinkSerializer.INSTANCE.deserialize(stream, offset);
        offset += OLinkSerializer.RID_SIZE;
        Change change = ChangeSerializationHelper.INSTANCE.deserializeChange(stream, offset);
        offset += Change.SIZE;

        final OIdentifiable identifiable;
        if (rid.isTemporary() && rid.getRecord() != null) identifiable = rid.getRecord();
        else identifiable = rid;

        res.put(identifiable, change);
      }

      return res;
    }
Example #5
0
File: DB.java Project: o-nix/Kafra
  @SuppressWarnings("unchecked")
  protected Object unwrap(Object node) {
    Object result = node;

    if (node instanceof Map) {
      Map<String, Object> cast = (Map<String, Object>) node;

      ORecordId id;

      if (cast.containsKey("id")) {
        id = new ORecordId((String) cast.get("id"));
        cast.remove("id");
      } else id = new ORecordId();

      ODocument real;

      if (id.isNew()) {
        if (cast.containsKey("class")) {
          real = new ODocument((String) cast.get("class"));

          cast.remove("class");
        } else
          throw new RuntimeException(
              "Unknown class in newly created ODocument. Please provide 'class' property in every new object.");
      } else real = new ODocument(id);

      for (String key : cast.keySet()) real.field(key, unwrap(cast.get(key)));

      result = real;
    } else if (node instanceof List) {
      List<Object> cast = (List<Object>) node;

      for (int i = 0; i < cast.size(); i++) cast.set(i, unwrap(cast.get(i)));
    }

    return result;
  }
  public void executeDeleteRecord(final OIdentifiable iRecord, final int iVersion) {
    checkOpeness();
    final ORecordId rid = (ORecordId) iRecord.getIdentity();

    if (rid == null)
      throw new ODatabaseException(
          "Cannot delete record because it has no identity. Probably was created from scratch or contains projections of fields rather than a full record");

    if (!rid.isValid()) return;

    checkSecurity(
        ODatabaseSecurityResources.CLUSTER,
        ORole.PERMISSION_DELETE,
        getClusterNameById(rid.clusterId));

    setCurrentDatabaseinThreadLocal();

    try {
      callbackHooks(TYPE.BEFORE_DELETE, iRecord);

      underlying.delete(rid, iVersion);

      callbackHooks(TYPE.AFTER_DELETE, iRecord);

      // REMOVE THE RECORD FROM 1 AND 2 LEVEL CACHES
      getLevel1Cache().deleteRecord(rid);

    } catch (OException e) {
      // RE-THROW THE EXCEPTION
      throw e;

    } catch (Throwable t) {
      // WRAP IT AS ODATABASE EXCEPTION
      throw new ODatabaseException(
          "Error on deleting record in cluster #" + iRecord.getIdentity().getClusterId(), t);
    }
  }
  @Override
  public IRelation convertToEntity(ODocument document) {
    Relation relation = new Relation();

    // load relation link
    ODocument relationLink = getRelationLink(document, true);
    if (relationLink == null) return null; // exact error was logged below

    // get from/to - slim entities, just title and id
    relation.setFromEntity(getRelatedEntity(relationLink, "out"));
    relation.setToEntity(getRelatedEntity(relationLink, "in"));

    // set relation type
    ORecordId relationType = document.field("relationType", ORecordId.class);
    if (relationType != null) {
      RelationTypeRepository relationTypeRepository =
          repositoryFactory.produceRepository(OrientDbRelationTypeRepository.class);
      if (relationTypeRepository != null)
        relation.setRelationType(
            relationTypeRepository.find(relationType.getIdentity().toString()));
      else logger.error("Could not produce RelationTypeRepository while converting relation.");
    }

    // rest is easy
    relation.setDescription(document.field("description", String.class));
    relation.setDescriptionMarkup(document.field("descriptionMarkup", String.class));

    // populate with data
    populateEntityWithBaseData(document, relation);
    populateEntityWithCreatedModified(document, relation);
    populateEntityWithColored(document, relation);
    populateEntityWithAnnotated(document, relation);
    populateEntityWithCore(document, relation);

    return relation;
  }
  public static void fieldTypeToString(
      final StringBuilder iBuffer, OType iType, final Object iValue) {
    if (iValue == null) return;

    final long timer = PROFILER.startChrono();

    if (iType == null) {
      if (iValue instanceof ORID) iType = OType.LINK;
      else iType = OType.EMBEDDED;
    }

    switch (iType) {
      case STRING:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.string2string"),
            "Serialize string to string",
            timer);
        break;

      case BOOLEAN:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.bool2string"),
            "Serialize boolean to string",
            timer);
        break;

      case INTEGER:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.int2string"),
            "Serialize integer to string",
            timer);
        break;

      case FLOAT:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.float2string"),
            "Serialize float to string",
            timer);
        break;

      case DECIMAL:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.decimal2string"),
            "Serialize decimal to string",
            timer);
        break;

      case LONG:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.long2string"),
            "Serialize long to string",
            timer);
        break;

      case DOUBLE:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.double2string"),
            "Serialize double to string",
            timer);
        break;

      case SHORT:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.short2string"),
            "Serialize short to string",
            timer);
        break;

      case BYTE:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.byte2string"),
            "Serialize byte to string",
            timer);
        break;

      case BINARY:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.binary2string"),
            "Serialize binary to string",
            timer);
        break;

      case DATE:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.date2string"),
            "Serialize date to string",
            timer);
        break;

      case DATETIME:
        simpleValueToStream(iBuffer, iType, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.datetime2string"),
            "Serialize datetime to string",
            timer);
        break;

      case LINK:
        if (iValue instanceof ORecordId) ((ORecordId) iValue).toString(iBuffer);
        else ((ORecord<?>) iValue).getIdentity().toString(iBuffer);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.link2string"),
            "Serialize link to string",
            timer);
        break;

      case EMBEDDEDSET:
        ORecordSerializerSchemaAware2CSV.INSTANCE.embeddedCollectionToStream(
            ODatabaseRecordThreadLocal.INSTANCE.getIfDefined(),
            null,
            iBuffer,
            null,
            null,
            iValue,
            null,
            true);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.embedSet2string"),
            "Serialize embeddedset to string",
            timer);
        break;

      case EMBEDDEDLIST:
        ORecordSerializerSchemaAware2CSV.INSTANCE.embeddedCollectionToStream(
            ODatabaseRecordThreadLocal.INSTANCE.getIfDefined(),
            null,
            iBuffer,
            null,
            null,
            iValue,
            null,
            true);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.embedList2string"),
            "Serialize embeddedlist to string",
            timer);
        break;

      case EMBEDDEDMAP:
        ORecordSerializerSchemaAware2CSV.INSTANCE.embeddedMapToStream(
            ODatabaseRecordThreadLocal.INSTANCE.getIfDefined(),
            null,
            iBuffer,
            null,
            null,
            iValue,
            null,
            true);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.embedMap2string"),
            "Serialize embeddedmap to string",
            timer);
        break;

      case EMBEDDED:
        OStringSerializerEmbedded.INSTANCE.toStream(iBuffer, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.embed2string"),
            "Serialize embedded to string",
            timer);
        break;

      case CUSTOM:
        OStringSerializerAnyStreamable.INSTANCE.toStream(iBuffer, iValue);
        PROFILER.stopChrono(
            PROFILER.getProcessMetric("serializer.record.string.custom2string"),
            "Serialize custom to string",
            timer);
        break;

      default:
        throw new IllegalArgumentException(
            "Type " + iType + " not supported to convert value: " + iValue);
    }
  }
  private void addRecord(
      final ORecordInternal<?> iRecord, final byte iStatus, final String iClusterName) {
    checkTransaction();

    if ((status == OTransaction.TXSTATUS.COMMITTING)
        && database.getStorage() instanceof OStorageEmbedded) {
      // I'M COMMITTING OR IT'S AN INDEX: BYPASS LOCAL BUFFER
      switch (iStatus) {
        case OTransactionRecordEntry.CREATED:
        case OTransactionRecordEntry.UPDATED:
          database.executeSaveRecord(
              iRecord, iClusterName, iRecord.getVersion(), iRecord.getRecordType());
          break;
        case OTransactionRecordEntry.DELETED:
          database.executeDeleteRecord(iRecord, iRecord.getVersion());
          break;
      }
    } else {
      final ORecordId rid = (ORecordId) iRecord.getIdentity();

      if (!rid.isValid()) {
        // // TODO: NEED IT FOR REAL?
        // // NEW RECORD: CHECK IF IT'S ALREADY IN
        // for (OTransactionRecordEntry entry : recordEntries.values()) {
        // if (entry.getRecord() == iRecord)
        // return;
        // }

        iRecord.onBeforeIdentityChanged(rid);

        // ASSIGN A UNIQUE SERIAL TEMPORARY ID
        if (rid.clusterId == ORID.CLUSTER_ID_INVALID)
          rid.clusterId =
              iClusterName != null
                  ? database.getClusterIdByName(iClusterName)
                  : database.getDefaultClusterId();
        rid.clusterPosition = newObjectCounter--;

        iRecord.onAfterIdentityChanged(iRecord);
      } else
        // REMOVE FROM THE DB'S CACHE
        database.getLevel1Cache().freeRecord(rid);

      OTransactionRecordEntry txEntry = getRecordEntry(rid);

      if (txEntry == null) {
        // NEW ENTRY: JUST REGISTER IT
        txEntry = new OTransactionRecordEntry(iRecord, iStatus, iClusterName);

        recordEntries.put(rid, txEntry);
      } else {
        // UPDATE PREVIOUS STATUS
        txEntry.setRecord(iRecord);

        switch (txEntry.status) {
          case OTransactionRecordEntry.LOADED:
            switch (iStatus) {
              case OTransactionRecordEntry.UPDATED:
                txEntry.status = OTransactionRecordEntry.UPDATED;
                break;
              case OTransactionRecordEntry.DELETED:
                txEntry.status = OTransactionRecordEntry.DELETED;
                break;
            }
            break;
          case OTransactionRecordEntry.UPDATED:
            switch (iStatus) {
              case OTransactionRecordEntry.DELETED:
                txEntry.status = OTransactionRecordEntry.DELETED;
                break;
            }
            break;
          case OTransactionRecordEntry.DELETED:
            break;
          case OTransactionRecordEntry.CREATED:
            switch (iStatus) {
              case OTransactionRecordEntry.DELETED:
                recordEntries.remove(rid);
                break;
            }
            break;
        }
      }
    }
  }
Example #10
0
public class ORecordId implements ORID {
  private static final long serialVersionUID = 247070594054408657L;

  public static final ORecordId EMPTY_RECORD_ID = new ORecordId();
  public static final byte[] EMPTY_RECORD_ID_STREAM = EMPTY_RECORD_ID.toStream();

  public int clusterId = CLUSTER_ID_INVALID; // INT TO AVOID
  // JVM
  // PENALITY, BUT
  // IT'S STORED
  // AS SHORT
  public OClusterPosition clusterPosition = OClusterPosition.INVALID_POSITION;
  public static final int PERSISTENT_SIZE =
      OBinaryProtocol.SIZE_SHORT + OClusterPositionFactory.INSTANCE.getSerializedSize();

  public ORecordId() {}

  public ORecordId(final int iClusterId, final OClusterPosition iPosition) {
    clusterId = iClusterId;
    checkClusterLimits();
    clusterPosition = iPosition;
  }

  public ORecordId(final int iClusterIdId) {
    clusterId = iClusterIdId;
    checkClusterLimits();
  }

  public ORecordId(final String iRecordId) {
    fromString(iRecordId);
  }

  /**
   * Copy constructor.
   *
   * @param parentRid Source object
   */
  public ORecordId(final ORID parentRid) {
    clusterId = parentRid.getClusterId();
    clusterPosition = parentRid.getClusterPosition();
  }

  public void reset() {
    clusterId = CLUSTER_ID_INVALID;
    clusterPosition = CLUSTER_POS_INVALID;
  }

  public boolean isValid() {
    return clusterPosition.isValid();
  }

  public boolean isPersistent() {
    return clusterId > -1 && clusterPosition.isPersistent();
  }

  public boolean isNew() {
    return clusterPosition.isNew();
  }

  public boolean isTemporary() {
    return clusterId != -1 && clusterPosition.isTemporary();
  }

  @Override
  public String toString() {
    return generateString(clusterId, clusterPosition);
  }

  public StringBuilder toString(StringBuilder iBuffer) {
    if (iBuffer == null) iBuffer = new StringBuilder();

    iBuffer.append(PREFIX);
    iBuffer.append(clusterId);
    iBuffer.append(SEPARATOR);
    iBuffer.append(clusterPosition);
    return iBuffer;
  }

  public static String generateString(final int iClusterId, final OClusterPosition iPosition) {
    final StringBuilder buffer = new StringBuilder(12);
    buffer.append(PREFIX);
    buffer.append(iClusterId);
    buffer.append(SEPARATOR);
    buffer.append(iPosition);
    return buffer.toString();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj == null) return false;
    if (!(obj instanceof OIdentifiable)) return false;
    final ORecordId other = (ORecordId) ((OIdentifiable) obj).getIdentity();

    if (clusterId != other.clusterId) return false;
    if (!clusterPosition.equals(other.clusterPosition)) return false;
    return true;
  }

  @Override
  public int hashCode() {
    int result = clusterId;
    result = 31 * result + clusterPosition.hashCode();
    return result;
  }

  public int compareTo(final OIdentifiable iOther) {
    if (iOther == this) return 0;

    if (iOther == null) return 1;

    final int otherClusterId = iOther.getIdentity().getClusterId();
    if (clusterId == otherClusterId) {
      final OClusterPosition otherClusterPos = iOther.getIdentity().getClusterPosition();

      return clusterPosition.compareTo(otherClusterPos);
    } else if (clusterId > otherClusterId) return 1;

    return -1;
  }

  public int compare(final OIdentifiable iObj1, final OIdentifiable iObj2) {
    if (iObj1 == iObj2) return 0;

    if (iObj1 != null) return iObj1.compareTo(iObj2);

    return -1;
  }

  public ORecordId copy() {
    return new ORecordId(clusterId, clusterPosition);
  }

  private void checkClusterLimits() {
    if (clusterId < -2)
      throw new ODatabaseException(
          "RecordId cannot support negative cluster id. You've used: " + clusterId);

    if (clusterId > CLUSTER_MAX)
      throw new ODatabaseException(
          "RecordId cannot support cluster id major than 32767. You've used: " + clusterId);
  }

  public ORecordId fromStream(final InputStream iStream) throws IOException {
    clusterId = OBinaryProtocol.bytes2short(iStream);

    clusterPosition = OClusterPositionFactory.INSTANCE.fromStream(iStream);
    return this;
  }

  public ORecordId fromStream(final OMemoryStream iStream) {
    clusterId = iStream.getAsShort();
    clusterPosition =
        OClusterPositionFactory.INSTANCE.fromStream(
            iStream.getAsByteArrayFixed(OClusterPositionFactory.INSTANCE.getSerializedSize()));
    return this;
  }

  public ORecordId fromStream(final byte[] iBuffer) {
    if (iBuffer != null) {
      clusterId = OBinaryProtocol.bytes2short(iBuffer, 0);

      clusterPosition =
          OClusterPositionFactory.INSTANCE.fromStream(iBuffer, OBinaryProtocol.SIZE_SHORT);
    }
    return this;
  }

  public int toStream(final OutputStream iStream) throws IOException {
    final int beginOffset = OBinaryProtocol.short2bytes((short) clusterId, iStream);
    iStream.write(clusterPosition.toStream());
    return beginOffset;
  }

  public int toStream(final OMemoryStream iStream) throws IOException {
    final int beginOffset = OBinaryProtocol.short2bytes((short) clusterId, iStream);
    iStream.write(clusterPosition.toStream());
    return beginOffset;
  }

  public byte[] toStream() {
    final int serializedSize = OClusterPositionFactory.INSTANCE.getSerializedSize();

    byte[] buffer = new byte[OBinaryProtocol.SIZE_SHORT + serializedSize];

    OBinaryProtocol.short2bytes((short) clusterId, buffer, 0);
    System.arraycopy(
        clusterPosition.toStream(), 0, buffer, OBinaryProtocol.SIZE_SHORT, serializedSize);

    return buffer;
  }

  public int getClusterId() {
    return clusterId;
  }

  public OClusterPosition getClusterPosition() {
    return clusterPosition;
  }

  public void fromString(String iRecordId) {
    if (iRecordId != null) iRecordId = iRecordId.trim();

    if (iRecordId == null || iRecordId.isEmpty()) {
      clusterId = CLUSTER_ID_INVALID;
      clusterPosition = CLUSTER_POS_INVALID;
      return;
    }

    if (!OStringSerializerHelper.contains(iRecordId, SEPARATOR))
      throw new IllegalArgumentException(
          "Argument '"
              + iRecordId
              + "' is not a RecordId in form of string. Format must be: <cluster-id>:<cluster-position>");

    final List<String> parts = OStringSerializerHelper.split(iRecordId, SEPARATOR, PREFIX);

    if (parts.size() != 2)
      throw new IllegalArgumentException(
          "Argument received '"
              + iRecordId
              + "' is not a RecordId in form of string. Format must be: #<cluster-id>:<cluster-position>. Example: #3:12");

    clusterId = Integer.parseInt(parts.get(0));
    checkClusterLimits();
    clusterPosition = OClusterPositionFactory.INSTANCE.valueOf(parts.get(1));
  }

  public void copyFrom(final ORID iSource) {
    if (iSource == null) throw new IllegalArgumentException("Source is null");

    clusterId = iSource.getClusterId();
    clusterPosition = iSource.getClusterPosition();
  }

  public String next() {
    return generateString(clusterId, clusterPosition.inc());
  }

  @Override
  public ORID nextRid() {
    return new ORecordId(clusterId, clusterPosition.inc());
  }

  public ORID getIdentity() {
    return this;
  }

  @SuppressWarnings("unchecked")
  public <T extends ORecord<?>> T getRecord() {
    if (!isValid()) return null;

    final ODatabaseRecord db = ODatabaseRecordThreadLocal.INSTANCE.get();
    if (db == null)
      throw new ODatabaseException(
          "No database found in current thread local space. If you manually control databases over threads assure to set the current database before to use it by calling: ODatabaseRecordThreadLocal.INSTANCE.set(db);");

    return (T) db.load(this);
  }
}
  public void executeSaveRecord(
      final ORecordInternal<?> iRecord,
      String iClusterName,
      final int iVersion,
      final byte iRecordType) {
    checkOpeness();

    if (!iRecord.isDirty()) return;

    final ORecordId rid = (ORecordId) iRecord.getIdentity();

    if (rid == null)
      throw new ODatabaseException(
          "Cannot create record because it has no identity. Probably is not a regular record or contains projections of fields rather than a full record");

    setCurrentDatabaseinThreadLocal();

    try {
      final boolean wasNew = rid.isNew();

      // STREAM.LENGTH == 0 -> RECORD IN STACK: WILL BE SAVED AFTER
      byte[] stream = iRecord.toStream();

      final boolean isNew = rid.isNew();
      if (isNew)
        // NOTIFY IDENTITY HAS CHANGED
        iRecord.onBeforeIdentityChanged(rid);
      else if (stream.length == 0)
        // ALREADY CREATED AND WAITING FOR THE RIGHT UPDATE (WE'RE IN A GRAPH)
        return;

      if (isNew && rid.clusterId < 0)
        rid.clusterId =
            iClusterName != null ? getClusterIdByName(iClusterName) : getDefaultClusterId();

      if (rid.clusterId > -1 && iClusterName == null)
        iClusterName = getClusterNameById(rid.clusterId);

      if (stream != null && stream.length > 0) {
        if (wasNew) {
          // CHECK ACCESS ON CLUSTER
          checkSecurity(ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_CREATE, iClusterName);
          if (callbackHooks(TYPE.BEFORE_CREATE, iRecord))
            // RECORD CHANGED IN TRIGGER, REACQUIRE IT
            stream = iRecord.toStream();
        } else {
          // CHECK ACCESS ON CLUSTER
          checkSecurity(ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_UPDATE, iClusterName);
          if (callbackHooks(TYPE.BEFORE_UPDATE, iRecord))
            // RECORD CHANGED IN TRIGGER, REACQUIRE IT
            stream = iRecord.toStream();
        }

        if (!iRecord.isDirty()) {
          // RECORD SAVED DURING PREVIOUS STREAMING PHASE: THIS HAPPENS FOR CIRCULAR REFERENCED
          // RECORDS
          // ADD/UPDATE IT IN CACHE IF IT'S ACTIVE
          getLevel1Cache().updateRecord(iRecord);
          return;
        }
      }

      // GET THE LATEST VERSION. IT COULD CHANGE BECAUSE THE RECORD COULD BE BEEN LINKED FROM OTHERS
      final int realVersion = iVersion == -1 || !mvcc ? -1 : iRecord.getVersion();

      // SAVE IT
      final long result = underlying.save(rid, stream, realVersion, iRecord.getRecordType());

      if (isNew) {
        // UPDATE INFORMATION: CLUSTER ID+POSITION
        ((ORecordId) iRecord.getIdentity()).copyFrom(rid);
        // NOTIFY IDENTITY HAS CHANGED
        iRecord.onAfterIdentityChanged(iRecord);
        // UPDATE INFORMATION: CLUSTER ID+POSITION
        iRecord.fill(rid, 0, stream, stream == null || stream.length == 0);
      } else {
        // UPDATE INFORMATION: VERSION
        iRecord.fill(rid, (int) result, stream, stream == null || stream.length == 0);
      }

      callbackHooks(wasNew ? TYPE.AFTER_CREATE : TYPE.AFTER_UPDATE, iRecord);

      if (stream != null && stream.length > 0)
        // ADD/UPDATE IT IN CACHE IF IT'S ACTIVE
        getLevel1Cache().updateRecord(iRecord);

    } catch (OException e) {
      // RE-THROW THE EXCEPTION
      throw e;

    } catch (Throwable t) {
      // WRAP IT AS ODATABASE EXCEPTION
      throw new ODatabaseException(
          "Error on saving record in cluster #" + iRecord.getIdentity().getClusterId(), t);
    }
  }
  public <RET extends ORecordInternal<?>> RET executeReadRecord(
      final ORecordId iRid,
      ORecordInternal<?> iRecord,
      final String iFetchPlan,
      final boolean iIgnoreCache) {
    checkOpeness();

    // setCurrentDatabaseinThreadLocal();

    try {
      checkSecurity(
          ODatabaseSecurityResources.CLUSTER,
          ORole.PERMISSION_READ,
          getClusterNameById(iRid.getClusterId()));

      // SEARCH IN LOCAL TX
      ORecordInternal<?> record = getTransaction().getRecord(iRid);
      if (record == null && !iIgnoreCache)
        // SEARCH INTO THE CACHE
        record = getLevel1Cache().findRecord(iRid);

      if (record != null) {
        OFetchHelper.checkFetchPlanValid(iFetchPlan);
        callbackHooks(TYPE.BEFORE_READ, record);

        if (record.getInternalStatus() == ORecordElement.STATUS.NOT_LOADED) record.reload();

        callbackHooks(TYPE.AFTER_READ, record);
        return (RET) record;
      }

      final ORawBuffer recordBuffer = underlying.read(iRid, iFetchPlan);
      if (recordBuffer == null) return null;

      if (iRecord == null || iRecord.getRecordType() != recordBuffer.recordType)
        // NO SAME RECORD TYPE: CAN'T REUSE OLD ONE BUT CREATE A NEW ONE FOR IT
        iRecord = Orient.instance().getRecordFactoryManager().newInstance(recordBuffer.recordType);

      iRecord.fill(iRid, recordBuffer.version, recordBuffer.buffer, false);

      callbackHooks(TYPE.BEFORE_READ, iRecord);

      iRecord.fromStream(recordBuffer.buffer);
      iRecord.setInternalStatus(ORecordElement.STATUS.LOADED);

      callbackHooks(TYPE.AFTER_READ, iRecord);

      if (!iIgnoreCache) getLevel1Cache().updateRecord(iRecord);

      return (RET) iRecord;
    } catch (OException e) {
      // RE-THROW THE EXCEPTION
      throw e;

    } catch (Exception e) {
      // WRAP IT AS ODATABASE EXCEPTION
      OLogManager.instance()
          .exception("Error on retrieving record " + iRid, e, ODatabaseException.class);
    }
    return null;
  }
  protected void addRecord(
      final ORecordInternal<?> iRecord, final byte iStatus, final String iClusterName) {
    checkTransaction();

    switch (iStatus) {
      case ORecordOperation.CREATED:
        database.checkSecurity(
            ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_CREATE, iClusterName);
        database.callbackHooks(TYPE.BEFORE_CREATE, iRecord);
        break;
      case ORecordOperation.LOADED:
        /**
         * Read hooks already invoked in {@link
         * com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract#executeReadRecord} .
         */
        break;
      case ORecordOperation.UPDATED:
        database.checkSecurity(
            ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_UPDATE, iClusterName);
        database.callbackHooks(TYPE.BEFORE_UPDATE, iRecord);
        break;
      case ORecordOperation.DELETED:
        database.checkSecurity(
            ODatabaseSecurityResources.CLUSTER, ORole.PERMISSION_DELETE, iClusterName);
        database.callbackHooks(TYPE.BEFORE_DELETE, iRecord);
        break;
    }

    try {
      if (iRecord.getIdentity().isTemporary())
        temp2persistent.put(iRecord.getIdentity().copy(), iRecord);

      if ((status == OTransaction.TXSTATUS.COMMITTING)
          && database.getStorage() instanceof OStorageEmbedded) {

        // I'M COMMITTING: BYPASS LOCAL BUFFER
        switch (iStatus) {
          case ORecordOperation.CREATED:
          case ORecordOperation.UPDATED:
            final ORID oldRid = iRecord.getIdentity().copy();
            database.executeSaveRecord(
                iRecord,
                iClusterName,
                iRecord.getRecordVersion(),
                iRecord.getRecordType(),
                false,
                OPERATION_MODE.SYNCHRONOUS,
                false,
                null,
                null);
            updateIdentityAfterCommit(oldRid, iRecord.getIdentity());
            break;
          case ORecordOperation.DELETED:
            database.executeDeleteRecord(
                iRecord,
                iRecord.getRecordVersion(),
                false,
                false,
                OPERATION_MODE.SYNCHRONOUS,
                false);
            break;
        }

        final ORecordOperation txRecord = getRecordEntry(iRecord.getIdentity());

        if (txRecord == null) {
          // NOT IN TX, SAVE IT ANYWAY
          allEntries.put(iRecord.getIdentity(), new ORecordOperation(iRecord, iStatus));
        } else if (txRecord.record != iRecord) {
          // UPDATE LOCAL RECORDS TO AVOID MISMATCH OF VERSION/CONTENT
          final String clusterName =
              getDatabase().getClusterNameById(iRecord.getIdentity().getClusterId());
          if (!clusterName.equals(OMetadataDefault.CLUSTER_MANUAL_INDEX_NAME)
              && !clusterName.equals(OMetadataDefault.CLUSTER_INDEX_NAME))
            OLogManager.instance()
                .warn(
                    this,
                    "Found record in transaction with the same RID %s but different instance. Probably the record has been loaded from another transaction and reused on the current one: reload it from current transaction before to update or delete it",
                    iRecord.getIdentity());

          txRecord.record = iRecord;
          txRecord.type = iStatus;
        }

      } else {
        final ORecordId rid = (ORecordId) iRecord.getIdentity();

        if (!rid.isValid()) {
          iRecord.onBeforeIdentityChanged(rid);

          // ASSIGN A UNIQUE SERIAL TEMPORARY ID
          if (rid.clusterId == ORID.CLUSTER_ID_INVALID)
            rid.clusterId =
                iClusterName != null
                    ? database.getClusterIdByName(iClusterName)
                    : database.getDefaultClusterId();
          rid.clusterPosition = OClusterPositionFactory.INSTANCE.valueOf(newObjectCounter--);

          iRecord.onAfterIdentityChanged(iRecord);
        } else
          // REMOVE FROM THE DB'S CACHE
          database.getLevel1Cache().freeRecord(rid);

        ORecordOperation txEntry = getRecordEntry(rid);

        if (txEntry == null) {
          if (!(rid.isTemporary() && iStatus != ORecordOperation.CREATED)) {
            // NEW ENTRY: JUST REGISTER IT
            txEntry = new ORecordOperation(iRecord, iStatus);
            recordEntries.put(rid, txEntry);
          }
        } else {
          // UPDATE PREVIOUS STATUS
          txEntry.record = iRecord;

          switch (txEntry.type) {
            case ORecordOperation.LOADED:
              switch (iStatus) {
                case ORecordOperation.UPDATED:
                  txEntry.type = ORecordOperation.UPDATED;
                  break;
                case ORecordOperation.DELETED:
                  txEntry.type = ORecordOperation.DELETED;
                  break;
              }
              break;
            case ORecordOperation.UPDATED:
              switch (iStatus) {
                case ORecordOperation.DELETED:
                  txEntry.type = ORecordOperation.DELETED;
                  break;
              }
              break;
            case ORecordOperation.DELETED:
              break;
            case ORecordOperation.CREATED:
              switch (iStatus) {
                case ORecordOperation.DELETED:
                  recordEntries.remove(rid);
                  break;
              }
              break;
          }
        }
      }

      switch (iStatus) {
        case ORecordOperation.CREATED:
          database.callbackHooks(TYPE.AFTER_CREATE, iRecord);
          break;
        case ORecordOperation.LOADED:
          /**
           * Read hooks already invoked in {@link
           * com.orientechnologies.orient.core.db.record.ODatabaseRecordAbstract#executeReadRecord}.
           */
          break;
        case ORecordOperation.UPDATED:
          database.callbackHooks(TYPE.AFTER_UPDATE, iRecord);
          break;
        case ORecordOperation.DELETED:
          database.callbackHooks(TYPE.AFTER_DELETE, iRecord);
          break;
      }
    } catch (Throwable t) {
      switch (iStatus) {
        case ORecordOperation.CREATED:
          database.callbackHooks(TYPE.CREATE_FAILED, iRecord);
          break;
        case ORecordOperation.UPDATED:
          database.callbackHooks(TYPE.UPDATE_FAILED, iRecord);
          break;
        case ORecordOperation.DELETED:
          database.callbackHooks(TYPE.DELETE_FAILED, iRecord);
          break;
      }

      if (t instanceof RuntimeException) throw (RuntimeException) t;
      else throw new ODatabaseException("Error on saving record " + iRecord.getIdentity(), t);
    }
  }