--[[ TechAge ======= Copyright (C) 2019 Joachim Stolberg GPL v3 See LICENSE.txt for more information Memory storage system for volatile and non-volatile memory. Non-volatile memory is stored from time to time and at shutdown as node metadata. Volatile memory is lost at every shutdown. ]]-- local S = function(pos) if pos then return minetest.pos_to_string(pos) end end -- Node data will be stored every NUM_SLOTS * CYCLE_TIME seconds local NUM_SLOTS = 50 local CYCLE_TIME = 60 local NvmStore = {} local MemStore = {} local NumNodes = 0 local StoredNodes = 0 local NextNum = 0 local Timeslot = 0 local FNAME = minetest.get_worldpath()..DIR_DELIM.."techage_metadata.txt" local function read_file() local f = io.open(FNAME, "r") if f ~= nil then local s = f:read("*all") io.close(f) return minetest.deserialize(s) or {} end return {} end local function write_file(tbl) local s = minetest.serialize(tbl) local f = io.open(FNAME, "w") f:write(s) f:close() end NvmStore = read_file() minetest.register_on_shutdown(function() write_file(NvmStore) end) local function set_metadata(hash, tbl) local pos = minetest.get_position_from_hash(hash) tbl.USED = nil local data = minetest.serialize(tbl) local meta = minetest.get_meta(pos) meta:set_string("ta_data", data) meta:mark_as_private("ta_data") end local function get_metadata(hash) local pos = minetest.get_position_from_hash(hash) local meta = minetest.get_meta(pos) local s = meta:get_string("ta_data") if s ~= "" then return minetest.deserialize(s) end end local function nvm_storage() local ToBeDeleted = {} for hash,tbl in pairs(NvmStore) do NumNodes = NumNodes + 1 if tbl.USED then if not tbl.SLOT then tbl.SLOT = NextNum % NUM_SLOTS NextNum = NextNum + 1 end if tbl.SLOT == Timeslot then set_metadata(hash, tbl) StoredNodes = StoredNodes + 1 end else ToBeDeleted[#ToBeDeleted+1] = hash end end for _,hash in ipairs(ToBeDeleted) do NvmStore[hash] = nil end return #ToBeDeleted end local function cyclic_task() local t = minetest.get_us_time() Timeslot = (Timeslot + 1) % NUM_SLOTS NumNodes = 0 StoredNodes = 0 local deleted = nvm_storage() t = minetest.get_us_time() - t if StoredNodes > 0 then minetest.log("action", "[TA NVM Storage] duration="..t.."us, total="..NumNodes..", stored="..StoredNodes..", deleted="..deleted) end minetest.after(CYCLE_TIME, cyclic_task) end minetest.after(CYCLE_TIME, cyclic_task) -- To get the volatile node data as table function techage.get_mem(pos) local hash = minetest.hash_node_position(pos) if not MemStore[hash] then MemStore[hash] = {} end return MemStore[hash] end -- To get the nonvolatile node data as table function techage.get_nvm(pos) local hash = minetest.hash_node_position(pos) if not NvmStore[hash] then NvmStore[hash] = get_metadata(hash) or {} end NvmStore[hash].USED = true return NvmStore[hash] end function techage.peek_nvm(pos) local hash = minetest.hash_node_position(pos) return NvmStore[hash] or {} end -- To be called when a node is removed function techage.del_mem(pos) local meta = minetest.get_meta(pos) meta:set_string("ta_data", "") local hash = minetest.hash_node_position(pos) NvmStore[hash] = nil MemStore[hash] = nil end