@@ -74,18 +74,57 @@ func (db *DB) NewStreamWriter() *StreamWriter {
7474// Prepare should be called before writing any entry to StreamWriter. It deletes all data present in
7575// existing DB, stops compactions and any writes being done by other means. Be very careful when
7676// calling Prepare, because it could result in permanent data loss. Not calling Prepare would result
77- // in a corrupt Badger instance.
77+ // in a corrupt Badger instance. Use PrepareIncremental to do incremental stream write.
7878func (sw * StreamWriter ) Prepare () error {
7979 sw .writeLock .Lock ()
8080 defer sw .writeLock .Unlock ()
8181
8282 done , err := sw .db .dropAll ()
83+ // Ensure that done() is never called more than once.
84+ var once sync.Once
85+ sw .done = func () { once .Do (done ) }
86+ return err
87+ }
88+
89+ // PrepareIncremental should be called before writing any entry to StreamWriter incrementally.
90+ // In incremental stream write, the tables are written at one level above the current base level.
91+ func (sw * StreamWriter ) PrepareIncremental () error {
92+ sw .writeLock .Lock ()
93+ defer sw .writeLock .Unlock ()
8394
8495 // Ensure that done() is never called more than once.
8596 var once sync.Once
97+
98+ // prepareToDrop will stop all the incoming writes and process any pending flush tasks.
99+ // Before we start writing, we'll stop the compactions because no one else should be writing to
100+ // the same level as the stream writer is writing to.
101+ f , err := sw .db .prepareToDrop ()
102+ if err != nil {
103+ sw .done = func () { once .Do (f ) }
104+ return err
105+ }
106+ sw .db .stopCompactions ()
107+ done := func () {
108+ sw .db .startCompactions ()
109+ f ()
110+ }
86111 sw .done = func () { once .Do (done ) }
87112
88- return err
113+ isEmptyDB := true
114+ for _ , level := range sw .db .Levels () {
115+ if level .NumTables > 0 {
116+ sw .prevLevel = level .Level
117+ isEmptyDB = false
118+ }
119+ }
120+ if isEmptyDB {
121+ // If DB is empty, we should allow doing incremental stream write.
122+ return nil
123+ }
124+ if sw .prevLevel == 0 {
125+ return fmt .Errorf ("Unable to do incremental writes because L0 has data" )
126+ }
127+ return nil
89128}
90129
91130// Write writes KVList to DB. Each KV within the list contains the stream id which StreamWriter
@@ -169,11 +208,6 @@ func (sw *StreamWriter) Write(buf *z.Buffer) error {
169208 }
170209
171210 sw .processingKeys = true
172- if sw .prevLevel == 0 {
173- // If prevLevel is 0, that means that we have not written anything yet. Equivalently,
174- // we were virtually writing to the maxLevel+1.
175- sw .prevLevel = len (sw .db .lc .levels )
176- }
177211 var meta , userMeta byte
178212 if len (kv .Meta ) > 0 {
179213 meta = kv .Meta [0 ]
@@ -220,6 +254,14 @@ func (sw *StreamWriter) Write(buf *z.Buffer) error {
220254 return err
221255 }
222256
257+ // Moved this piece of code to within the lock.
258+ if sw .prevLevel == 0 {
259+ // If prevLevel is 0, that means that we have not written anything yet.
260+ // So, we can write to the maxLevel. newWriter writes to prevLevel - 1,
261+ // so we can set prevLevel to len(levels).
262+ sw .prevLevel = len (sw .db .lc .levels )
263+ }
264+
223265 for streamID , req := range streamReqs {
224266 writer , ok := sw .writers [streamID ]
225267 if ! ok {
0 commit comments