Exemplo n.º 1
0
 /**
  * <p>
  * Decodes the content of the supplied <code>ValueState</code> as an array
  * of Objects. Usually this array has one element containing the single
  * Object value encoded in the <code>ValueState</code>.  However, if multiple
  * items were written to the original <code>Value</code> from which the
  * <code>ValueState</code> was derived in
  * <a href="com.persistit.Value.html#_streamMode">Stream Mode</a>, this
  * method returns all of the encoded objects.
  * </p>
  * <p>
  * If the <code>valueState</code> represents an undefined value, this method
  * returns an array of length zero.  If the <code>valueState</code> encodes
  * a value of <code>null</code>, then this method returns an array containing
  * one element which is <code>null</code>.
  * </p>
  *
  * @param valueState    Representation of an encoded {@link Value).
  *
  * @param context       Object passed to any {@link ValueCoder} used in
  *                      decoding the value. May be <code>null</code>
  *
  * @return              Array of zero or more Objects encoded
  *                      in the <code>ValueState</code>
  * @throws RemoteException
  */
 @Override
 public Object[] decodeValueObjects(final ValueState valueState, final CoderContext context)
     throws RemoteException {
   try {
     final Value value = new Value(_persistit);
     valueState.copyTo(value);
     value.setStreamMode(true);
     final Vector vector = new Vector();
     while (value.hasMoreItems()) {
       vector.addElement(value.get(null, context));
     }
     final Object[] result = new Object[vector.size()];
     for (int index = 0; index < result.length; index++) {
       result[index] = vector.get(index);
     }
     return result;
   } catch (final Exception e) {
     throw new WrappedRemoteException(e);
   }
 }
Exemplo n.º 2
0
  /**
   * Look up and return the ClassInfo for an integer handle. This is used when decoding an <code>
   * Object</code> from a <code>com.persistit.Value</code> to associate the encoded integer handle
   * value with the corresponding class.
   *
   * @param handle The handle
   * @return The associated ClassInfo, or <i>null</i> if there is none.
   */
  public ClassInfo lookupByHandle(final int handle) {
    final AtomicReferenceArray<ClassInfoEntry> hashTable = _hashTable;
    ClassInfoEntry cie = hashTable.get(handle % hashTable.length());
    while (cie != null) {
      if (cie._classInfo.getHandle() == handle) return cie._classInfo;
      cie = cie._next;
    }

    _cacheMisses.incrementAndGet();

    synchronized (this) {
      _sessionId.assign();
      Exchange ex = null;
      try {
        ex = getExchange();
        final Transaction txn = ex.getTransaction();
        txn.begin();
        try {
          ex.clear().append(BY_HANDLE).append(handle).fetch();
          txn.commit();
        } catch (final Exception e) {
          _persistit.getLogBase().exception.log(e);
          throw new ConversionException(e);
        } finally {
          txn.end();
        }
        final Value value = ex.getValue();
        if (value.isDefined()) {
          value.setStreamMode(true);
          final int storedId = value.getInt();
          final String storedName = value.getString();
          final long storedSuid = value.getLong();
          if (storedId != handle) {
            throw new IllegalStateException(
                "ClassInfo stored for handle=" + handle + " has invalid stored handle=" + storedId);
          }
          final Class<?> cl =
              Class.forName(storedName, false, Thread.currentThread().getContextClassLoader());

          long suid = 0;
          final ObjectStreamClass osc = ObjectStreamClass.lookupAny(cl);
          if (osc != null) suid = osc.getSerialVersionUID();
          if (storedSuid != suid) {
            throw new ConversionException(
                "Class "
                    + cl.getName()
                    + " persistent SUID="
                    + storedSuid
                    + " does not match current class SUID="
                    + suid);
          }
          final ClassInfo ci = new ClassInfo(cl, suid, handle, osc);
          hashClassInfo(ci);
          return ci;
        } else {
          final ClassInfo ci = new ClassInfo(null, 0, handle, null);
          hashClassInfo(ci);
          return ci;
        }
      } catch (final ClassNotFoundException cnfe) {
        throw new ConversionException(cnfe);
      } catch (final PersistitException pe) {
        throw new ConversionException(pe);
      } finally {
        if (ex != null) releaseExchange(ex);
      }
    }
  }
