@@ -22,15 +22,16 @@ type LUAConfig struct {
2222}
2323
2424type LUA struct {
25- l * lua.LState
26- ud * lua.LUserData
27- luaFunc lua.LValue
28- luaNext * lua.LFunction
25+ l * lua.LState // lua state used during all the baker filter lifetime
26+ ud * lua.LUserData // pre-allocated (reused) userdata for the processed record
27+ luaFunc lua.LValue // lua filter function
28+ luaNext * lua.LFunction // lua next function (reused)
2929 next func (baker.Record )
3030}
3131
3232func NewLUA (cfg baker.FilterParams ) (baker.Filter , error ) {
3333 dcfg := cfg .DecodedConfig .(* LUAConfig )
34+
3435 l := lua .NewState ()
3536 if err := l .DoFile (dcfg .Script ); err != nil {
3637 return nil , fmt .Errorf ("can't compile lua script %q: %v" , dcfg .Script , err )
@@ -44,21 +45,25 @@ func NewLUA(cfg baker.FilterParams) (baker.Filter, error) {
4445 }
4546
4647 // Preallocate the userdata we use to wrap the record passed to the filter.
48+ // We can do this since a single instance of a baker filter is only ever
49+ // processing a single record at a time, so we can reuse the lua userdata
50+ // structure for it. This reduces allocations.
4751 ud := l .NewUserData ()
4852 l .SetMetatable (ud , l .GetTypeMetatable (luaRecordTypeName ))
4953
50- f := & LUA {
51- luaFunc : luaFunc ,
52- l : l ,
53- ud : ud ,
54- }
54+ f := & LUA {}
5555
56- // Preallocate the lua next function passed to the filter
57- f . luaNext = l .NewFunction (func (L * lua.LState ) int {
56+ // Preallocate the lua next function passed to the filter.
57+ luaNext : = l .NewFunction (func (L * lua.LState ) int {
5858 f .next (fastcheckLuaRecord (L , 1 ).r )
5959 return 0
6060 })
6161
62+ f .l = l
63+ f .ud = ud
64+ f .luaNext = luaNext
65+ f .luaFunc = luaFunc
66+
6267 runtime .SetFinalizer (f , func (f * LUA ) { f .l .Close () })
6368
6469 return f , nil
0 commit comments