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