Example #1
0
// 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
}
Example #2
0
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)
	}
}