| Comment: | begin replacing inefficient memory management with a pool-based solution; fix memory leaks |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
7c8769bf968cda064fdda9ccd9fcd551 |
| User & Date: | lexi on 2021-01-10 08:19:56 |
| Other Links: | manifest | tags |
|
2021-01-10
| ||
| 11:17 | add follow notices check-in: 00a6815988 user: lexi tags: trunk | |
| 08:19 | begin replacing inefficient memory management with a pool-based solution; fix memory leaks check-in: 7c8769bf96 user: lexi tags: trunk | |
| 03:54 | add memory pool impl, handle various little details, add beginnings of mimelib check-in: 8d35307a7f user: lexi tags: trunk | |
Modified html.t from [f6f8bc0dcc] to [06c69e3651].
1 1 -- vim: ft=terra 2 2 local m={} 3 3 local pstr = lib.mem.ptr(int8) 4 4 5 -terra m.sanitize(txt: pstr, quo: bool) 5 +terra m.sanitize(pool: &lib.mem.pool, txt: pstr, quo: bool) 6 6 if txt.ptr == nil then return pstr.null() end 7 7 if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end 8 - var a: lib.str.acc a:init(txt.ct*1.3) 8 + var a: lib.str.acc a:pool(pool,txt.ct*1.3) 9 9 for i=0,txt.ct do 10 10 if txt(i) == @'<' then a:lpush('<') 11 11 elseif txt(i) == @'>' then a:lpush('>') 12 12 elseif txt(i) == @'&' then a:lpush('&') 13 13 elseif quo and txt(i) == @'"' then a:lpush('"') 14 14 else a:push(&txt(i),1) end 15 15 end ................................................................................ 24 24 25 25 terra m.hexbyte(i: uint8): int8[2] 26 26 return arrayof(int8, 27 27 m.hexdgt(i / 0x10), 28 28 m.hexdgt(i % 0x10)) 29 29 end 30 30 31 -terra m.urlenc(txt: pstr, qparam: bool) 31 +terra m.urlenc(pool: &lib.mem.pool, txt: pstr, qparam: bool) 32 32 if txt.ptr == nil then return pstr.null() end 33 33 if txt.ct == 0 then txt.ct = lib.str.sz(txt.ptr) end 34 - var a: lib.str.acc a:init(txt.ct*1.3) 34 + var a: lib.str.acc a:pool(pool,txt.ct*1.3) 35 35 for i=0,txt.ct do 36 36 if txt(i) == @' ' then a:lpush('+') 37 37 elseif txt(i) == @'&' and not qparam then a:lpush('&') 38 38 elseif (txt(i) < 0x2c or 39 39 (txt(i) > @';' and txt(i) < @'@') or 40 40 (txt(i) > @'Z' and txt(i) < @'a') or 41 41 (txt(i) >= 0x7b and txt(i) <= 0x7f)) and
Modified mem.t from [de24aef2de] to [7e2b478eaf].
179 179 end) 180 180 181 181 struct m.pool { 182 182 -- implements growable memory pools. EVERY THREAD MUST HAVE ITS OWN 183 183 storage: &opaque 184 184 cursor: &opaque 185 185 sz: intptr 186 + debris: &m.pool 186 187 } 187 188 188 189 terra m.pool:cue(sz: intptr) 189 190 if self.storage == nil then 190 191 self.storage = m.heapa_raw(sz) 191 192 self.cursor = self.storage 192 193 self.sz = sz 193 194 else 194 195 if self.sz >= sz then return self end 195 - var ofs = [&uint8](self.cursor) - [&uint8](self.storage) 196 - self.storage = m.heapr_raw(self.storage, sz) 197 - self.cursor = [&opaque]([&uint8](self.storage) + ofs) 198 - self.sz = sz 196 + var oldblock = @self 197 + self:init(sz) 198 + @self.debris = oldblock 199 199 end 200 200 return self 201 201 end 202 202 203 203 terra m.pool:init(sz: intptr) 204 - self.storage = nil 205 - self:cue(sz) 204 + var b = m.heapa_raw(sz + sizeof(m.pool)) 205 + self.storage = [&uint8](b) + sizeof(m.pool) 206 + self.cursor = self.storage 207 + self.sz = sz 208 + self.debris = [&m.pool](b) 209 + self.debris.storage = nil 206 210 return self 207 211 end 208 212 209 -terra m.pool:free() 210 - m.heapf(self.storage) 213 +terra m.pool:free(): {} 214 +lib.io.fmt('DRAINING POOL %p\n',self.storage) 215 + if self.storage == nil then return end 216 + if self.debris.storage ~= nil then self.debris:free() end 217 + m.heapf(self.debris) -- storage + debris field allocated in one block 211 218 self.storage = nil 212 219 self.cursor = nil 213 220 self.sz = 0 221 + self.debris = nil 214 222 end 215 223 216 224 terra m.pool:clear() 225 + if self.debris.storage ~= nil then self.debris:free() end 217 226 self.cursor = self.storage 218 227 return self 219 228 end 220 229 221 230 terra m.pool:alloc_bytes(sz: intptr): &opaque 222 231 var space = self.sz - ([&uint8](self.cursor) - [&uint8](self.storage)) 223 - if space < sz then self:cue(space + sz + 256) end 232 +lib.io.fmt('%p / %p @ allocating %llu bytes in %llu of space\n',self.storage,self.cursor,sz,space) 233 + if space < sz then 234 +lib.dbg('reserving more space') 235 + self:cue(space + sz + 256) end 224 236 var ptr = self.cursor 225 237 self.cursor = [&opaque]([&uint8](self.cursor) + sz) 226 238 return ptr 227 239 end 228 240 229 -m.pool.methods.alloc = macro(function(self,ty,sz) 230 - return `[ty](self:alloc_bytes(sizeof(ty) * sz)) 241 +terra m.pool:realloc_bytes(oldptr: &opaque, oldsz: intptr, newsz: intptr): &opaque 242 + var space = self.sz - ([&uint8](self.cursor) - [&uint8](self.storage)) 243 + var cur = [&uint8](self.cursor) 244 + if cur - [&uint8](oldptr) == oldsz and newsz - oldsz < space then 245 + lib.dbg('moving pool cursor') 246 + cur = cur + (newsz - oldsz) 247 + self.cursor = [&opaque](cur) 248 + return oldptr 249 + else 250 + lib.dbg('copying pool object') 251 + var new = self:alloc_bytes(newsz) 252 + m.cpy(new, oldptr, oldsz) 253 + return new 254 + end 255 +end 256 + 257 +m.pool.methods.alloc = macro(function(self,typ,sz) 258 + local ty = typ:astype() 259 + return `[m.ptr(ty)] { 260 + ptr = [&ty](self:alloc_bytes(sizeof([ty]) * [sz])); 261 + ct = [sz]; 262 + } 263 +end) 264 + 265 +m.pool.methods.realloc = macro(function(self,ptr,oldsz,newsz) 266 + local ty = self.tree.type.type 267 + return `[m.ptr(ty)] { 268 + ptr = [&ty](self:realloc_bytes(ptr, 269 + sizeof(ty) * oldsz, 270 + sizeof(ty) * newsz)); 271 + ct = sz; 272 + } 231 273 end) 232 274 233 275 terra m.pool:frame() -- stack-style linear mgmt 234 276 return self.cursor 235 277 end 236 278 237 279 terra m.pool:reset(frame: &opaque) 238 - self.cursor = frame 280 + if frame >= self.storage and frame <= self.cursor then 281 + self.cursor = frame 282 + else -- trying to rewind into a previous block! not possible 283 + self.cursor = self.storage 284 + end 239 285 return self 240 286 end 241 287 242 288 243 289 return m
Modified render/compose.t from [13509724e6] to [95dc7dcbc1].
12 12 form.acl = lib.trn(target == nil, 'all', 'mentioned') -- TODO default acl setting? 13 13 else 14 14 form.content = lib.coalesce(edit.body, '') 15 15 form.acl = edit.acl 16 16 end 17 17 if acc ~= nil then form:append(acc) return end 18 18 19 - var cotxt = form:tostr() defer cotxt:free() 19 + var cotxt = form:poolstr(&co.srv.pool) -- defer cotxt:free() 20 20 21 21 var doc = [lib.srv.convo.page] { 22 22 title = lib.str.plit 'compose'; 23 23 body = cotxt; 24 24 class = lib.str.plit 'compose'; 25 25 cache = true; 26 26 } 27 27 28 28 co:stdpage(doc) 29 29 end 30 30 31 31 return render_compose
Modified render/conf.t from [241a1c4277] to [cd79efba6f].
28 28 local invoker = quote co:complain(404,'not found','no such control panel is available in this version of parsav') end 29 29 30 30 for i, m in ipairs(mappings) do 31 31 if lib.render.conf[m.render] then 32 32 invoker = quote 33 33 if path(1):cmp(lib.str.lit([m.url])) then 34 34 var body = [lib.render.conf[m.render]] (co, path) 35 - var a: lib.str.acc a:init(body.ct+48) 35 + var a = co:stra(body.ct+48) 36 36 if not body then 37 37 a:lpush(['<h1>' .. m.title .. ' :: error</h1>' .. 38 38 '<p>the requested resource is not available.</p>']) 39 39 panel = a:finalize() 40 40 else 41 41 a:lpush(['<h1>' .. m.title .. '</h1>']):ppush(body) 42 42 panel = a:finalize() 43 - body:free() 43 + --body:free() 44 44 end 45 45 else [invoker] end 46 46 end 47 47 end 48 48 end 49 49 50 50 local terra 51 51 render_conf([co], [path], notify: pstr) 52 - var menu: lib.str.acc menu:init(64):lpush('<hr>') defer menu:free() 52 + var menu = co:stra(256) 53 + menu:lpush('<hr>') 53 54 54 55 -- build menu 55 56 do var p = co.who.rights.powers 56 57 if p:affect_users() then menu:lpush '<a href="/conf/users">users</a>' end 57 58 if p.censor() then menu:lpush '<a href="/conf/censor">badthink alerts</a>' end 58 59 if p.config() then menu:lpush([ 59 60 '<a href="/conf/srv">server & policy</a>' .. ................................................................................ 74 75 menu = mptr; 75 76 panel = panel; 76 77 } 77 78 78 79 var pgt: pstr 79 80 if notify:ref() then 80 81 var fnpg: lib.str.acc 81 - fnpg:compose('<div class="flashmsg">', notify, '</div>') 82 + fnpg:pcompose(&co.srv.pool, '<div class="flashmsg">', notify, '</div>') 82 83 pg:append(&fnpg) 83 84 pgt = fnpg:finalize() 84 - else pgt = pg:tostr() end 85 - defer pgt:free() 85 + else pgt = pg:poolstr(&co.srv.pool) end 86 + --defer pgt:free() 86 87 87 88 co:stdpage([lib.srv.convo.page] { 88 89 title = 'configure'; body = pgt; 89 90 class = lib.str.plit 'conf'; 90 91 cache = false; 91 92 }) 92 93 93 - if panel.ct ~= 0 then panel:free() end 94 + --if panel.ct ~= 0 then panel:free() end 94 95 end 95 96 96 97 return render_conf
Modified render/conf/profile.t from [864a63a85e] to [5b3736f2f4].
11 11 var hue: int8[21] 12 12 var c = data.view.conf_profile { 13 13 handle = cs(co.who.handle); 14 14 nym = cs(lib.coalesce(co.who.nym,'')); 15 15 bio = cs(lib.coalesce(co.who.bio,'')); 16 16 hue = lib.math.decstr(co.ui_hue, &hue[20]); 17 17 } 18 - return c:tostr() 18 + return c:poolstr(&co.srv.pool) 19 19 end 20 20 21 21 return render_conf_profile
Modified render/conf/sec.t from [f6e2d18341] to [d16c1b9a13].
9 9 lib.osclock.ctime_r(&time, &tstr[0]) 10 10 var body = data.view.conf_sec { 11 11 lastreset = pstr { 12 12 ptr = &tstr[0], ct = lib.str.sz(&tstr[0]) 13 13 } 14 14 } 15 15 16 - var a: lib.str.acc a:init(768) defer a:free() 16 + var a = co:stra(768) -- defer a:free() 17 17 18 18 if co.srv.cfg.credmgd then 19 19 var new = co:pgetv('new') 20 20 if not new then 21 21 body:append(&a) 22 22 var credmgr = data.view.conf_sec_credmg { 23 23 credlist = pstr{'',0}; 24 24 } 25 25 var creds = co.srv:auth_enum_uid(uid) 26 26 if creds.ct > 0 then defer creds:free() 27 - var cl: lib.str.acc cl:init(256) 27 + var cl = co:stra(256) 28 28 for i=0, creds.ct do var c = creds(i).ptr 29 29 if not c.blacklist then 30 30 cl:lpush('<option value="'):shpush(c.aid):lpush('"> ['):push(c.kind,0):lpush('] '):push(c.comment,0) 31 31 if c.netmask.pv ~= 0 then 32 32 -- push string rep 33 33 end 34 34 cl:lpush('</option>') 35 35 end 36 36 end 37 37 credmgr.credlist = cl:finalize() 38 38 end 39 39 credmgr:append(&a) 40 - if credmgr.credlist.ct > 0 then credmgr.credlist:free() end 40 + --if credmgr.credlist.ct > 0 then credmgr.credlist:free() end 41 41 else 42 42 if new:cmp(lib.str.plit'pw') then 43 43 var d: data.view.conf_sec_pwnew 44 44 var time = lib.osclock.time(nil) 45 45 var timestr: int8[26] lib.osclock.ctime_r(&time, ×tr[0]) 46 - var cmt: lib.str.acc 47 - cmt:init(48):lpush('enrolled over http on '):push(×tr[0],0) 46 + var cmt = co:stra(48) 47 + cmt:lpush('enrolled over http on '):push(×tr[0],0) 48 48 d.comment = cmt:finalize() 49 49 50 - var st = d:tostr() 51 - d.comment:free() 50 + var st = d:poolstr(&co.srv.pool) 51 + --d.comment:free() 52 52 return st 53 53 elseif new:cmp(lib.str.plit'challenge') then 54 54 -- we're going to break the rules a bit and do database munging from 55 55 -- the rendering code, because doing otherwise in this case would be 56 56 -- genuinely nightmarish 57 57 elseif new:cmp(lib.str.plit'otp') then 58 58 elseif new:cmp(lib.str.plit'api') then
Modified render/conf/users.t from [59cb9f4fac] to [7c5c858095].
170 170 -- FIXME allow xids as well, for manual queries 171 171 if not user then goto e404 end 172 172 defer user:free() 173 173 if not co.who:overpowers(user.ptr) then goto e403 end 174 174 175 175 if path.ct == 4 then 176 176 if path(3):cmp(lib.str.lit'cred') then 177 - var pg: lib.str.acc pg:init(1024) 177 + var pg = co:stra(1024) 178 178 pg:lpush('<div class="context">editing credentials for user <a href="/conf/users/'):rpush(path(2)):lpush('">'):push(user(0).xid,0):lpush('</a></div>') 179 179 var credmgr = lib.render.conf.sec(co, uid) 180 180 pg:ppush(credmgr) 181 - credmgr:free() 181 + --credmgr:free() 182 182 return pg:finalize() 183 183 else goto e404 end 184 184 elseif path.ct == 3 then 185 - var cinp: lib.str.acc cinp:init(256) 185 + var cinp = co:stra(256) 186 186 cinp:lpush('<div class="elem-group">') 187 187 if user.ptr.rights.rank > 0 and (co.who.rights.powers.elevate() or co.who.rights.powers.demote()) then 188 188 var max = co.who.rights.rank 189 189 if not co.who.rights.powers.elevate() then max = user.ptr.rights.rank end 190 190 var min = co.srv.cfg.nranks 191 191 if not co.who.rights.powers.demote() then min = user.ptr.rights.rank end 192 192 193 193 push_num_field(cinp, 'rank', 'rank', max, min, user.ptr.rights.rank, user.ptr.id == co.who.id) 194 194 end 195 195 if co.who.rights.powers.herald() then 196 196 var sanitized: pstr 197 197 if user.ptr.epithet == nil 198 198 then sanitized = pstr {ptr='', ct=0} 199 - else sanitized = lib.html.sanitize(cs(user.ptr.epithet),true) 199 + else sanitized = lib.html.sanitize(&co.srv.pool,cs(user.ptr.epithet),true) 200 200 end 201 201 cinp:lpush('<div class="elem"><label for="epithet">epithet</label><input type="text" id="epithet" name="epithet" value="'):ppush(sanitized):lpush('"></div>') 202 - if user.ptr.epithet ~= nil then sanitized:free() end 202 + --if user.ptr.epithet ~= nil then sanitized:free() end 203 203 end 204 204 if co.who.rights.powers.invite() or co.who.rights.powers.discipline() then 205 205 var min: uint32 = 0 206 206 if not (co.who.rights.powers.discipline() or 207 207 co.who.rights.powers.demote() and co.who.rights.powers.invite()) 208 208 then min = user.ptr.rights.invites end 209 209 var max: uint32 = co.srv.cfg.maxinvites ................................................................................ 234 234 var map = array([lib.store.powmap]) 235 235 cinp:lpush('<details><summary>powers</summary><div class="pick-list">') 236 236 for i=0, [map.type.N] do 237 237 if (co.who.rights.powers and map[i].val):sz() > 0 then 238 238 var on = (user.ptr.rights.powers and map[i].val):sz() > 0 239 239 var enabled = ( on and co.who.rights.powers.demote() ) or 240 240 ((not on) and co.who.rights.powers.elevate()) 241 - var namea: lib.str.acc namea:compose('power-', map[i].name) 241 + var namea: lib.str.acc namea:pcompose(&co.srv.pool,'power-', map[i].name) 242 242 var name = namea:finalize() 243 243 push_pickbox(&cinp, name, pstr.null(), map[i].name, on, enabled, pstr.null()) 244 - name:free() 244 + --name:free() 245 245 end 246 246 end 247 247 cinp:lpush('</div></details>') 248 248 end 249 249 250 250 if co.who.id ~= uid and co.who.rights.powers.purge() then 251 - var purgeconf: lib.str.acc purgeconf:init(48) 251 + var purgeconf = co:stra(48) 252 252 var purgestrs = array( 253 253 'alpha', 'beta', 'gamma', 'delta', 'epsilon', 'eta', 'nu', 'kappa', 254 254 'emerald', 'carnelian', 'sapphire', 'ruby', 'amethyst', 'glory', 255 255 'hope', 'grace', 'pearl', 'carnation', 'rose', 'peony', 'poppy' 256 256 ) 257 257 for i=0,3 do 258 258 purgeconf:push(purgestrs[lib.crypt.random(intptr,0,[purgestrs.type.N])],0) 259 259 if i ~= 2 then purgeconf:lpush('-') end 260 260 end 261 261 cinp:lpush('<details><summary>purge account</summary><p>you have the authority to destroy this account and all its associated content irreversibly and irretrievably. if you really wish to apply such an extreme sanction, enter the confirmation string <strong style="user-select:none">'):push(purgeconf.buf,purgeconf.sz):lpush('</strong> below and press the “alter” button to begin the process.</p><div class="elem"><label for="purge">purge confirmation string</label><input type="text" id="purge" name="purgekey"></div><input type="hidden" name="purgestr" value="'):push(purgeconf.buf,purgeconf.sz):lpush('"></details>') 262 - purgeconf:free() 262 + --purgeconf:free() 263 263 end 264 264 265 265 -- TODO black mark system? e.g. resolution option for badthink reports 266 266 -- adds a black mark to the offending user; they can be automatically banned 267 267 -- or brought up for review after a certain number of offenses; possibly lower 268 268 -- set of default privs for marked users 269 269 270 - var cinpp = cinp:finalize() defer cinpp:free() 271 - var unym: lib.str.acc unym:init(64) 270 + var cinpp = cinp:finalize() --defer cinpp:free() 271 + var unym = co:stra(64) 272 272 unym:lpush('<a href="/') 273 273 if user(0).origin ~= 0 then unym:lpush('@') end 274 - do var sanxid = lib.html.sanitize(user(0).xid, true) 274 + do var sanxid = lib.html.sanitize(&co.srv.pool,user(0).xid, true) 275 275 unym:ppush(sanxid) 276 - sanxid:free() end 276 + --sanxid:free() 277 + end 277 278 unym:lpush('" class="id">') 278 279 lib.render.nym(user.ptr,0,&unym,false) 279 280 unym:lpush('</a>') 280 281 var ctlbox = data.view.conf_user_ctl { 281 282 name = unym:finalize(); 282 283 inputcontent = cinpp; 283 284 btns = pstr{'',0}; 284 285 } 285 286 if co.who.id ~= uid and co.who.rights.powers.cred() then 286 - ctlbox.btns = lib.str.acc{}:compose('<a class="button" href="/conf/users/',path(2),'/cred">security & credentials</a>'):finalize() 287 + ctlbox.btns = lib.str.acc{}:pcompose(&co.srv.pool,'<a class="button" href="/conf/users/',path(2),'/cred">security & credentials</a>'):finalize() 287 288 end 288 - var pg: lib.str.acc pg:init(512) 289 + var pg = co:stra(512) 289 290 ctlbox:append(&pg) 290 - ctlbox.name:free() 291 - if ctlbox.btns.ct > 0 then ctlbox.btns:free() end 291 + --ctlbox.name:free() 292 + --if ctlbox.btns.ct > 0 then ctlbox.btns:free() end 292 293 293 294 return pg:finalize() 294 295 end 295 296 else 296 297 var modes = array(P'local', P'remote', P'staff', P'titled', P'peons', P'all') 297 298 var idbuf: int8[lib.math.shorthand.maxlen] 298 - var ulst: lib.str.acc ulst:init(256) 299 + var ulst = co:stra(256) 299 300 var mode: uint8 = mode_local 300 301 var modestr = co:pgetv('show') 301 302 ulst:lpush('<div style="text-align: right"><em>showing ') 302 303 for i=0,[modes.type.N] do 303 304 if modestr:ref() and modes[i]:cmp(modestr) then mode = i end 304 305 end 305 306 for i=0,[modes.type.N] do
Modified render/media-gallery.t from [da27a31f83] to [5c4e9df122].
14 14 var owner = false 15 15 if co.aid ~= 0 and co.who.id == uid then owner = true end 16 16 var ou = co.srv:actor_fetch_uid(uid) 17 17 if not ou then goto e404 end 18 18 do defer ou:free() 19 19 var pfx = pstr.null() 20 20 if not owner then 21 - var pa: lib.str.acc pa:init(32) 21 + var pa = co:stra(32) 22 22 pa:lpush('/') 23 23 if ou(0).origin ~= 0 then pa:lpush('@') end 24 24 pa:push(ou(0).xid,0) 25 25 pfx = pa:finalize() 26 26 end 27 27 28 28 if path.ct >= 3 and path(1):cmp(lib.str.lit'a') then ................................................................................ 31 31 var art = co.srv:artifact_fetch(uid, id) 32 32 if not art then goto e404 end 33 33 if path.ct == 3 then 34 34 -- sniff out the artifact type and display the appropriate viewer 35 35 var artid = cs(art(0).url) 36 36 var btns: lib.str.acc 37 37 if owner then 38 - btns:compose('<a class="neg button" href="',pfx,'/media/a/',artid,'/del">delete</a><a class="button" href="',pfx,'/media/a/',artid,'/edit">alter</a>') 38 + btns:pcompose(&co.srv.pool,'<a class="neg button" href="',pfx,'/media/a/',artid,'/del">delete</a><a class="button" href="',pfx,'/media/a/',artid,'/edit">alter</a>') 39 39 else 40 - btns:compose('<a class="pos button" href="',pfx,'/media/a/',artid,'/collect">collect</a>') 40 + btns:pcompose(&co.srv.pool,'<a class="pos button" href="',pfx,'/media/a/',artid,'/collect">collect</a>') 41 41 end 42 - var btntxt = btns:finalize() defer btntxt:free() 43 - var desc = lib.smackdown.html(pstr{art(0).desc,0}, true) defer desc:free() 42 + var btntxt = btns:finalize() -- defer btntxt:free() 43 + var desc = lib.smackdown.html(&co.srv.pool, pstr{art(0).desc,0}, true) -- defer desc:free() 44 44 var viewerprops = { 45 45 pfx = pfx, desc = desc; 46 46 id = artid; btns = btntxt; 47 47 } 48 48 if lib.str.ncmp(art(0).mime, 'image/', 6) == 0 then 49 49 var view = data.view.media_image(viewerprops) 50 - var pg = view:tostr() 50 + var pg = view:poolstr(&co.srv.pool) 51 51 co:stdpage([lib.srv.convo.page] { 52 52 title = lib.str.plit'media :: image'; 53 53 class = lib.str.plit'media viewer img'; 54 54 cache = false, body = pg; 55 55 }) 56 - pg:free() 56 + --pg:free() 57 57 elseif lib.str.cmp(art(0).mime, 'text/markdown') == 0 then 58 58 var view = data.view.media_text(viewerprops) 59 59 var text, mime = co.srv:artifact_load(id) mime:free() 60 - view.text = lib.smackdown.html(pstr{[rawstring](text.ptr),text.ct}, false) 60 + view.text = lib.smackdown.html(&co.srv.pool, pstr{[rawstring](text.ptr),text.ct}, false) 61 61 text:free() 62 - var pg = view:tostr() 63 - view.text:free() 62 + var pg = view:poolstr(&co.srv.pool) 63 + --view.text:free() 64 64 co:stdpage([lib.srv.convo.page] { 65 65 title = lib.str.plit'media :: text'; 66 66 class = lib.str.plit'media viewer text'; 67 67 cache = false, body = pg; 68 68 }) 69 - pg:free() 69 + --pg:free() 70 70 elseif 71 71 lib.str.ncmp(art(0).mime, 'text/', 5) == 0 or 72 72 lib.str.cmp(art(0).mime, 'application/x-perl') == 0 or 73 73 lib.str.cmp(art(0).mime, 'application/sql') == 0 74 74 -- and so on (we need a mimelib at some point) -- 75 75 then 76 76 var view = data.view.media_text(viewerprops) 77 77 var text, mime = co.srv:artifact_load(id) mime:free() 78 - var san = lib.html.sanitize(pstr{[rawstring](text.ptr),text.ct}, false) 78 + var san = lib.html.sanitize(&co.srv.pool,pstr{[rawstring](text.ptr),text.ct}, false) 79 79 text:free() 80 80 view.text = lib.str.acc{}:compose('<pre>',san,'</pre>'):finalize() 81 81 san:free() 82 82 var pg = view:tostr() 83 83 view.text:free() 84 84 co:stdpage([lib.srv.convo.page] { 85 85 title = lib.str.plit'media :: text'; ................................................................................ 123 123 folders = pstr{'',0}; 124 124 directory = pstr{'',0}; 125 125 images = pstr{'',0}; 126 126 pfx = pfx; 127 127 } 128 128 129 129 if folders.ct > 0 then 130 - var fa: lib.str.acc fa:init(128) 130 + var fa: lib.str.acc fa:pool(&co.srv.pool,128) 131 131 var fldr = co:pgetv('folder') 132 132 for i=0,folders.ct do 133 - var ule = lib.html.urlenc(folders(i), true) defer ule:free() 134 - var san = lib.html.sanitize(folders(i), true) defer san:free() 133 + var ule = lib.html.urlenc(&co.srv.pool,folders(i), true) -- defer ule:free() 134 + var san = lib.html.sanitize(&co.srv.pool,folders(i), true) -- defer san:free() 135 135 fa:lpush('<a href="'):ppush(pfx):lpush('/media?folder='):ppush(ule) 136 136 :lpush('">'):ppush(san):lpush('</a>') 137 137 lib.dbg('checking folder ',{fldr.ptr,fldr.ct},' against ',{folders(i).ptr,folders(i).ct}) 138 138 if fldr:ref() and folders(i):cmp(fldr) 139 139 then folder = folders(i) lib.dbg('folder match ',{fldr.ptr,fldr.ct}) 140 140 else folders(i):free() 141 141 end ................................................................................ 146 146 end 147 147 148 148 if owner then 149 149 view.menu = P'<a class="pos" href="/media/upload">upload</a><hr>' 150 150 end 151 151 152 152 var md = co.srv:artifact_enum_uid(uid, folder) 153 - var gallery: lib.str.acc gallery:init(256) 154 - var files: lib.str.acc files:init(256) 153 + var gallery: lib.str.acc gallery:pool(&co.srv.pool,256) 154 + var files: lib.str.acc files:pool(&co.srv.pool,256) 155 155 for i=0,md.ct do 156 - var desc = lib.smackdown.html(pstr{md(i)(0).desc,0}, true) defer desc:free() 156 + var desc = lib.smackdown.html(&co.srv.pool,pstr{md(i)(0).desc,0}, true) --defer desc:free() 157 157 if lib.str.ncmp(md(i)(0).mime, 'image/', 6) == 0 then 158 158 gallery:lpush('<a class="thumb" href="'):ppush(pfx):lpush('/media/a/') 159 159 :push(md(i)(0).url,0):lpush('"><img src="/file/'):push(md(i)(0).url,0) 160 160 :lpush('"><div class="caption">'):ppush(desc) 161 161 :lpush('</div></a>') 162 162 else 163 - var mime = lib.html.sanitize(pstr{md(i)(0).mime,0}, true) defer mime:free() --just in case 163 + var mime = lib.html.sanitize(&co.srv.pool,pstr{md(i)(0).mime,0}, true) --defer mime:free() --just in case 164 164 files:lpush('<a class="file" href="'):ppush(pfx):lpush('/media/a/') 165 165 :push(md(i)(0).url,0):lpush('"><span class="label">'):ppush(desc) 166 166 :lpush('</span> <span class="mime">'):ppush(mime) 167 167 :lpush('</span></a>') 168 168 end 169 169 md(i):free() 170 170 end ................................................................................ 171 171 172 172 view.images = gallery:finalize() 173 173 view.directory = files:finalize() 174 174 175 175 if acc ~= nil then 176 176 view:append(acc) 177 177 else 178 - lib.dbg('emitting page') 179 - var pg = view:tostr() defer pg:free() 180 - lib.dbg('compiled page') 178 + var pg = view:poolstr(&co.srv.pool) -- defer pg:free() 181 179 co:stdpage([lib.srv.convo.page] { 182 180 title = P'media'; 183 181 class = P'media manager'; 184 182 cache = false; 185 183 body = pg; 186 184 }) 187 - lib.dbg('sent page') 188 185 end 189 186 190 - view.images:free() 191 - view.directory:free() 192 - if view.folders.ct > 0 then view.folders:free() end 187 + --view.images:free() 188 + --view.directory:free() 189 + --if view.folders.ct > 0 then view.folders:free() end 193 190 if folder.ct > 0 then folder:free() end 194 191 if md:ref() then md:free() end 195 192 end 196 - if not owner then pfx:free() end 193 + --if not owner then pfx:free() end 197 194 return end 198 195 199 196 ::e404:: co:complain(404,'media not found','no such media exists on this server') 200 197 end 201 198 202 199 return render_media_gallery
Modified render/nav.t from [0fd87c81ae] to [9f2c55cf5b].
1 1 -- vim: ft=terra 2 2 local terra 3 3 render_nav(co: &lib.srv.convo) 4 - var t: lib.str.acc t:init(64) 4 + var t = co:stra(64) 5 5 if co.who ~= nil or co.srv.cfg.pol_sec == lib.srv.secmode.public then 6 6 t:lpush(' <a accesskey="t" href="/">timeline</a>') 7 7 end 8 8 if co.who ~= nil then 9 9 t:lpush(' <a accesskey="c" href="/compose">compose</a> <a accesskey="p" href="/'):push(co.who.xid,0) 10 10 t:lpush('">profile</a> <a accesskey="m" href="/media">media</a> <a accesskey="o" href="/conf">configure</a> <a accesskey="d" href="/doc">docs</a> <div class="ident">@') 11 11 t:push(co.who.handle,0)
Modified render/notices.t from [99b348e685] to [745afb2f25].
13 13 14 14 if notes.ct == 0 then 15 15 co:complain(200,'no news is good news',"you don't have any notices to review") 16 16 return 17 17 end 18 18 defer notes:free() 19 19 20 - var pg: lib.str.acc pg:init(512) defer pg:free() 21 - var pflink: lib.str.acc pflink:init(64) 22 - var body: lib.str.acc body:init(256) 20 + var pg = co:stra(512) -- defer pg:free() 21 + var pflink = co:stra(64) 22 + var body = co:stra(256) 23 23 var latest: lib.store.timepoint = 0 24 24 for i=0,notes.ct do 25 25 if notes(i).when > latest then latest = notes(i).when end 26 26 var who = co.srv:actor_fetch_uid(notes(i).who) defer who:free() 27 27 if not who then lib.bail('schema integrity violation: nonexistent actor referenced in notification, this is almost certainly an SQL error or bug in the backend implementation') end 28 28 pflink:cue(lib.str.sz(who(0).xid) + 4) 29 29 if who(0).origin == 0 then pflink:lpush('/') ................................................................................ 49 49 n.kind = P'reply' 50 50 n.act = P'replied to your post' 51 51 notweet = false 52 52 end 53 53 else goto skip end 54 54 do var idbuf: int8[lib.math.shorthand.maxlen] 55 55 var idlen = lib.math.shorthand.gen(notes(i).what, idbuf) 56 - var b = lib.smackdown.html(pstr {ptr=what(0).body,ct=0},true) defer b:free() 56 + var b = lib.smackdown.html(&co.srv.pool, pstr {ptr=what(0).body,ct=0},true) --defer b:free() 57 57 body:lpush(' <a class="quote" href="/post/'):push(&idbuf[0],idlen):lpush('">'):ppush(b):lpush('</a>') 58 58 end 59 59 if not notweet then 60 60 var reply = co.srv:post_fetch(notes(i).reply) 61 61 lib.render.tweet(co,reply.ptr,&body) 62 62 reply:free() 63 63 end ................................................................................ 64 64 n.ref = pstr {ptr = body.buf, ct = body.sz} 65 65 66 66 n:append(&pg) 67 67 ::skip:: n.nym:free() 68 68 pflink:reset() 69 69 body:reset() 70 70 end 71 - pflink:free() 71 + --pflink:free() 72 72 pg:lpush('<form method="post"><button name="act" value="clear">clear all notices</button></form>') 73 73 co:livepage([lib.srv.convo.page] { 74 74 title = P'notices', class = P'notices'; 75 75 body = pstr {ptr = pg.buf, ct = pg.sz}; 76 76 cache = false; 77 77 }, latest) 78 78 end 79 79 80 80 return render_notices
Modified render/nym.t from [ea921b8ffe] to [c2ab22760a].
8 8 render_nym(who: &lib.store.actor, scope: uint64, tgt: &lib.str.acc, minimal: bool) 9 9 var acc: lib.str.acc 10 10 var n: &lib.str.acc 11 11 if tgt ~= nil then n = tgt else 12 12 n = &acc 13 13 n:init(128) 14 14 end 15 - var xidsan = lib.html.sanitize(cs(who.xid),false) 15 + 16 + var pool_obj: lib.mem.pool 17 + var pool: &lib.mem.pool 18 + if tgt ~= nil and tgt.pool ~= nil then 19 + pool = tgt.pool 20 + else 21 + pool_obj:init(128) 22 + pool = &pool_obj 23 + end 24 + 25 + var xidsan = lib.html.sanitize(pool,cs(who.xid),false) 16 26 if who.nym ~= nil and who.nym[0] ~= 0 then 17 - var nymsan = lib.html.sanitize(cs(who.nym),false) 27 + var nymsan = lib.html.sanitize(pool,cs(who.nym),false) 18 28 n:lpush('<span class="nym">'):ppush(nymsan) 19 29 :lpush('</span> [<span class="handle">'):ppush(xidsan) 20 30 :lpush('</span>]') 21 - nymsan:free() 31 + --nymsan:free() 22 32 else n:lpush('<span class="handle">'):ppush(xidsan):lpush('</span>') end 23 - xidsan:free() 33 + --xidsan:free() 24 34 25 35 if not minimal then 26 36 if who.epithet ~= nil then 27 - var episan = lib.html.sanitize(cs(who.epithet),false) 37 + var episan = lib.html.sanitize(pool,cs(who.epithet),false) 28 38 n:lpush('<span class="epithet">'):ppush(episan):lpush('</span>') 29 - episan:free() 39 + --episan:free() 30 40 end 31 41 end 32 42 43 + if pool == &pool_obj then pool:free() end 33 44 -- TODO: if scope == chat room then lookup titles in room member db 34 45 if tgt == nil then 35 46 return n:finalize() 36 47 else return pstr.null() end 37 48 end 38 49 39 50 return render_nym
Modified render/profile.t from [3525ca58bc] to [a033243372].
9 9 co: &lib.srv.convo, 10 10 actor: &lib.store.actor, 11 11 relationship: &lib.store.relationship 12 12 ): pstr 13 13 var aux: lib.str.acc 14 14 var followed = false -- FIXME 15 15 if co.aid ~= 0 and co.who.id == actor.id then 16 - aux:compose('<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>') 16 + aux:pcompose(&co.srv.pool,'<a accesskey="a" class="button" href="/conf/profile?go=/@',actor.handle,'">alter</a>') 17 17 elseif co.aid ~= 0 then 18 18 if not relationship.rel.follow() then 19 - aux:compose('<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>') 19 + aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="pos" name="act" value="follow">follow</button>') 20 20 elseif relationship.rel.follow() then 21 - aux:compose('<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>') 21 + aux:pcompose(&co.srv.pool,'<button accesskey="f" method="post" class="neg" name="act" value="unfollow">unfollow</button>') 22 22 end 23 23 aux:lpush('<a accesskey="h" class="button" href="/'):push(actor.xid,0):lpush('/chat">chat</a>') 24 24 if co.who.rights.powers:affect_users() and co.who:overpowers(actor) then 25 25 aux:lpush('<a accesskey="n" class="button" href="/'):push(actor.xid,0):lpush('/ctl">control</a>') 26 26 end 27 27 else 28 - aux:compose('<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>') 28 + aux:pcompose(&co.srv.pool,'<a accesskey="f" class="button" href="/', actor.xid, '/follow">remote follow</a>') 29 29 end 30 30 var auxp = aux:finalize() 31 31 var timestr: int8[26] lib.osclock.ctime_r(&actor.knownsince, ×tr[0]) 32 32 33 33 var strfbuf: int8[28*4] 34 34 var stats = co.srv:actor_stats(actor.id) 35 35 var sn_posts = cs(lib.math.decstr_friendly(stats.posts, &strfbuf[ [strfbuf.type.N - 1] ])) 36 36 var sn_follows = cs(lib.math.decstr_friendly(stats.follows, sn_posts.ptr - 1)) 37 37 var sn_followers = cs(lib.math.decstr_friendly(stats.followers, sn_follows.ptr - 1)) 38 38 var sn_mutuals = cs(lib.math.decstr_friendly(stats.mutuals, sn_followers.ptr - 1)) 39 39 var bio = lib.str.plit '<em style="opacity:0.6">tall, dark, and mysterious</em>' 40 40 if actor.bio ~= nil then 41 - bio = lib.smackdown.html(cs(actor.bio),false) 41 + bio = lib.smackdown.html(&co.srv.pool,cs(actor.bio),false) 42 42 end 43 43 var fullname = lib.render.nym(actor,0,nil,false) defer fullname:free() 44 - var comments: lib.str.acc comments:init(64) 44 + var comments: lib.str.acc comments:pool(&co.srv.pool,64) 45 45 46 46 if co.srv.cfg.master == actor.id then 47 47 var foundertxt = lib.str.plit 'founder' 48 48 if co.srv.cfg.ui_cue_founder:ref() then 49 49 if co.srv.cfg.ui_cue_founder.ct == 0 -- empty string, suppress field 50 50 then foundertxt = pstr.null() 51 51 else foundertxt = co.srv.cfg.ui_cue_founder ................................................................................ 94 94 95 95 remarks = ''; 96 96 97 97 auxbtn = auxp; 98 98 } 99 99 if comments.sz > 0 then profile.remarks = comments:finalize() end 100 100 101 - var ret = profile:tostr() 102 - auxp:free() 103 - if actor.bio ~= nil then bio:free() end 101 + var ret = profile:poolstr(&co.srv.pool) 102 + -- auxp:free() 103 + --if actor.bio ~= nil then bio:free() end 104 104 if comments.sz > 0 then profile.remarks:free() end 105 105 return ret 106 106 end 107 107 108 108 return render_profile
Modified render/timeline.t from [ab5808172b] to [7375f87c90].
22 22 from_time = stoptime; 23 23 to_idx = 64; 24 24 }) 25 25 elseif mode == modes.fediglobal then 26 26 elseif mode == modes.circle then 27 27 end 28 28 29 - var acc: lib.str.acc acc:init(1024) 29 + var acc: lib.str.acc acc:pool(&co.srv.pool,1024) 30 30 acc:lpush('<div id="tl" data-live="10">') 31 31 var newest: lib.store.timepoint = 0 32 32 for i = 0, posts.sz do 33 33 lib.render.tweet(co, posts(i).ptr, &acc) 34 34 var t = lib.math.biggest(lib.math.biggest(posts(i).ptr.posted, posts(i).ptr.discovered),posts(i).ptr.edited) 35 35 if t > newest then newest = t end 36 36 posts(i):free() ................................................................................ 41 41 var doc = [lib.srv.convo.page] { 42 42 title = lib.str.plit'timeline'; 43 43 body = acc:finalize(); 44 44 class = lib.str.plit'timeline'; 45 45 cache = false; 46 46 } 47 47 co:livepage(doc,newest) 48 - doc.body:free() 48 + --doc.body:free() 49 49 end 50 50 return render_timeline
Modified render/tweet-page.t from [c0b864229b] to [304c6c3aff].
26 26 render_tweet_page( 27 27 co: &lib.srv.convo, 28 28 path: lib.mem.ptr(pref), 29 29 p: &lib.store.post 30 30 ): {} 31 31 var livetime = co.srv:thread_latest_arrival_calc(p.id) 32 32 33 - var pg: lib.str.acc pg:init(256) 33 + var pg = co:stra(256) 34 34 pg:lpush('<div data-live="10">') -- make the OP refresh too 35 35 lib.render.tweet(co, p, &pg) 36 36 pg:lpush('</div>') 37 37 38 38 if co.aid ~= 0 then 39 39 pg:lpush('<form class="action-bar" method="post">') 40 40 if not co.srv:post_liked_uid(co.who.id, p.id) ................................................................................ 58 58 render_tweet_replies(co, &pg, p.id) 59 59 pg:lpush('</div>') 60 60 61 61 if co.aid ~= 0 and co.who.rights.powers.post() then 62 62 lib.render.compose(co, nil, &pg) 63 63 end 64 64 65 - var ppg = pg:finalize() defer ppg:free() 65 + var ppg = pg:finalize() --defer ppg:free() 66 66 co:livepage([lib.srv.convo.page] { 67 67 title = lib.str.plit 'post'; cache = false; 68 68 class = lib.str.plit 'post'; body = ppg; 69 69 }, livetime) 70 70 71 71 -- TODO display conversation 72 72 -- perhaps display descendant nodes here, and have a link to the top of the whole tree? 73 73 end 74 74 75 75 return render_tweet_page
Modified render/tweet.t from [83917dbbe9] to [57f4f6bb5e].
34 34 retweeter = co.actorcache:insert(co.srv:actor_fetch_uid(p.rtdby)).ptr 35 35 end 36 36 37 37 ::foundauth:: 38 38 var timestr: int8[26] lib.osclock.ctime_r(&p.posted, ×tr[0]) 39 39 for i=0,26 do if timestr[i] == @'\n' then timestr[i] = 0 break end end -- 🙄 40 40 41 - var bhtml = lib.smackdown.html([lib.mem.ptr(int8)] {ptr=p.body,ct=0},false) 42 - defer bhtml:free() 41 + var bhtml = lib.smackdown.html(&co.srv.pool, [lib.mem.ptr(int8)] {ptr=p.body,ct=0},false) 42 + --defer bhtml:free() 43 43 44 44 var idbuf: int8[lib.math.shorthand.maxlen] 45 45 var idlen = lib.math.shorthand.gen(p.id, idbuf) 46 - var permalink: lib.str.acc permalink:compose('/post/',{idbuf,idlen}) 46 + var permalink: lib.str.acc permalink:pool(&co.srv.pool, 7+idlen):lpush('/post/'):push(idbuf,idlen) 47 47 var fullname = lib.render.nym(author,0,nil, false) defer fullname:free() 48 48 var tpl = data.view.tweet { 49 49 text = bhtml; 50 50 subject = cs(lib.coalesce(p.subject,'')); 51 51 nym = fullname; 52 52 when = cs(×tr[0]); 53 53 avatar = cs(author.avatar); ................................................................................ 61 61 var parent = co.srv:post_fetch(p.parent) defer parent:free() 62 62 if not parent then 63 63 lib.bail('schema integrity violation - could not match post to parent') 64 64 end 65 65 var pauth = co.srv:actor_fetch_uid(parent(0).author) defer pauth:free() 66 66 var pidbuf: int8[lib.math.shorthand.maxlen] 67 67 var pidlen = lib.math.shorthand.gen(p.parent, pidbuf) 68 - var pa: lib.str.acc pa:init(128) 68 + var pa: lib.str.acc pa:pool(&co.srv.pool, 128) 69 69 pa:lpush('<small>in reply to <a class="username" href="/post/'):push(&pidbuf[0],pidlen):lpush('">') 70 70 lib.render.nym(pauth.ptr,0,&pa,true) 71 71 pa:lpush('</a></small>') 72 72 tpl.extra = pa:finalize() 73 73 end 74 74 if p.rts + p.likes > 0 then 75 - var s: lib.str.acc s:init(128) 75 + var s: lib.str.acc s:pool(&co.srv.pool,128) 76 76 s:lpush('<div class="stats">') 77 77 if p.rts > 0 then s:lpush('<div class="rt">' ):dpush(p.rts ):lpush('</div>') end 78 78 if p.likes > 0 then s:lpush('<div class="like">'):dpush(p.likes):lpush('</div>') end 79 79 s:lpush('</div>') 80 80 tpl.stats = s:finalize() 81 81 end 82 82 ................................................................................ 91 91 attrcur = lib.str.cpy(attrcur, '"') 92 92 end 93 93 if co.aid ~= 0 and p.author == co.who.id then attrcur = lib.str.cpy(attrcur, ' data-own') end 94 94 if retweeter ~= nil then attrcur = lib.str.cpy(attrcur, ' data-rt') end 95 95 96 96 if attrcur ~= &attrbuf[0] then tpl.attr = &attrbuf[0] end 97 97 98 - defer tpl.permalink:free() 98 + --defer tpl.permalink:free() 99 99 if acc ~= nil then 100 100 if retweeter ~= nil then push_promo_header(co, acc, retweeter, p.rtact) end 101 101 tpl:append(acc) 102 102 if retweeter ~= nil then acc:lpush('</div>') end 103 - if p.rts + p.likes > 0 then tpl.stats:free() end 104 - if tpl.extra.ct > 0 then tpl.extra:free() end 103 + --if p.rts + p.likes > 0 then tpl.stats:free() end 104 + --if tpl.extra.ct > 0 then tpl.extra:free() end 105 105 return [lib.mem.ptr(int8)]{ptr=nil,ct=0} 106 106 end 107 107 108 108 if retweeter ~= nil then 109 - var rta: lib.str.acc rta:init(512) 109 + var rta: lib.str.acc rta:pool(&co.srv.pool,512) 110 110 push_promo_header(co, &rta, retweeter, p.rtact) 111 111 tpl:append(&rta) rta:lpush('</div>') 112 - if tpl.extra.ct > 0 then tpl.extra:free() end 112 + --if tpl.extra.ct > 0 then tpl.extra:free() end 113 113 return rta:finalize() 114 114 else 115 - var txt = tpl:tostr() 116 - if tpl.extra.ct > 0 then tpl.extra:free() end 117 - if p.rts + p.likes > 0 then tpl.stats:free() end 115 + var txt = tpl:poolstr(&co.srv.pool) 116 + --if tpl.extra.ct > 0 then tpl.extra:free() end 117 + --if p.rts + p.likes > 0 then tpl.stats:free() end 118 118 return txt 119 119 end 120 120 end 121 121 return render_tweet
Modified render/user-page.t from [e4691ec838] to [be37fdb666].
9 9 if co.aid ~= 0 and co.who.id == actor.id then 10 10 ti:compose('my profile') 11 11 else 12 12 ti:compose('profile :: ', actor.handle) 13 13 end 14 14 var tiptr = ti:finalize() 15 15 16 - var acc: lib.str.acc acc:init(1024) 17 - var pftxt = lib.render.profile(co,actor,relationship) defer pftxt:free() 16 + var acc: lib.str.acc acc:pool(&co.srv.pool, 1024) 17 + var pftxt = lib.render.profile(co,actor,relationship) --defer pftxt:free() 18 18 acc:ppush(pftxt) 19 19 20 20 var stoptime = lib.osclock.time(nil) 21 21 var posts = co.srv:post_enum_author_uid(actor.id, lib.store.range { 22 22 mode = 1; -- T->I 23 23 from_time = stoptime; 24 24 to_idx = 64; ................................................................................ 39 39 co:livepage([lib.srv.convo.page] { 40 40 title = tiptr; body = bdf; 41 41 class = lib.str.plit 'profile'; 42 42 cache = false; 43 43 }, newest) 44 44 45 45 tiptr:free() 46 - bdf:free() 46 + --bdf:free() 47 47 end 48 48 49 49 return render_userpage
Modified route.t from [2b1fe64d41] to [a232000d86].
248 248 else 249 249 conf = data.view.confirm { 250 250 title = lib.str.plit 'cancel retweet'; 251 251 query = lib.str.plit 'are you sure you want to undo this retweet?'; 252 252 cancel = lib.str.plit'/'; 253 253 } 254 254 end 255 - var body = conf:tostr() defer body:free() 255 + var fr = co.srv.pool:frame() 256 + var body = conf:poolstr(&co.srv.pool) --defer body:free() 256 257 co:stdpage([lib.srv.convo.page] { 257 258 title = lib.str.plit 'post :: delete'; 258 259 class = lib.str.plit 'query'; 259 260 body = body; cache = false; 260 261 }) 262 + co.srv.pool:reset(fr) 261 263 return 262 264 elseif meth == method.post then 263 265 var act = co:ppostv('act') 264 266 if act:cmp(lib.str.plit 'confirm') then 265 267 if post:ref() then 266 268 post(0).source:post_destroy(post(0).id) 267 269 elseif rt.kind ~= 0 then ................................................................................ 513 515 514 516 terra http.media_manager(co: &lib.srv.convo, path: hpath, meth: method.t, uid: uint64) 515 517 if co.aid ~= 0 and co.who.id == uid and path.ct == 2 and path(1):cmp(lib.str.lit'upload') and co.who.rights.powers.artifact() then 516 518 if meth == method.get then 517 519 var view = data.view.media_upload { 518 520 folders = '' 519 521 } 520 - var pg = view:tostr() defer pg:free() 522 + var pg = view:poolstr(&co.srv.pool) -- defer pg:free() 521 523 co:stdpage([lib.srv.convo.page] { 522 524 title = lib.str.plit'media :: upload'; 523 525 class = lib.str.plit'media upload'; 524 526 cache = false; body = pg; 525 527 }) 526 528 elseif meth == method.post_file then 527 529 var desc = pstring.null()
Modified smackdown.t from [e99ea3e622] to [ad4d039b1c].
52 52 local terra scanline_wordend(l: rawstring, max: intptr, n: rawstring, nc: intptr) 53 53 var sl = scanline(l,max,n,nc) 54 54 if sl == nil then return nil else sl = sl + nc end 55 55 if sl >= l+max or not isws(@(sl-1)) then return sl-nc end 56 56 return nil 57 57 end 58 58 59 -terra m.html(input: pstr, firstline: bool) 59 +terra m.html(pool: &lib.mem.pool, input: pstr, firstline: bool) 60 60 if input.ptr == nil then return pstr.null() end 61 61 if input.ct == 0 then input.ct = lib.str.sz(input.ptr) end 62 62 63 - var md = lib.html.sanitize(input,false) 63 + var md = lib.html.sanitize(pool,input,false) 64 64 65 - var styled: lib.str.acc styled:init(md.ct) 65 + var styled: lib.str.acc styled:pool(pool,md.ct) 66 66 67 67 do var i = 0 while i < md.ct do 68 68 --var wordstart = (i == 0 or isws(md.ptr[i-1])) 69 69 --var wordend = (i == md.ct - 1 or isws(md.ptr[i+1])) 70 70 var wordstart = (i + 1 < md.ct and not isws(md.ptr[i+1])) 71 71 var wordend = (i == md.ct - 1 or not isws(md.ptr[i-1])) 72 72 ................................................................................ 118 118 goto skip 119 119 end 120 120 end 121 121 122 122 ::fallback::styled:push(here,1) -- :/ 123 123 i = i + 1 124 124 ::skip::end end 125 - md:free() 125 + --md:free() 126 126 127 127 -- we make two passes: the first detects and transforms inline elements, 128 128 -- the second carries out block-level organization 129 129 130 - var html: lib.str.acc html:init(styled.sz) 130 + var html: lib.str.acc html:pool(pool,styled.sz) 131 131 var s = state { 132 132 segt = segt.none; 133 133 bqlvl = 0; 134 134 curpos = md.ptr; 135 135 blockstart = nil; 136 136 } 137 137 while s.curpos < md.ptr + md.ct do 138 138 s.curpos = s.curpos + 1 139 139 end 140 140 141 - html:free() -- JUST FOR NOW 141 + --html:free() -- JUST FOR NOW 142 142 return styled:finalize() 143 143 end 144 144 145 145 return m
Modified srv.t from [80adbc5ad3] to [854410a8ca].
5 5 local struct srv 6 6 local struct cfgcache { 7 7 secret: pstring 8 8 pol_sec: secmode.t 9 9 pol_reg: bool 10 10 credmgd: bool 11 11 maxupsz: intptr 12 + poolinitsz: intptr 12 13 instance: pstring 13 14 overlord: &srv 14 15 ui_cue_staff: pstring 15 16 ui_cue_founder: pstring 16 17 ui_hue: uint16 17 18 nranks: uint16 18 19 maxinvites: uint16 ................................................................................ 20 21 } 21 22 local struct srv { 22 23 sources: lib.mem.ptr(lib.store.source) 23 24 webmgr: lib.net.mg_mgr 24 25 webcon: &lib.net.mg_connection 25 26 cfg: cfgcache 26 27 id: rawstring 28 + pool: lib.mem.pool 27 29 } 28 30 29 31 terra cfgcache:free() -- :/ 30 32 self.secret:free() 31 33 self.instance:free() 32 34 self.ui_cue_staff:free() 33 35 self.ui_cue_founder:free() ................................................................................ 306 308 307 309 terra convo:confirm(title: pstring, msg: pstring, cancel: pstring) 308 310 var conf = data.view.confirm { 309 311 title = title; 310 312 query = msg; 311 313 cancel = cancel; 312 314 } 313 - var ti: lib.str.acc ti:compose('confirm :: ', title) 314 - var body = conf:tostr() defer body:free() 315 + var ti: lib.str.acc ti:pcompose(&self.srv.pool,'confirm :: ', title) 316 + var body = conf:poolstr(&self.srv.pool) -- defer body:free() 315 317 var cf = [convo.page] { 316 318 title = ti:finalize(); 317 319 class = lib.str.plit 'query'; 318 320 body = body; cache = false; 319 321 } 320 322 self:stdpage(cf) 321 - cf.title:free() 323 + --cf.title:free() 324 +end 325 + 326 +terra convo:stra(sz: intptr) -- convenience function 327 + var s: lib.str.acc 328 + s:pool(&self.srv.pool,sz) 329 + return s 322 330 end 323 331 324 332 convo.methods.assertpow = macro(function(self, pow) 325 333 return quote 326 334 var ok = true 327 335 if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then 328 336 ok = false ................................................................................ 330 338 end 331 339 in ok end 332 340 end) 333 341 334 342 -- CALL ONLY ONCE PER VAR 335 343 terra convo:postv(name: rawstring) 336 344 if self.varbuf.ptr == nil then 337 - self.varbuf = lib.mem.heapa(int8, self.msg.body.len + self.msg.query.len) 345 + self.varbuf = self.srv.pool:alloc(int8, self.msg.body.len + self.msg.query.len) 338 346 self.vbofs = self.varbuf.ptr 339 347 end 340 348 var o = lib.net.mg_http_get_var(&self.msg.body, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr)) 341 349 if o > 0 then 342 350 var r = self.vbofs 343 351 self.vbofs = self.vbofs + o + 1 344 352 @(self.vbofs - 1) = 0 ................................................................................ 349 357 terra convo:ppostv(name: rawstring) 350 358 var s,l = self:postv(name) 351 359 return pstring { ptr = s, ct = l } 352 360 end 353 361 354 362 terra convo:getv(name: rawstring) 355 363 if self.varbuf.ptr == nil then 356 - self.varbuf = lib.mem.heapa(int8, self.msg.query.len + self.msg.body.len) 364 + self.varbuf = self.srv.pool:alloc(int8, self.msg.query.len + self.msg.body.len) 357 365 self.vbofs = self.varbuf.ptr 358 366 end 359 367 var o = lib.net.mg_http_get_var(&self.msg.query, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr)) 360 368 if o > 0 then 361 369 var r = self.vbofs 362 370 self.vbofs = self.vbofs + o + 1 363 371 @(self.vbofs - 1) = 0 ................................................................................ 551 559 var livelast_p = lib.http.findheader(msg, 'X-Live-Last-Arrival') 552 560 if livelast_p ~= nil and livelast_p.ptr ~= nil then 553 561 var ll, ok = lib.math.decparse(pstring{ptr = livelast_p.ptr, ct = livelast_p.ct - 1}) 554 562 if ok then co.live_last = ll end 555 563 end 556 564 557 565 558 - var uridec = lib.mem.heapa(int8, msg.uri.len) defer uridec:free() 566 + var uridec = server.pool:alloc(int8, msg.uri.len) 559 567 var urideclen = lib.net.mg_url_decode(msg.uri.ptr, msg.uri.len, uridec.ptr, uridec.ct, 1) 560 568 561 569 var uri = uridec 562 570 if urideclen == -1 then 563 571 for i = 0,msg.uri.len do 564 572 if msg.uri.ptr[i] == @'+' 565 573 then uri.ptr[i] = @' ' ................................................................................ 677 685 bsr:free() 678 686 upmap:free() 679 687 end 680 688 end 681 689 end 682 690 683 691 route.dispatch_http(&co, uri, co.method) 692 + 693 + ::fail:: 684 694 if co.uploads.run > 0 then 685 695 for i=0,co.uploads.sz do 686 696 co.uploads(i).filename:free() 687 697 co.uploads(i).field:free() 688 698 end 689 699 co.uploads:free() 690 700 end 691 701 692 - ::fail:: 693 702 if co.aid ~= 0 then lib.mem.heapf(co.who) end 694 - if co.varbuf.ptr ~= nil then co.varbuf:free() end 695 - if co.navbar.ptr ~= nil then co.navbar:free() end 703 + -- if co.varbuf.ptr ~= nil then co.varbuf:free() end 704 + -- if co.navbar.ptr ~= nil then co.navbar:free() end 696 705 co.actorcache:free() 706 + server.pool:clear() 697 707 end 698 708 end 699 709 end; 700 710 } 701 711 702 712 local terra cfg(s: &srv, befile: rawstring) 703 713 lib.report('configuring backends from ', befile) ................................................................................ 853 863 lib.bail('could not connect to any data sources!') 854 864 end 855 865 end 856 866 857 867 terra srv:start(iname: rawstring) 858 868 self:conprep(lib.store.prepmode.full) 859 869 self.cfg:init(self) 870 + self.pool:init(self.cfg.poolinitsz) 860 871 var dbbind = self:conf_get('bind') 861 872 if iname == nil then iname = lib.proc.getenv('parsav_instance') end 862 873 if iname == nil then 863 874 self.id = self.cfg.instance.ptr; 864 875 -- let this leak -- it'll be needed for the lifetime of the process anyway 865 876 else self.id = iname end 866 877 ................................................................................ 890 901 terra srv:shutdown() 891 902 lib.net.mg_mgr_free(&self.webmgr) 892 903 for i=0,self.sources.ct do var src = self.sources.ptr + i 893 904 lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')') 894 905 src:close() 895 906 end 896 907 self.sources:free() 908 + self.pool:free() 897 909 end 898 910 899 911 terra cfgcache:cfint(name: rawstring, default: intptr) 900 912 var str = self.overlord:conf_get(name) 901 913 if str.ptr ~= nil then 902 914 var i,ok = lib.math.decparse(str) 903 915 if ok then default = i else 904 916 lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected integer; using default value instead') 905 917 end 906 918 str:free() 919 + end 920 + return default 921 +end 922 + 923 +terra cfgcache:cffsz(name: rawstring, default: intptr) 924 + var str = self.overlord:conf_get(name) 925 + if str:ref() then 926 + var sz, ok = lib.math.fsz_parse(str) 927 + if ok then default = sz else 928 + lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected byte length; using default value instead') 929 + end 930 + str:free() 907 931 end 908 932 return default 909 933 end 910 934 911 935 terra cfgcache:cfbool(name: rawstring, default: bool) 912 936 var str = self.overlord:conf_get(name) 913 937 if str.ptr ~= nil then ................................................................................ 937 961 if lib.str.cmp(sreg.ptr, 'managed') == 0 938 962 then self.credmgd = true 939 963 else self.credmgd = false 940 964 end 941 965 sreg:free() 942 966 end end 943 967 944 - do self.maxupsz = [1024 * 100] -- 100 kilobyte default 945 - var sreg = self.overlord:conf_get('maximum-artifact-size') 946 - if sreg:ref() then 947 - var sz, ok = lib.math.fsz_parse(sreg) 948 - if ok then self.maxupsz = sz else 949 - lib.warn('invalid configuration value for maximum-artifact-size; keeping default 100K upload limit') 950 - end 951 - sreg:free() end 952 - end 968 + self.maxupsz = self:cffsz('maximum-artifact-size', [1024 * 100]) -- 100 kilobyte default 969 + self.poolinitsz = self:cffsz('server-pool-size-initial', [1024 * 10]) -- 10 kilobyte default 953 970 954 971 self.pol_sec = secmode.lockdown 955 972 var smode = self.overlord:conf_get('policy-security') 956 973 if smode.ptr ~= nil then 957 974 if lib.str.cmp(smode.ptr, 'public') == 0 then 958 975 self.pol_sec = secmode.public 959 976 elseif lib.str.cmp(smode.ptr, 'private') == 0 then ................................................................................ 970 987 self.nranks = self:cfint('user-ranks',10) 971 988 self.maxinvites = self:cfint('max-invites',64) 972 989 973 990 var webmaster = self.overlord:conf_get('master') 974 991 if webmaster:ref() then defer webmaster:free() 975 992 var wma = self.overlord:actor_fetch_xid(webmaster) 976 993 if not wma then 977 - lib.warn('the webmaster specified in the configuration store does not seem to exist or is not known to this instance; preceding as if no master defined. if the master is a remote user, you can rectify this with the `actor ',{webmaster.ptr,webmaster.ct},' instantiate` and `conf refresh` commands') 994 + lib.warn('the webmaster specified in the configuration store does not seem to exist or is not known to this instance; preceding as if no master defined. if the master is a remote user, you can rectify this with the `actor "',{webmaster.ptr,webmaster.ct},'" instantiate` and `conf refresh` commands') 978 995 else 979 996 self.master = wma(0).id 980 997 wma:free() 981 998 end 982 999 end 983 1000 984 1001 self.ui_cue_staff = self.overlord:conf_get('ui-profile-cue-staff')
Modified str.t from [d98a573fe7] to [89921fa130].
107 107 end 108 108 109 109 struct m.acc { 110 110 buf: rawstring 111 111 sz: intptr 112 112 run: intptr 113 113 space: intptr 114 + pool: &lib.mem.pool 114 115 } 115 116 116 117 terra m.cdowncase(c: int8) 117 118 if c >= @'A' and c <= @'Z' then 118 119 return c + (@'a' - @'A') 119 120 else return c end 120 121 end ................................................................................ 127 128 128 129 local terra biggest(a: intptr, b: intptr) 129 130 if a > b then return a else return b end 130 131 end 131 132 132 133 terra m.acc:init(run: intptr) 133 134 --lib.dbg('initializing string accumulator') 135 + self.pool = nil 134 136 if run == 0 then 135 137 lib.warn('attempted to allocate zero-length string accumulator') 136 138 self.buf = nil 137 139 else 138 140 self.buf = [rawstring](lib.mem.heapa_raw(run)) 139 141 if self.buf == nil then 140 142 lib.warn('string buffer allocation failed, very little memory availble') ................................................................................ 141 143 end 142 144 end 143 145 self.run = lib.trn(self.buf == nil, 0, run) 144 146 self.space = self.run 145 147 self.sz = 0 146 148 return self 147 149 end; 150 + 151 +terra m.acc:pool(pool: &lib.mem.pool, run: intptr) 152 + self.buf = [&int8](pool:alloc_bytes(run)) 153 + self.pool = pool 154 + self.run = run 155 + self.space = self.run 156 + self.sz = 0 157 + return self 158 +end 148 159 149 160 terra m.acc:free() 150 161 --lib.dbg('freeing string accumulator') 162 + if self.pool ~= nil then 163 + lib.dbg('attempted to free pooled string accumulator; use frame-reset instead') 164 + return 165 + end 151 166 if self.buf ~= nil and self.space > 0 then 152 167 lib.mem.heapf(self.buf) 153 168 end 154 169 end; 155 170 156 171 terra m.acc:crush() 157 172 --lib.dbg('crushing string accumulator') 173 + if self.pool ~= nil then return self end -- no point unless at end of buffer 158 174 self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.sz)) 159 175 self.space = self.sz 160 176 return self 161 177 end; 162 178 163 179 terra m.acc:finalize() 164 180 --lib.dbg('finalizing string accumulator') ................................................................................ 169 185 self.buf = nil 170 186 self.sz = 0 171 187 return pt 172 188 end; 173 189 174 190 terra m.acc:cue(sz: intptr) 175 191 if sz <= self.run then return end 192 + var curspace = self.space 176 193 self.run = sz 177 194 if self.space - self.sz < self.run then 178 195 self.space = self.sz + self.run 179 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 196 + if self.pool ~= nil then 197 + self.buf = [&int8](self.pool:realloc_bytes(self.buf, curspace, self.space)) 198 + else 199 + self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 200 + end 180 201 end 181 202 end 182 203 183 204 terra m.acc:reset() -- semantic convenience function 184 205 self.sz = 0 185 206 end 186 207 ................................................................................ 189 210 if str == nil then return self end 190 211 --if str[len - 1] == 0xA then llen = llen - 1 end -- don't display newlines in debug output 191 212 -- lib.dbg('pushing "',{str,llen},'" onto accumulator') 192 213 if self.buf == nil then self:init(self.run) end 193 214 if self.buf == nil then lib.warn('attempted to push string onto unallocated accumulator') return self end 194 215 if len == 0 then len = m.sz(str) end 195 216 if len >= self.space - self.sz then 196 - self.space = self.space + biggest(self.run,len + 1) 197 - self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 217 + self:cue(self.space + biggest(self.run,len + 1)) 218 + --self.space = self.space + biggest(self.run,len + 1) 219 + --self.buf = [rawstring](lib.mem.heapr_raw(self.buf, self.space)) 198 220 end 199 221 lib.mem.cpy(self.buf + self.sz, str, len) 200 222 self.sz = self.sz + len 201 223 self.buf[self.sz] = 0 202 224 return self 203 225 end; 204 226 ................................................................................ 242 264 return `self:push([str:asvalue()], [#(str:asvalue())]) end) 243 265 m.acc.methods.ppush = terra(self: &m.acc, str: lib.mem.ptr(int8)) 244 266 self:push(str.ptr, str.ct) return self end; 245 267 m.acc.methods.rpush = terra(self: &m.acc, str: lib.mem.ref(int8)) 246 268 self:push(str.ptr, str.ct) return self end; 247 269 m.acc.methods.merge = terra(self: &m.acc, str: lib.mem.ptr(int8)) 248 270 self:push(str.ptr, str.ct) str:free() return self end; 249 -m.acc.methods.compose = macro(function(self, ...) 271 +local composefn = function(call, ...) 250 272 local minlen = 0 251 273 local pstrs = {} 252 274 for i,v in ipairs{...} do 253 275 if type(v) == 'table' then 254 276 local gl = 16 -- guess wildly 255 277 if v.tree and v.tree.type.convertible == 'tuple' then 256 278 pstrs[#pstrs+1] = {str = `v._0, len = `v._1} ................................................................................ 263 285 else pstrs[#pstrs+1] = {str = v, len = 0} end 264 286 minlen = minlen + gl 265 287 elseif type(v) == 'string' then 266 288 pstrs[#pstrs+1] = {str = v, len = #v} 267 289 minlen = minlen + #v + 1 268 290 else error('invalid type in compose expression') end 269 291 end 270 - local call = `self:init(minlen) 292 + call = call(minlen) --`self:init(minlen) 271 293 for i,v in ipairs(pstrs) do 272 294 call = `[call]:push([v.str],[v.len]) 273 295 end 274 296 return call 297 +end 298 +m.acc.methods.compose = macro(function(self, ...) 299 + return composefn(function(minlen) return `self:init(minlen) end, ...) 300 +end) 301 +m.acc.methods.pcompose = macro(function(self, pool, ...) 302 + return composefn(function(minlen) return `self:pool(pool,minlen) end, ...) 275 303 end) 304 + 276 305 m.acc.metamethods.__lshift = terralib.overloadedfunction('(<<)', { 277 306 terra(self: &m.acc, str: rawstring) return self: push(str,0) end; 278 307 terra(self: &m.acc, str: lib.mem.ptr(int8)) return self:ppush(str ) end; 279 308 }) 280 309 281 310 m.box = terralib.memoize(function(ty) 282 311 local b = struct {
Modified tpl.t from [9f68e11c52] to [db48a650e7].
89 89 end 90 90 91 91 local copiers = {} 92 92 local senders = {} 93 93 local appenders = {} 94 94 local symtxt = symbol(lib.mem.ptr(int8)) 95 95 local cpypos = symbol(&opaque) 96 + local pool = symbol(&lib.mem.pool) 96 97 local accumulator = symbol(&lib.str.acc) 97 98 local destcon = symbol(&lib.net.mg_connection) 98 99 for idx, seg in ipairs(segs) do 99 100 copiers[#copiers+1] = quote [cpypos] = lib.mem.cpy([cpypos], [&opaque]([seg]), [#seg]) end 100 101 senders[#senders+1] = quote lib.net.mg_send([destcon], [seg], [#seg]) end 101 102 appenders[#appenders+1] = quote [accumulator]:push([seg], [#seg]) end 102 103 if fields[idx] and fields[idx].mode then 103 104 local f = fields[idx] 104 105 local fp = `symself.[f.key] 105 106 copiers[#copiers+1] = quote 106 107 if fp.ct > 0 then 107 - var san = lib.html.sanitize(fp, [f.mode == ':']) 108 + var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 108 109 [cpypos] = lib.mem.cpy([cpypos], [&opaque](san.ptr), san.ct) 109 110 --san:free() 110 111 end 111 112 end 112 113 senders[#senders+1] = quote 113 114 if fp.ct > 0 then 114 - var san = lib.html.sanitize(fp, [f.mode == ':']) 115 + var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 115 116 lib.net.mg_send([destcon], san.ptr, san.ct) 116 117 --san:free() 117 118 end 118 119 end 119 120 appenders[#appenders+1] = quote 120 121 if fp.ct > 0 then 121 - var san = lib.html.sanitize(fp, [f.mode == ':']) 122 + var san = lib.html.sanitize(pool, fp, [f.mode == ':']) 122 123 [accumulator]:ppush(san) 123 124 --san:free() 124 125 end 125 126 end 126 127 elseif fields[idx] then 127 128 local f = fields[idx] 128 129 local fp = `symself.[f.key] ................................................................................ 139 140 appenders[#appenders+1] = quote 140 141 if fp.ct > 0 then [accumulator]:ppush(fp) end 141 142 end 142 143 end 143 144 end 144 145 145 146 local tid = tplspec.id or '<anonymous>' 147 + rec.methods.poolstr = terra([symself],[pool]) 148 + lib.dbg(['pooling template ' .. tid]) 149 + [tallyup] 150 + var [symtxt] = pool:alloc(int8, [runningtally]) 151 + var [cpypos] = [&opaque](symtxt.ptr) 152 + [copiers] 153 + @[&int8](cpypos) = 0 154 + symtxt.ct = [&int8](cpypos) - symtxt.ptr 155 + return symtxt 156 + end 146 157 rec.methods.tostr = terra([symself]) 147 158 lib.dbg(['compiling template ' .. tid]) 148 159 [tallyup] 149 160 var [symtxt] = lib.mem.heapa(int8, [runningtally]) 150 161 var [cpypos] = [&opaque](symtxt.ptr) 162 + var p: lib.mem.pool p:init(128) 163 + var [pool] = &p 151 164 [copiers] 152 165 @[&int8](cpypos) = 0 153 166 symtxt.ct = [&int8](cpypos) - symtxt.ptr 167 + pool:free() 154 168 return symtxt 155 169 end 156 170 rec.methods.append = terra([symself], [accumulator]) 171 + var [pool] 172 + var p: lib.mem.pool 173 + if [accumulator].pool == nil then 174 + p:init(128) 175 + pool = &p 176 + else pool = [accumulator].pool end 157 177 lib.dbg(['appending template ' .. tid]) 158 178 [tallyup] 159 179 accumulator:cue([runningtally]) 160 180 [appenders] 181 + if [accumulator].pool == nil then p:free() end 161 182 return accumulator 162 183 end 163 184 rec.methods.head = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header)) 185 + var p: lib.mem.pool p:init(128) -- FIXME 186 + var [pool] = &p 164 187 lib.dbg(['transmitting template headers ' .. tid]) 165 188 [tallyup] 166 189 lib.net.mg_printf([destcon], 'HTTP/1.1 %s', lib.http.codestr(code)) 167 190 for i = 0, hd.ct do 168 191 lib.net.mg_printf([destcon], '%s: %s\r\n', hd.ptr[i].key, hd.ptr[i].value) 169 192 end 170 193 lib.net.mg_printf([destcon],'Content-Length: %llu\r\n\r\n', [runningtally] + 1) 194 + p:free() 171 195 end 172 196 rec.methods.send = terra([symself], [destcon], code: uint16, hd: lib.mem.ptr(lib.http.header)) 197 + var p: lib.mem.pool p:init(128) -- FIXME 198 + var [pool] = &p 173 199 lib.dbg(['transmitting template ' .. tid]) 174 200 175 201 symself:head(destcon,code,hd) 176 202 177 203 [senders] 178 204 lib.net.mg_send([destcon],'\r\n',2) 205 + p:free() 179 206 end 180 207 rec.methods.sz = terra([symself]) 181 208 lib.dbg(['tallying template ' .. tid]) 182 209 [tallyup] 183 210 return [runningtally] + 1 184 211 end 185 212 186 213 return rec 187 214 end 188 215 189 216 return m