func (s *storageMgr) createSnapshotWorker(streamId common.StreamId, bucket string, tsVbuuid *common.TsVbuuid, indexSnapMap IndexSnapMap, numVbuckets int, indexInstMap common.IndexInstMap, indexPartnMap IndexPartnMap, stats *IndexerStats) { defer destroyIndexSnapMap(indexSnapMap) var needsCommit bool snapType := tsVbuuid.GetSnapType() if snapType == common.DISK_SNAP { needsCommit = true } var wg sync.WaitGroup //for every index managed by this indexer for idxInstId, partnMap := range indexPartnMap { // Create snapshots for all indexes in parallel wg.Add(1) go func(idxInstId common.IndexInstId, partnMap PartitionInstMap) { defer wg.Done() idxInst := indexInstMap[idxInstId] idxStats := stats.indexes[idxInst.InstId] lastIndexSnap := indexSnapMap[idxInstId] //if index belongs to the flushed bucket and stream if idxInst.Defn.Bucket == bucket && idxInst.Stream == streamId && idxInst.State != common.INDEX_STATE_DELETED { // List of snapshots for reading current timestamp var isSnapCreated bool = true partnSnaps := make(map[common.PartitionId]PartitionSnapshot) //for all partitions managed by this indexer for partnId, partnInst := range partnMap { var lastPartnSnap PartitionSnapshot if lastIndexSnap != nil { lastPartnSnap = lastIndexSnap.Partitions()[partnId] } sc := partnInst.Sc sliceSnaps := make(map[SliceId]SliceSnapshot) //create snapshot for all the slices for _, slice := range sc.GetAllSlices() { var latestSnapshot Snapshot if lastIndexSnap.Partitions() != nil { lastSliceSnap := lastPartnSnap.Slices()[slice.Id()] latestSnapshot = lastSliceSnap.Snapshot() } //if flush timestamp is greater than last //snapshot timestamp, create a new snapshot snapTs := NewTimestamp(numVbuckets) if latestSnapshot != nil { snapTsVbuuid := latestSnapshot.Timestamp() snapTs = getSeqTsFromTsVbuuid(snapTsVbuuid) } ts := getSeqTsFromTsVbuuid(tsVbuuid) //if the flush TS is greater than the last snapshot TS //and slice has some changes. Skip only in-memory snapshot //in case of unchanged data. if latestSnapshot == nil || (ts.GreaterThan(snapTs) && (slice.IsDirty() || needsCommit)) { newTsVbuuid := tsVbuuid.Copy() var err error var info SnapshotInfo var newSnapshot Snapshot logging.Tracef("StorageMgr::handleCreateSnapshot Creating New Snapshot "+ "Index: %v PartitionId: %v SliceId: %v Commit: %v", idxInstId, partnId, slice.Id(), needsCommit) snapCreateStart := time.Now() if info, err = slice.NewSnapshot(newTsVbuuid, needsCommit); err != nil { logging.Errorf("handleCreateSnapshot::handleCreateSnapshot Error "+ "Creating new snapshot Slice Index: %v Slice: %v. Skipped. Error %v", idxInstId, slice.Id(), err) isSnapCreated = false common.CrashOnError(err) continue } snapCreateDur := time.Since(snapCreateStart) idxStats := stats.indexes[idxInstId] idxStats.numSnapshots.Add(1) if needsCommit { idxStats.numCommits.Add(1) } snapOpenStart := time.Now() if newSnapshot, err = slice.OpenSnapshot(info); err != nil { logging.Errorf("StorageMgr::handleCreateSnapshot Error Creating Snapshot "+ "for Index: %v Slice: %v. Skipped. Error %v", idxInstId, slice.Id(), err) isSnapCreated = false common.CrashOnError(err) continue } snapOpenDur := time.Since(snapOpenStart) logging.Infof("StorageMgr::handleCreateSnapshot Added New Snapshot Index: %v "+ "PartitionId: %v SliceId: %v Crc64: %v (%v) SnapCreateDur %v SnapOpenDur %v", idxInstId, partnId, slice.Id(), tsVbuuid.Crc64, info, snapCreateDur, snapOpenDur) ss := &sliceSnapshot{ id: slice.Id(), snap: newSnapshot, } sliceSnaps[slice.Id()] = ss } else { // Increment reference latestSnapshot.Open() ss := &sliceSnapshot{ id: slice.Id(), snap: latestSnapshot, } sliceSnaps[slice.Id()] = ss logging.Warnf("StorageMgr::handleCreateSnapshot Skipped Creating New Snapshot for Index %v "+ "PartitionId %v SliceId %v. No New Mutations. IsDirty %v", idxInstId, partnId, slice.Id(), slice.IsDirty()) logging.Debugf("StorageMgr::handleCreateSnapshot SnapTs %v FlushTs %v", snapTs, ts) continue } } ps := &partitionSnapshot{ id: partnId, slices: sliceSnaps, } partnSnaps[partnId] = ps } is := &indexSnapshot{ instId: idxInstId, ts: tsVbuuid.Copy(), partns: partnSnaps, } if isSnapCreated { s.updateSnapMapAndNotify(is, idxStats) } else { DestroyIndexSnapshot(is) } s.updateSnapIntervalStat(idxStats) } }(idxInstId, partnMap) } wg.Wait() s.supvRespch <- &MsgMutMgrFlushDone{mType: STORAGE_SNAP_DONE, streamId: streamId, bucket: bucket, ts: tsVbuuid} }