// MergeLabels handles merging of any number of labels throughout the various label data // structures. It assumes that the merges aren't cascading, e.g., there is no attempt // to merge label 3 into 4 and also 4 into 5. The caller should have flattened the merges. // TODO: Provide some indication that subset of labels are under evolution, returning // an "unavailable" status or 203 for non-authoritative response. This might not be // feasible for clustered DVID front-ends due to coordination issues. // // EVENTS // // labels.MergeStartEvent occurs at very start of merge and transmits labels.DeltaMergeStart struct. // // labels.MergeBlockEvent occurs for every block of a merged label and transmits labels.DeltaMerge struct. // // labels.MergeEndEvent occurs at end of merge and transmits labels.DeltaMergeEnd struct. // func (d *Data) MergeLabels(v dvid.VersionID, m labels.MergeOp) error { dvid.Infof("Merging data %q (labels %s) into label %d ...\n", d.DataName(), m.Merged, m.Target) // Mark these labels as dirty until done, and make sure we can actually initiate the merge. if err := labels.MergeStart(d.getMergeIV(v), m); err != nil { return err } d.StartUpdate() // Signal that we are starting a merge. evt := datastore.SyncEvent{d.DataUUID(), labels.MergeStartEvent} msg := datastore.SyncMessage{labels.MergeStartEvent, v, labels.DeltaMergeStart{m}} if err := datastore.NotifySubscribers(evt, msg); err != nil { d.StopUpdate() return err } // Asynchronously perform merge and handle any concurrent requests using the cache map until // labelvol and labelblk are updated and consistent. go func() { d.asyncMergeLabels(v, m) // Remove dirty labels and updating flag when done. labels.MergeStop(d.getMergeIV(v), m) d.StopUpdate() dvid.Infof("Finished with merge of labels %s.\n", m) }() return nil }
func (d *Data) processMerge(v dvid.VersionID, delta labels.DeltaMerge) { mutID := d.NewMutationID() for izyxStr := range delta.Blocks { n := izyxStr.Hash(numBlockHandlers) d.MutAdd(mutID) op := mergeOp{mutID: mutID, MergeOp: delta.MergeOp, block: izyxStr} d.procCh[n] <- procMsg{op: op, v: v} } // When we've processed all the delta blocks, we can remove this merge op // from the merge cache since all labels will have completed. iv := dvid.InstanceVersion{d.DataUUID(), v} go func() { d.MutWait(mutID) d.MutDelete(mutID) labels.MergeStop(iv, delta.MergeOp) d.publishDownresCommit(v, mutID) }() }