/** * 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; } } }