Snippets

Leslie Krause Incremental Map Backup Tools

Created by Leslie Krause last modified
local sqlite3 = require( "lsqlite3complete" )
local helpers = dofile( "/home/minetest/maplib/helpers.lua" )

if #arg == 0 then
	print( "Usage: export.lua maplog.txt master.sqlite backup.sqlite" )
	print( "Export all changed mapblocks from master database to backup database" )
	os.exit( 1 )
end

local maplog_path = assert( arg[ 1 ] )
local source_path = assert( arg[ 2 ] )
local target_path = assert( arg[ 3 ] )

--------------------------------------------------------

local file = assert( io.open( maplog_path ), "Cannot open changelog for reading." )

local old_sql = sqlite3.open( source_path, sqlite3.OPEN_READONLY )
if not old_sql then
	log_error( "Cannot open master database for reading." )
end

local new_sql = sqlite3.open( target_path )
if not new_sql then
	log_error( "Cannot open backup database for writing." )
end

for _ in new_sql:rows( "SELECT * FROM sqlite_master WHERE name = 'blocks' and type = 'table'" ) do
	error( "Cannot overwrite backup database." )
end

if new_sql:exec( "CREATE TABLE blocks (pos INTEGER PRIMARY KEY, data BLOB)" ) ~= sqlite3.OK then
	error( "Cannot create backup database." )
end

local insert = new_sql:prepare( "INSERT INTO blocks VALUES (?, ?)" )
local select = old_sql:prepare( "SELECT data FROM blocks WHERE pos = ?" )
local stored_count = 0
local logged_count = 0
local logged_total = 0
local logged_blocks = { }

--------------------------------------------------------

for line in file:lines( ) do
	local x, y, z = string.match( line, "Mapblock %((.-),(.-),(.-)%)" )
	local pos = { x = x + 0, y = y + 0, z = z + 0 }
	local index = helpers.encode_pos( pos )
	local version = logged_blocks[ index ] or 0

	if version == 0 then
		logged_count = logged_count + 1
	end
	logged_blocks[ index ] = version + 1
	logged_total = logged_total + 1
end

file:close( )

print( string.format( "Found %d mapblocks (%d total changes).", logged_count, logged_total ) )

--------------------------------------------------------

new_sql:exec( "BEGIN" )

for k, v in pairs( logged_blocks ) do
	select:reset( )
	select:bind_values( k )
	if select:step( ) ~= sqlite3.ROW then
		error( "Failed to read mapblock." )
	end

	local blob = select:get_value( 0 )

	insert:reset( )
	insert:bind_values( k, blob )
	if insert:step( ) ~= sqlite3.DONE then
		error( "Failed to write mapblock." )
	end
	stored_count = stored_count + 1
end

new_sql:exec( "END" )
new_sql:close( )
old_sql:close( )

print( string.format( "Successfully exported %d mapblocks.", stored_count ) )
local sqlite3 = require( "lsqlite3complete" )
local helpers = dofile( "/home/minetest/maplib/helpers.lua" )

if #arg == 0 then
        print( "Usage: import.lua master.sqlite backup.sqlite" )
        print( "Import all mapblocks from backup database into master database" )
        os.exit( 1 )
end

local target_path = assert( arg[ 1 ] )
local source_path = assert( arg[ 2 ] )

--------------------------------------------------------

local old_sql = sqlite3.open( source_path, sqlite3.OPEN_READONLY )
if not old_sql then
	log_error( "Cannot open backup database for reading." )
end

local new_sql = sqlite3.open( target_path )
if not new_sql then
	log_error( "Cannot open master database for writing." )
end

local insert = new_sql:prepare( "INSERT OR REPLACE INTO blocks VALUES (?, ?)" )
local stored_count = 0

--------------------------------------------------------

new_sql:exec( "BEGIN" )

for index, blob in old_sql:urows( "SELECT pos, data FROM blocks" ) do
	insert:reset( )
	insert:bind_values( index, blob )
	if insert:step( ) ~= sqlite3.DONE then
		error( "Failed to write mapblock." )
	end
	local pos = helpers.decode_pos( index )
	print( string.format( "Imported mapblock (%d,%d,%d) of %d bytes.", pos.x, pos.y, pos.z, #blob ) )
	stored_count = stored_count + 1
end

new_sql:exec( "END" )
new_sql:close( )
old_sql:close( )

--------------------------------------------------------

print( string.format( "Successfully imported %d mapblocks.", stored_count ) )

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.