Exemplo n.º 1
0
  /**
   * Find the container and then create the page in that container.
   *
   * <p>This is the process of creating a new page in a container, in that case no need to read the
   * page from disk - just need to initialize it in the cache.
   *
   * <p>
   *
   * @return new page, higher levels have already checked the page number is valid for an open.
   * @param key Which page is this?
   * @param createParameter details needed to create page like size, format id, ...
   * @exception StandardException Standard exception policy.
   * @see Cacheable#createIdentity
   */
  public Cacheable createIdentity(Object key, Object createParameter) throws StandardException {

    if (SanityManager.DEBUG) {
      SanityManager.ASSERT(key instanceof PageKey);
    }

    initialize();

    PageKey newIdentity = (PageKey) key;

    PageCreationArgs createArgs = (PageCreationArgs) createParameter;
    int formatId = createArgs.formatId;

    if (formatId == -1) {
      throw StandardException.newException(
          SQLState.DATA_UNKNOWN_PAGE_FORMAT_2,
          newIdentity,
          org.apache.derby.iapi.util.StringUtil.hexDump(pageData));
    }

    // createArgs[0] contains the integer form of the formatId
    // if it is not the same as this instance's formatId, instantiate the
    // real page object
    if (formatId != getTypeFormatId()) {
      return (changeInstanceTo(formatId, newIdentity).createIdentity(key, createParameter));
    }

    // this is the correct page instance
    initializeHeaders(5);
    createPage(newIdentity, createArgs);

    fillInIdentity(newIdentity);

    initialRowCount = 0;

    /*
     * if we need to grow the container and the page has not been
     * preallocated, writing page before the log is written so that we
     * know if there is an IO error - like running out of disk space - then
     * we don't write out the log record, because if we do, it may fail
     * after the log goes to disk and then the database may not be
     * recoverable.
     *
     * WRITE_SYNC is used when we create the page without first
     *	preallocating it
     * WRITE_NO_SYNC is used when we are preallocating the page - there
     *	will be a SYNC call after all the pages are preallocated
     * 0 means creating a page that has already been preallocated.
     */
    int syncFlag = createArgs.syncFlag;
    if ((syncFlag & WRITE_SYNC) != 0 || (syncFlag & WRITE_NO_SYNC) != 0)
      writePage(newIdentity, (syncFlag & WRITE_SYNC) != 0);

    if (SanityManager.DEBUG) {
      if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE)) {
        String sync =
            ((syncFlag & WRITE_SYNC) != 0)
                ? "Write_Sync"
                : (((syncFlag & WRITE_NO_SYNC) != 0) ? "Write_NO_Sync" : "No_write");

        SanityManager.DEBUG(
            FileContainer.SPACE_TRACE, "creating new page " + newIdentity + " with " + sync);
      }
    }

    return this;
  }
  /**
   * Write a format id for the object provied followed by the object itself to this
   * FormatIdOutputStream.
   *
   * @param ref a reference to the object.
   * @exception java.io.IOException the exception.
   */
  public void writeObject(Object ref) throws IOException {
    if (ref == null) {
      FormatIdUtil.writeFormatIdInteger(this, StoredFormatIds.NULL_FORMAT_ID);
      return;
    }

    if (ref instanceof String) {
      // String's are special cased to use writeUTF which is more
      // efficient than the default writeObject(String), but the format
      // can only store 65535 bytes.  The worst case size conversion is
      // 3 bytes for each unicode character in a String, so limiting
      // writeUTF optimization to strings smaller than 20000 should
      // insure that we won't call writeUTF() and produce more than
      // 65535 bytes.

      String str = (String) ref;

      if (str.length() <= 20000) {
        FormatIdUtil.writeFormatIdInteger(this, StoredFormatIds.STRING_FORMAT_ID);

        this.writeUTF((String) ref);
        return;
      }
    }

    // Add debugging code to read-in every formatable that we write
    // to ensure that it can be read and it's correctly registered.
    OutputStream oldOut = null;
    if (SanityManager.DEBUG) {

      if (ref instanceof Formatable) {

        oldOut = this.out;

        this.out = new DebugByteTeeOutputStream(oldOut);
      }
    }

    if (ref instanceof Storable) {
      Storable s = (Storable) ref;

      int fmtId = s.getTypeFormatId();

      if (fmtId != StoredFormatIds.SERIALIZABLE_FORMAT_ID) {
        FormatIdUtil.writeFormatIdInteger(this, fmtId);
        boolean isNull = s.isNull();
        writeBoolean(isNull);
        if (!isNull) {
          s.writeExternal(this);
        }
        if (SanityManager.DEBUG) {
          ((DebugByteTeeOutputStream) this.out).checkObject(s);
          this.out = oldOut;
        }
        return;
      }
    } else if (ref instanceof Formatable) {
      Formatable f = (Formatable) ref;
      int fmtId = f.getTypeFormatId();

      if (fmtId != StoredFormatIds.SERIALIZABLE_FORMAT_ID) {
        FormatIdUtil.writeFormatIdInteger(this, fmtId);
        f.writeExternal(this);

        if (SanityManager.DEBUG) {
          ((DebugByteTeeOutputStream) this.out).checkObject(f);
          this.out = oldOut;
        }
        return;
      }
    }

    /*
     ** Otherwise we assume (ref instanceof Serializable).
     ** If it isn't we'll get an error, which is what
     ** we would expect if someone uses something that
     ** doesn't support Serializable/Externalizable/Formattable
     ** when it should.
     */
    {

      /*
       ** If we are debugging (SerializeTrace), we are
       ** going to print out every unexpected serialized
       ** class.  We print them out to stdout to help
       ** in debugging (so they cause diffs in test runs).
       ** This is only active in a SANE server.
       */
      if (SanityManager.DEBUG) {
        if (SanityManager.DEBUG_ON("SerializedTrace")) {
          String name = ref.getClass().getName();
          if (!name.startsWith("java.lang") && !name.startsWith("java.math")) {
            SanityManager.DEBUG("SerializedTrace", "...writing serialized class: " + name);
            System.out.println("...writing serialized class: " + name);
          }
        }
      }

      FormatIdUtil.writeFormatIdInteger(this, StoredFormatIds.SERIALIZABLE_FORMAT_ID);
      ObjectOutputStream oos = new ObjectOutputStream(this);
      oos.writeObject(ref);
      oos.flush();

      if (SanityManager.DEBUG && ref instanceof Formatable) {
        ((DebugByteTeeOutputStream) this.out).checkObject((Formatable) ref);
        this.out = oldOut;
      }
    }
  }