Exemplo n.º 3
0
  /**
   * Look up and return the ClassInfo for a class. This is used when encoding an <code>Object</code>
   * into a <code>com.persistit.Value</code>.
   *
   * @param clazz The <code>Class</code>
   * @return The ClassInfo for the specified Class.
   */
  public ClassInfo lookupByClass(final Class<?> clazz) {
    final AtomicReferenceArray<ClassInfoEntry> hashTable = _hashTable;

    ObjectStreamClass osc = null;
    long suid = 0;

    final int nh = clazz.getName().hashCode() & 0x7FFFFFFF;
    ClassInfoEntry cie = hashTable.get(nh % hashTable.length());

    while (cie != null) {
      if (clazz.equals(cie._classInfo.getDescribedClass())) {
        return cie._classInfo;
      }
      if (cie._classInfo.getDescribedClass() != null
          && cie._classInfo.getName().equals(clazz.getName())) {
        if (osc == null) {
          osc = ObjectStreamClass.lookupAny(clazz);
          if (osc != null) {
            suid = osc.getSerialVersionUID();
          }
        }
        if (suid == cie._classInfo.getSUID()) {
          return cie._classInfo;
        }
      }
      cie = cie._next;
    }

    if (osc == null) {
      osc = ObjectStreamClass.lookupAny(clazz);
    }
    if (osc != null) {
      suid = osc.getSerialVersionUID();
    }

    _cacheMisses.incrementAndGet();

    /**
     * To update the tree, this class uses a unique SessionId and results in using a unique
     * Transaction context unrelated to the application context. Therefore if an application does
     * this:
     *
     * <pre>
     * <code>
     * txn.begin();
     * value.put(new SomeClass());
     * txn.rollback();
     * txn.end();
     * </code>
     * </pre>
     *
     * the class SomeClass will be registered even though the enclosing transaction rolled back.
     * This is important because other concurrent threads may have started using the handle for
     * SomeClass. Therefore this class ensures that a non-nested transaction to insert the new
     * ClassInfo into the system volume has committed before adding the handle to the hash table.
     */
    synchronized (this) {
      final SessionId saveSessionId = _persistit.getSessionId();
      Exchange ex = null;
      try {
        _persistit.setSessionId(_sessionId);
        ex = getExchange();
        final Transaction txn = ex.getTransaction();
        final ClassInfo ci;
        final int handle;
        txn.begin();
        ex.clear().append(BY_NAME).append(clazz.getName()).append(suid).fetch();
        final Value value = ex.getValue();
        try {
          if (value.isDefined()) {
            value.setStreamMode(true);

            handle = value.getInt();
            final String storedName = value.getString();
            final long storedSuid = value.getLong();

            if (storedSuid != suid || !clazz.getName().equals(storedName)) {
              throw new ConversionException(
                  "Class "
                      + clazz.getName()
                      + " persistent SUID="
                      + storedSuid
                      + " does not match current class SUID="
                      + suid);
            }
            ci = new ClassInfo(clazz, suid, handle, osc);
          } else {
            //
            // Store a new ClassInfo record
            //
            ex.clear().append(NEXT_ID).fetch();
            handle = Math.max(_testIdFloor, value.isDefined() ? value.getInt() : HANDLE_BASE) + 1;
            value.clear().put(handle);
            ex.store();

            value.clear();
            value.setStreamMode(true);
            value.put(handle);
            value.put(clazz.getName());
            value.put(suid);

            ex.clear().append(BY_NAME).append(clazz.getName()).append(suid).store();

            ex.clear().append(BY_HANDLE).append(handle).store();

            ci = new ClassInfo(clazz, suid, handle, osc);
          }
          txn.commit();
          hashClassInfo(ci);
          return ci;
        } finally {
          txn.end();
        }
      } catch (final PersistitException pe) {
        throw new ConversionException(pe);
      } finally {
        if (ex != null) {
          releaseExchange(ex);
        }
        _persistit.setSessionId(saveSessionId);
      }
    }
  }