Write Batches

A batch groups several writes so they're applied atomically – either all of them take effect, or (if the process crashes before the batch is written) none of them do. Both tiers offer this.

Tier 2: WriteBatch and write!

using RocksDB

db = opendb(mktempdir() * "/batchdb")
wb = WriteBatch()
put!(wb, "a", "1")
put!(wb, "b", "2")
delete!(wb, "a")     # deletes can be staged in the same batch as puts
write!(db, wb)        # applied atomically

get(db, "a")                  # nothing
String(get(db, "b"))          # "2"
close(db)

Reuse a batch across multiple rounds of writes with empty!(wb) instead of allocating a new one each time.

RocksDB.batch(db) do wb ... end is a do-block shortcut for the same thing: it creates the batch, runs the block, and calls write! for you automatically – only if the block returns normally:

using RocksDB

db = opendb(mktempdir() * "/batchdb2")
RocksDB.batch(db) do wb
    put!(wb, "a", "1")
    put!(wb, "b", "2")
end   # write! called here, automatically
String(get(db, "a"))   # "1"
close(db)

Tier 3: RocksDB.batch

using RocksDB

d = RocksDBDict{String,String}(mktempdir() * "/batchdict")
RocksDB.batch(d) do b
    b["x"] = "1"
    b["y"] = "2"
end   # committed atomically here
d["x"]   # "1"
close(d)

Rollback on exception

If the block passed to RocksDB.batch throws (at either tier), nothing staged in it is written – the exception simply propagates, and write! is never called:

using RocksDB

d = RocksDBDict{String,String}(mktempdir() * "/batchdict2")
try
    RocksDB.batch(d) do b
        b["z"] = "3"
        error("something went wrong downstream")
    end
catch e
    println("caught: ", e)
end
haskey(d, "z")   # false -- the batch was discarded, not partially applied
close(d)

Building a WriteBatch by hand (rather than through the do-block form) gives you the same guarantee just as easily: don't call write! if you decide not to commit (e.g. inside a try/catch) – an un-written WriteBatch has no effect on the database at all.