Example #1
0
func mergedEnumerate(ctx *context.Context, dest chan<- blob.SizedRef, nsrc int, getSource func(int) BlobEnumerator, after string, limit int) error {
	defer close(dest)

	subctx := ctx.New()
	defer subctx.Cancel()

	startEnum := func(source BlobEnumerator) (*blob.ChanPeeker, <-chan error) {
		ch := make(chan blob.SizedRef, buffered)
		errch := make(chan error, 1)
		go func() {
			errch <- source.EnumerateBlobs(subctx, ch, after, limit)
		}()
		return &blob.ChanPeeker{Ch: ch}, errch
	}

	peekers := make([]*blob.ChanPeeker, 0, nsrc)
	errs := make([]<-chan error, 0, nsrc)
	for i := 0; i < nsrc; i++ {
		peeker, errch := startEnum(getSource(i))
		peekers = append(peekers, peeker)
		errs = append(errs, errch)
	}

	nSent := 0
	var lastSent blob.Ref
	tooLow := func(br blob.Ref) bool { return lastSent.Valid() && (br == lastSent || br.Less(lastSent)) }
	for nSent < limit {
		lowestIdx := -1
		var lowest blob.SizedRef
		for idx, peeker := range peekers {
			for !peeker.Closed() && tooLow(peeker.MustPeek().Ref) {
				peeker.Take()
			}
			if peeker.Closed() {
				continue
			}
			sb := peeker.MustPeek() // can't be nil if not Closed
			if lowestIdx == -1 || sb.Ref.Less(lowest.Ref) {
				lowestIdx = idx
				lowest = sb
			}
		}
		if lowestIdx == -1 {
			// all closed
			break
		}

		dest <- lowest
		nSent++
		lastSent = lowest.Ref
	}

	// If any part returns an error, we return an error.
	var retErr error
	for _, errch := range errs {
		if err := <-errch; err != nil {
			retErr = err
		}
	}
	return retErr
}
Example #2
0
// Collect performs a garbage collection.
func (c *Collector) Collect(ctx *context.Context) (err error) {
	if c.World == nil {
		return errors.New("no World")
	}
	if c.Marker == nil {
		return errors.New("no Marker")
	}
	if c.Roots == nil {
		return errors.New("no Roots")
	}
	if c.Sweeper == nil {
		return errors.New("no Sweeper")
	}
	if c.ItemEnumerator == nil {
		return errors.New("no ItemEnumerator")
	}
	if c.Deleter == nil {
		return errors.New("no Deleter")
	}
	if err := c.World.Stop(); err != nil {
		return err
	}
	defer func() {
		startErr := c.World.Start()
		if err == nil {
			err = startErr
		}
	}()

	// Mark.
	roots := make(chan Item, buffered)
	markCtx := ctx.New()
	var marker syncutil.Group
	marker.Go(func() error {
		defer markCtx.Cancel()
		for it := range roots {
			if err := c.markItem(markCtx, it, true); err != nil {
				return err
			}
		}
		return nil
	})
	marker.Go(func() error {
		return c.Roots.Enumerate(markCtx, roots)
	})
	if err := marker.Err(); err != nil {
		return fmt.Errorf("Mark failure: %v", err)
	}

	// Sweep.
	all := make(chan Item, buffered)
	sweepCtx := ctx.New()
	var sweeper syncutil.Group
	sweeper.Go(func() error {
		return c.Sweeper.Enumerate(sweepCtx, all)
	})
	sweeper.Go(func() error {
		defer sweepCtx.Done()
		for it := range all {
			ok, err := c.Marker.IsMarked(it)
			if err != nil {
				return err
			}
			if !ok {
				if err := c.Deleter.Delete(it); err != nil {
					return err
				}
			}
		}
		return nil
	})
	if err := sweeper.Err(); err != nil {
		return fmt.Errorf("Sweep failure: %v", err)
	}
	return nil
}