diff options
author | mpeterv <mpeterval@gmail.com> | 2016-04-17 18:56:11 +0300 |
---|---|---|
committer | mpeterv <mpeterval@gmail.com> | 2016-04-17 18:56:11 +0300 |
commit | 1234e0ffe19f3c6a9100d736d1456f63b7eb5dff (patch) | |
tree | 777fb1f20188d52bfa3da53ed8254f440609c7fb | |
parent | 4bac04e98c8da125d9d33a3324e753434e3571e5 (diff) | |
download | luacov-1234e0ffe19f3c6a9100d736d1456f63b7eb5dff.tar.gz |
Accumulate new coverage instead of storing all of it
Instead of loading all stats at start, updating them gradually and
saving at the end, accumulate new stats; then, when saving, load
old stats, add new stats to them, save the sum.
This means that stats saving/loading is much more "atomic":
luacov doesn't care at all if another instance updates the stats file,
unless they happen to try to save stats at the same time.
That can't happen in the most common case when parent Lua with
luacov enabled starts another one using os.execute. Even with luacov.tick
parent may only save after the child exits.
luacov.pause and luacov.resume are now only needed for pausing stats
saving, which may be useful for performance when using luacov.tick.
-rw-r--r-- | src/luacov/runner.lua | 85 | ||||
-rw-r--r-- | tests/nested/test.lua | 4 |
2 files changed, 32 insertions, 57 deletions
diff --git a/src/luacov/runner.lua b/src/luacov/runner.lua index e9b87b7..7671862 100644 --- a/src/luacov/runner.lua +++ b/src/luacov/runner.lua @@ -20,7 +20,7 @@ local function on_exit_wrap(fn) return anchor end -local data +local data = {} local tick local paused = true local initialized = false @@ -80,6 +80,22 @@ function runner.update_stats(old_stats, extra_stats) end end +-- Adds accumulated stats to existing stats file or writes a new one, then resets data. +local function save_stats() + local loaded = stats.load(runner.configuration.statsfile) or {} + + for name, file_data in pairs(data) do + if loaded[name] then + runner.update_stats(loaded[name], file_data) + else + loaded[name] = file_data + end + end + + stats.save(runner.configuration.statsfile, loaded) + data = {} +end + -------------------------------------------------- -- Debug hook set by LuaCov. -- Acknowledges that a line is executed, but does nothing @@ -144,7 +160,7 @@ function runner.debug_hook(_, line_nr, level) ctr = 0 if not paused then - stats.save(runner.configuration.statsfile, data) + save_stats() end end end @@ -175,10 +191,11 @@ local function on_exit() -- so this method could be called twice if on_exit_run_once then return end on_exit_run_once = true + save_stats() - runner.pause() - - if runner.configuration.runreport then runner.run_report(runner.configuration) end + if runner.configuration.runreport then + runner.run_report(runner.configuration) + end end -- Returns true if the given filename exists. @@ -376,58 +393,16 @@ function runner.load_config(configuration) end -------------------------------------------------- --- Pauses LuaCov's runner. --- Saves collected data and stops, allowing other processes to write to --- the same stats file. Data is still collected during pause. +-- Pauses saving data collected by LuaCov's runner. +-- Allows other processes to write to the same stats file. +-- Data is still collected during pause. function runner.pause() - if paused then - return - end - paused = true - stats.save(runner.configuration.statsfile, data) - -- Reset data, so that after resuming it could be added to data loaded - -- from the stats file, possibly updated from another process. - data = {} end -------------------------------------------------- --- Resumes LuaCov's runner. --- Reloads stats file, possibly updated from other processes, --- and continues saving collected data. +-- Resumes saving data collected by LuaCov's runner. function runner.resume() - if not paused then - return - end - - local loaded = stats.load(runner.configuration.statsfile) or {} - - if data then - for name, file in pairs(loaded) do - if data[name] then - runner.update_stats(data[name], file) - else - data[name] = file - end - end - else - data = loaded - end - - if not tick then - -- As __gc hooks are called in reverse order of their creation, - -- and stats file has a __gc hook closing it, - -- the exit __gc hook writing data to stats file must be recreated - -- after stats file is reopened. - - if runner.on_exit_trick then - -- Deactivate previous handler. - getmetatable(runner.on_exit_trick).__gc = nil - end - - runner.on_exit_trick = on_exit_wrap(on_exit) - end - paused = false end @@ -476,7 +451,6 @@ end function runner.init(configuration) runner.configuration = runner.load_config(configuration) tick = runner.tick - runner.resume() -- metatable trick on filehandle won't work if Lua exits through -- os.exit() hence wrap that with exit code as well @@ -517,7 +491,12 @@ function runner.init(configuration) end end + if not tick then + runner.on_exit_trick = on_exit_wrap(on_exit) + end + initialized = true + paused = false end -------------------------------------------------- @@ -525,7 +504,7 @@ end -- This should only be called from daemon processes or sandboxes which have -- disabled os.exit and other hooks that are used to determine shutdown. function runner.shutdown() - on_exit() + on_exit() end -- Gets the sourcefilename from a function. diff --git a/tests/nested/test.lua b/tests/nested/test.lua index 67a5e72..d9d4e49 100644 --- a/tests/nested/test.lua +++ b/tests/nested/test.lua @@ -3,8 +3,6 @@ local luacov = require "luacov.runner" testlib.f1() -luacov.pause() - local cmd = arg[-5] or "lua" local slash = cmd:find("/") @@ -21,6 +19,4 @@ cmd = cmd .. " -e 'dofile([[script.lua]])'" local ok = os.execute("cd subdir && " .. cmd) assert(ok == 0 or ok == true) -luacov.resume() - testlib.f2() |