/** @see LN#writeToLog */ public void writeToLog(ByteBuffer logBuffer) { /* * Add the tracked (live) summary to the base summary before writing it * to the log, and reset the tracked summary. Do this even when * deleting the LN, so that the tracked summary is cleared. */ if (trackedSummary != null) { baseSummary.add(trackedSummary); if (!isDeleted()) { getOffsets(); } /* Reset the totals to zero and clear the tracked offsets. */ trackedSummary.reset(); } super.writeToLog(logBuffer); if (!isDeleted()) { baseSummary.writeToLog(logBuffer); obsoleteOffsets.writeToLog(logBuffer); } }
/** If tracked offsets may be present, get them so they are ready to be written to the log. */ private void getOffsets() { if (needOffsets) { long[] offsets = trackedSummary.getObsoleteOffsets(); if (offsets != null) { int oldSize = obsoleteOffsets.getExtraMemorySize(); obsoleteOffsets.pack(offsets); int newSize = obsoleteOffsets.getExtraMemorySize(); memBudget.updateTreeMemoryUsage(newSize - oldSize); } needOffsets = false; } }
/** * This reader looks at all nodes for the max node id and database id. It only returns * non-provisional INs and IN delete entries. */ protected boolean processEntry(ByteBuffer entryBuffer) throws DatabaseException { boolean useEntry = false; boolean entryLoaded = false; /* If this is a targetted entry, read the entire log entry. */ if (targetLogEntry != null) { targetLogEntry.readEntry(entryBuffer, currentEntrySize, currentEntryTypeVersion, true); DatabaseId dbId = getDatabaseId(); boolean isMapDb = dbId.equals(DbTree.ID_DB_ID); useEntry = (!mapDbOnly || isMapDb); entryLoaded = true; } /* Do a partial load during tracking if necessary. */ if (trackIds) { /* * Do partial load of db and txn id tracking entries if necessary. * Note that these entries do not overlap with targetLogEntry. * * XXX We're doing a full load for now, since LNLogEntry does not * read the db and txn id in a partial load, only the node id. */ LNLogEntry lnEntry = null; if (dbIdTrackingEntry != null) { /* This entry has a db id */ lnEntry = dbIdTrackingEntry; lnEntry.readEntry( entryBuffer, currentEntrySize, currentEntryTypeVersion, true /* full load */); entryLoaded = true; MapLN mapLN = (MapLN) lnEntry.getMainItem(); int dbId = mapLN.getDatabase().getId().getId(); if (dbId > maxDbId) { maxDbId = dbId; } } if (txnIdTrackingEntry != null) { /* This entry has a txn id */ if (lnEntry == null) { lnEntry = txnIdTrackingEntry; lnEntry.readEntry( entryBuffer, currentEntrySize, currentEntryTypeVersion, true /* full load */); entryLoaded = true; } long txnId = lnEntry.getTxnId().longValue(); if (txnId > maxTxnId) { maxTxnId = txnId; } } /* * Perform utilization counting under trackIds to prevent * double-counting. */ if (fsTrackingEntry != null) { /* Must do full load to get key from file summary LN. */ if (!entryLoaded) { nodeTrackingEntry.readEntry( entryBuffer, currentEntrySize, currentEntryTypeVersion, true /* full load */); entryLoaded = true; } /* * When a FileSummaryLN is encountered, reset the tracked * summary for that file to replay what happens when a * FileSummaryLN log entry is written. */ byte[] keyBytes = fsTrackingEntry.getKey(); FileSummaryLN fsln = (FileSummaryLN) fsTrackingEntry.getMainItem(); long fileNum = fsln.getFileNumber(keyBytes); TrackedFileSummary trackedLN = tracker.getTrackedFile(fileNum); if (trackedLN != null) { trackedLN.reset(); } /* Save the LSN of the FileSummaryLN for use by undo/redo. */ fileSummaryLsns.put(new Long(fileNum), new Long(getLastLsn())); /* * SR 10395: Do not cache the file summary in the * UtilizationProfile here, since it may be for a deleted log * file. */ } /* * Do partial load of nodeTrackingEntry (and inTrackingEntry) if not * already loaded. We only need the node id. */ if (nodeTrackingEntry != null) { if (!entryLoaded) { nodeTrackingEntry.readEntry( entryBuffer, currentEntrySize, currentEntryTypeVersion, false /* partial load */); entryLoaded = true; } /* Keep track of the largest node id seen. */ long nodeId = nodeTrackingEntry.getNodeId(); maxNodeId = (nodeId > maxNodeId) ? nodeId : maxNodeId; } if (inTrackingEntry != null) { assert entryLoaded : "All nodes should have been loaded"; /* * Count the obsolete LSN of the previous version, if available * and if not already counted. Use inexact counting for two * reasons: 1) we don't always have the full LSN because earlier * log versions only had the file number, and 2) we can't * guarantee obsoleteness for provisional INs. */ long oldLsn = inTrackingEntry.getObsoleteLsn(); if (oldLsn != DbLsn.NULL_LSN) { long newLsn = getLastLsn(); if (!isObsoleteLsnAlreadyCounted(oldLsn, newLsn)) { tracker.countObsoleteNodeInexact(oldLsn, fromLogType); } } /* * Count a provisional IN as obsolete if it follows * partialCkptStart. It cannot have been already counted, * because provisional INs are not normally counted as obsolete; * they are only considered obsolete when they are part of a * partial checkpoint. * * Depending on the exact point at which the checkpoint was * aborted, this technique is not always accurate; therefore * inexact counting must be used. */ if (isProvisional && partialCkptStart != DbLsn.NULL_LSN) { oldLsn = getLastLsn(); if (DbLsn.compareTo(partialCkptStart, oldLsn) < 0) { tracker.countObsoleteNodeInexact(oldLsn, fromLogType); } } } } /* Return true if this entry should be processed */ return useEntry; }