bytesMoved
← YggNav
.SetUninterpretedContents[trans: trans, did: did, firstByte:
0, byteCount:
1024, from:
addr];
YggNavImpl.SetUninterpretedContents first obtains a volatile form of the document (a VDoc (REF YggRep.VDocRep)) from YggRep.VolatizeFromDID, and then modifies it via YggRep.BytesToBits. These two parts of the operation are described separately below.
YggVolatilizeImpl.VolatizeFromDID calls YggTransContextImpl.EstablishTransactionContext with a callback of YggVolatilizeImpl.VolatizeFromDID.innerVolatizeFromDID. innerVolatizeFromDID calls YggOpenDocImpl.Register to find the OpenDoc and hence YggDIDMap entries for the file. If the did is not already in use for the transaction, then YggDIDMapImpl.Register is called to find the YggInternal.Document for the did. If needed, a new YggDIDMapPrivate.DocumentRep is built with NIL values for the componentFiles list.
YggVolatilizeImpl.VolatizeFromDID.innerVolatizeFromDID calls YggLockCoreImpl.Set to claim the document for this transaction. The did is then looked up in the cache YggVolatilizeImpl keeps. If it is found, then it is returned. Else, the files that comprise the document are obtained by calling YggDIDImpl.StreamsForDID. These streams are parsed to build a document.
YggBitsImpl.BytesToBits
AlpFileImpl.WritePages is called. As usual, this is just translated into an RPC call to the server at PageActionsImpl.WritePages.
First, WritePages does the EstablishOpenFileContext and arranges to call back to (you guessed it) "Work". If things look ok, then we call FileLockImpl.AcquirePageLocks for the run we are about to write. This will upgrade the implicit intendRead (from the file being locked in intend read) to update or write locks for these pages. We then mess around with the CommittedSize and CommittedHighWaterMark, and if necessary set them in LogMapImpl (does not write to the log).
PerformAnyCommittedIntentions is called by Work. This looks at the run to be written, and insures that any write actions on those pages by committed transactions are performed now (Why is this done? Isn't this a bad performance bug? This forces the "about to be dirtied" pages to disk. These writes are useless, if the pages are logged. Maybe the system can't handle it, but it looks like a design bug.) The LogMap entry is then removed (LogMapImpl.UnregisterPages). Part of this is that we check out all the pages.
We are now actually going to write the data somewhere. If the writes are past the highWaterMark and we locked the file in whole file update, we just write them to the base (the real file). Otherwise, we "write" them to the log by calling FileLogImpl.LogWritePages (who eventually calls LogBasicTailImpl.PutEntry who glues the entry on the log to be written) and LogMapImpl.RegisterPages (to remember the pages were written?). In my test case, we are before highWaterMark, so we just log the changes.
[] ← trans.Finish[requestedOutcome: commit, continue:
FALSE];
All we have to do now is to commit the transaction, and all will be well.
AlpTransactionImpl.Finish does a RPC call that ends up at CoordinatorImpl.Finish in the server. FinishEntry is called. It starts the coordinator finish sequence. Ignoring special cases, we just do the two-phase commit protocol. First we force the log (LogImpl.Force), and go into the collecting state. We do RPC calls to other workers, and try to reach agreement. If we succeed, we return.
One might ask when the pages that were logged actually get written. FilePageMgrIOImpl.Idler and FilePageMgrMainImpl.Sweeper scan the page cache and do the writes. Also, PageActionsImpl.PerformAnyCommittedIntentions