func (m *MemDB) NewSnapshot() (*Snapshot, error) { buf := m.snapshots.MakeBuf() defer m.snapshots.FreeBuf(buf) // Stitch all local gclists from all writers to create snapshot gclist var head, tail *skiplist.Node for w := m.wlist; w != nil; w = w.next { if tail == nil { head = w.gchead tail = w.gctail } else if w.gchead != nil { tail.GClink = w.gchead tail = w.gctail } w.gchead = nil w.gctail = nil // Update global stats m.store.Stats.Merge(&w.slSts1) atomic.AddInt64(&m.itemsCount, w.count) w.count = 0 } snap := &Snapshot{db: m, sn: m.getCurrSn(), refCount: 1, count: m.ItemsCount()} m.snapshots.Insert(unsafe.Pointer(snap), CompareSnapshot, buf, &m.snapshots.Stats) snap.gclist = head newSn := atomic.AddUint32(&m.currSn, 1) if newSn == math.MaxUint32 { return nil, ErrMaxSnapshotsLimitReached } return snap, nil }
func (w *Writer) DeleteNode(x *skiplist.Node) (success bool) { defer func() { if success { w.count -= 1 } }() x.GClink = nil sn := w.getCurrSn() gotItem := (*Item)(x.Item()) if gotItem.bornSn == sn { success = w.store.DeleteNode(x, w.insCmp, w.buf, &w.slSts1) barrier := w.store.GetAccesBarrier() barrier.FlushSession(unsafe.Pointer(x)) return } success = atomic.CompareAndSwapUint32(&gotItem.deadSn, 0, sn) if success { if w.gctail == nil { w.gctail = x w.gchead = w.gctail } else { w.gctail.GClink = x w.gctail = x } } return }
func (m *MemDB) Close() { // Wait until all snapshot iterators have finished for s := m.snapshots.GetStats(); int(s.NodeCount) != 0; s = m.snapshots.GetStats() { time.Sleep(time.Millisecond) } m.hasShutdown = true // Acquire gc chan ownership // This will make sure that no other goroutine will write to gcchan for !atomic.CompareAndSwapInt32(&m.isGCRunning, 0, 1) { time.Sleep(time.Millisecond) } close(m.gcchan) buf := dbInstances.MakeBuf() defer dbInstances.FreeBuf(buf) dbInstances.Delete(unsafe.Pointer(m), CompareMemDB, buf, &dbInstances.Stats) if m.useMemoryMgmt { buf := m.snapshots.MakeBuf() defer m.snapshots.FreeBuf(buf) m.shutdownWg1.Wait() close(m.freechan) m.shutdownWg2.Wait() // Manually free up all nodes iter := m.store.NewIterator(m.iterCmp, buf) defer iter.Close() var lastNode *skiplist.Node iter.SeekFirst() if iter.Valid() { lastNode = iter.GetNode() iter.Next() } for lastNode != nil { m.freeItem((*Item)(lastNode.Item())) m.store.FreeNode(lastNode, &m.store.Stats) lastNode = nil if iter.Valid() { lastNode = iter.GetNode() iter.Next() } } } }