in sumdb/client.go [397:461]
func (c *Client) mergeLatestMem(msg []byte) (when int, err error) {
if len(msg) == 0 {
// Accept empty msg as the unsigned, empty timeline.
c.latestMu.Lock()
latest := c.latest
c.latestMu.Unlock()
if latest.N == 0 {
return msgNow, nil
}
return msgPast, nil
}
note, err := note.Open(msg, c.verifiers)
if err != nil {
return 0, fmt.Errorf("reading tree note: %v\nnote:\n%s", err, msg)
}
tree, err := tlog.ParseTree([]byte(note.Text))
if err != nil {
return 0, fmt.Errorf("reading tree: %v\ntree:\n%s", err, note.Text)
}
// Other lookups may be calling mergeLatest with other heads,
// so c.latest is changing underfoot. We don't want to hold the
// c.mu lock during tile fetches, so loop trying to update c.latest.
c.latestMu.Lock()
latest := c.latest
latestMsg := c.latestMsg
c.latestMu.Unlock()
for {
// If the tree head looks old, check that it is on our timeline.
if tree.N <= latest.N {
if err := c.checkTrees(tree, msg, latest, latestMsg); err != nil {
return 0, err
}
if tree.N < latest.N {
return msgPast, nil
}
return msgNow, nil
}
// The tree head looks new. Check that we are on its timeline and try to move our timeline forward.
if err := c.checkTrees(latest, latestMsg, tree, msg); err != nil {
return 0, err
}
// Install our msg if possible.
// Otherwise we will go around again.
c.latestMu.Lock()
installed := false
if c.latest == latest {
installed = true
c.latest = tree
c.latestMsg = msg
} else {
latest = c.latest
latestMsg = c.latestMsg
}
c.latestMu.Unlock()
if installed {
return msgFuture, nil
}
}
}