예제 #1
0
    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;
    }
  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);
    }
  }