// 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) handleEvent(msg datastore.SyncMessage) { switch delta := msg.Delta.(type) { case labels.DeltaMergeStart: // Add this merge into the cached blockRLEs iv := dvid.InstanceVersion{d.DataUUID(), msg.Version} d.StartUpdate() labels.MergeStart(iv, delta.MergeOp) d.StopUpdate() case labels.DeltaMerge: d.processMerge(msg.Version, delta) case labels.DeltaSplit: d.processSplit(msg.Version, delta) case deltaBlock: // received downres processing from upstream // NOTE: need to add wait here since there will be delay through channel compared to commit event. if d.MutAdd(delta.mutID) { d.StartUpdate() } n := delta.block.Hash(numBlockHandlers) d.procCh[n] <- procMsg{op: delta, v: msg.Version} case imageblk.Block: if d.MutAdd(delta.MutID) { d.StartUpdate() } n := delta.Index.Hash(numBlockHandlers) block := delta.Index.ToIZYXString() d.procCh[n] <- procMsg{op: deltaBlock{delta.MutID, block, delta.Data}, v: msg.Version} case imageblk.MutatedBlock: if d.MutAdd(delta.MutID) { d.StartUpdate() } n := delta.Index.Hash(numBlockHandlers) block := delta.Index.ToIZYXString() d.procCh[n] <- procMsg{op: deltaBlock{delta.MutID, block, delta.Data}, v: msg.Version} case labels.DeleteBlock: if d.MutAdd(delta.MutID) { d.StartUpdate() } n := delta.Index.Hash(numBlockHandlers) block := delta.Index.ToIZYXString() d.procCh[n] <- procMsg{op: deltaBlock{delta.MutID, block, nil}, v: msg.Version} default: dvid.Criticalf("Received unknown delta in labelblk.processEvents(): %v\n", msg) } }