You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: snapshoter.go
    path of file: ./repos/flyte/flyteadmin/scheduler/snapshoter
    
    the code of the file until where you have to start completion: package snapshoter

import (
	"bytes"
	"context"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/grpc/codes"

	"github.com/flyteorg/flyte/flyteadmin/pkg/errors"
	repositoryInterfaces "github.com/flyteorg/flyte/flyteadmin/scheduler/repositories/interfaces"
	"github.com/flyteorg/flyte/flyteadmin/scheduler/repositories/models"
	"github.com/flyteorg/flyte/flytestdlib/logger"
	"github.com/flyteorg/flyte/flytestdlib/promutils"
)

type Metrics struct {
	Scope                      promutils.Scope
	SnapshotSaveErrCounter     prometheus.Counter
	SnapshotCreationErrCounter prometheus.Counter
}

type snapshoter stru
    
func (w *snapshoter) Read(ctx context.Context, reader Reader) (Snapshot, error) {
	scheduleEntitiesSnapShot, err := w.db.ScheduleEntitiesSnapshotRepo().Read(ctx)
	var snapshot Snapshot
	snapshot = &SnapshotV1{LastTimes: map[string]*time.Time{}}
	// Just log the error but dont interrupt the startup of the scheduler
	if err != nil {
		if err.(errors.FlyteAdminError).Code() == codes.NotFound {
			// This is not an error condition and hence can be ignored.
			return snapshot, nil
		}
		logger.Errorf(ctx, "unable to read the snapshot from the DB due to %v", err)
		return nil, err
	}
	f := bytes.NewReader(scheduleEntitiesSnapShot.Snapshot)
	snapshot, err = reader.ReadSnapshot(f)
	// Similarly just log the error but dont interrupt the startup of the scheduler
	if err != nil {
		logger.Errorf(ctx, "unable to construct the snapshot struct from the file due to %v", err)
		return nil, err
	}
	return snapshot, nil
}