parsav  Check-in [a4e71fdfda]

Overview
Comment:add in a bunch of missing pqclears, because i am a *retard*, and wipe out a fuckton of memory leaks
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a4e71fdfda530542a5efa3090ac16dcbab3a263734139356906d120696628e0b
User & Date: lexi on 2021-01-28 02:44:55
Original Comment: add in a bunch of missing pqclears, because i am a *retards*, and wipe out a fuckton of memory leaks
Other Links: manifest | tags
Context
2021-01-28
02:50
fix more dumb leaks check-in: 4ce1aab090 user: lexi tags: trunk
02:44
add in a bunch of missing pqclears, because i am a *retard*, and wipe out a fuckton of memory leaks check-in: a4e71fdfda user: lexi tags: trunk
00:51
wrote mimelib, continued iterating on litepub support; tweets can now be imported into honk check-in: c774e2c5a9 user: lexi tags: trunk
Changes

Modified api/lp/outbox.t from [7ed4c4752c] to [748fc8c886].

    24     24   			var time: lib.store.timepoint
    25     25   			if at:cmp('top') then
    26     26   				time = lib.osclock.time(nil)
    27     27   			else
    28     28   				var tp, ok = lib.math.decparse(at)
    29     29   				if ok then time = tp end
    30     30   			end
    31         -			lib.io.fmt('from-time: %llu\n', time)
    32     31   			var posts = co.srv:post_enum_author_uid(uid, lib.store.range {
    33     32   				mode = 1; -- time -> idx
    34     33   				from_time = time;
    35     34   				to_idx = 65;
    36     35   			})
    37     36   			var oldest = time
    38     37   			json:lpush',"partOf":"https://':ppush(co.srv.cfg.domain):ppush(path)
    39     38   			    :lpush'","type":"CollectionPage","orderedItems":['
    40     39   			if posts.sz > 0 then defer posts:free()
    41     40   				for i=0, lib.math.smallest(posts.sz,64) do
    42     41   					if i~=0 then json:lpush',' end
    43     42   					json:ppush(lib.api.lp.tweet(co,posts(i).ptr,true))
    44     43   					oldest = lib.math.smallest(posts(i)().posted, oldest)
           44  +					posts(i):free()
    45     45   				end
    46     46   			end
    47     47   			json:lpush'],"totalItems":':ipush(posts.sz)
    48     48   			if oldest ~= time and oldest > 0 and posts.sz > 64 then
    49     49   				json:lpush',"next":"https://':ppush(co.srv.cfg.domain):ppush(path)
    50     50   				    :lpush'?at=':ipush(oldest-1):lpush'"'
    51     51   			end

Modified backend/pgsql.t from [d6c61590d0] to [8e095d7d59].

   954    954   -- only to the connecting parsav instance, stored in memory, and dropped
   955    955   -- as soon as the connection session ends.
   956    956   
   957    957   local tempviews = sqlsquash(lib.util.ingest 'backend/schema/pgsql-views.sql')
   958    958   local prep = { quote
   959    959   	var res = lib.pq.PQexec([con], tempviews)
   960    960   	if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then
   961         -		lib.dbg('uploading pgsql session views')
          961  +		lib.dbg('uploaded pgsql session views')
          962  +		lib.pq.PQclear(res)
   962    963   	else
   963    964   		lib.bail('backend pgsql - failed to upload session views: \n', lib.pq.PQresultErrorMessage(res))
   964    965   	end
   965    966   end }
   966    967   
   967    968   for k,q in pairs(queries) do
   968    969   	local qt = sqlsquash(q.sql)
................................................................................
  1026   1027   			[#args], params, params_sz, params_ft, 1)
  1027   1028   		if res == nil then
  1028   1029   			lib.bail(['grievous error occurred executing '..k..' against database'])
  1029   1030   		elseif lib.pq.PQresultStatus(res) ~= okconst then
  1030   1031   			lib.bail(['PGSQL database procedure '..k..' failed\n'],
  1031   1032   			lib.pq.PQresultErrorMessage(res))
  1032   1033   		end
  1033         -
  1034         -		var ct = lib.pq.PQntuples(res)
  1035         -		if ct == 0 then
  1036         -			lib.pq.PQclear(res)
  1037         -			return pqr {0, nil}
  1038         -		else
  1039         -			return pqr {ct, res}
         1034  +		escape
         1035  +			if q.cmd then
         1036  +				emit quote lib.pq.PQclear(res) end
         1037  +			else emit quote
         1038  +				var ct = lib.pq.PQntuples(res)
         1039  +				if ct == 0 then
         1040  +					lib.pq.PQclear(res)
         1041  +					return pqr {0, nil}
         1042  +				else
         1043  +					return pqr {ct, res}
         1044  +				end
         1045  +			end end
  1040   1046   		end
  1041   1047   	end
  1042   1048   	q.exec.name = 'pgsql.' .. k .. '.exec'
  1043   1049   end
  1044   1050   
  1045   1051   local terra row_to_artifact(res: &pqr, i: intptr): lib.mem.ptr(lib.store.artifact)
  1046   1052   	var id = res:int(uint64,i,0)
................................................................................
  1242   1248   local getpow = terra(
  1243   1249   	src: &lib.store.source,
  1244   1250   	uid: uint64
  1245   1251   ): lib.store.powerset
  1246   1252   	var powers = lib.store.rights_default().powers
  1247   1253   	var map = array([privmap])
  1248   1254   	var r = queries.actor_powers_fetch.exec(src, uid)
         1255  +	defer r:free()
  1249   1256   
  1250   1257   	for i=0, r.sz do
  1251   1258   		for j=0, [map.type.N] do
  1252   1259   			var pn = r:_string(i,0)
  1253   1260   			if map[j].name:cmp(pn) then
  1254   1261   				if r:bool(i,1)
  1255   1262   					then powers = powers + map[j].val
................................................................................
  1261   1268   
  1262   1269   	return powers
  1263   1270   end
  1264   1271   
  1265   1272   
  1266   1273   local txdo = terra(src: &lib.store.source)
  1267   1274   	var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), 'begin')
         1275  +	var r: bool
  1268   1276   	if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then
  1269   1277   		lib.dbg('beginning pgsql transaction')
  1270         -		return true
         1278  +		r = true
  1271   1279   	else
  1272   1280   		lib.warn('backend pgsql - failed to begin transaction: \n', lib.pq.PQresultErrorMessage(res))
  1273         -		return false
         1281  +		r = false
  1274   1282   	end
         1283  +	lib.pq.PQclear(res)
         1284  +	return r
  1275   1285   end
  1276   1286   
  1277   1287   local txdone = terra(src: &lib.store.source)
  1278   1288   	var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), 'end')
         1289  +	var r: bool
  1279   1290   	if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then
  1280   1291   		lib.dbg('completing pgsql transaction')
  1281         -		return true
         1292  +		r = true
  1282   1293   	else
  1283   1294   		lib.warn('backend pgsql - failed to complete transaction: \n', lib.pq.PQresultErrorMessage(res))
  1284         -		return false
         1295  +		r = false
  1285   1296   	end
         1297  +	lib.pq.PQclear(res)
         1298  +	return r
  1286   1299   end
  1287   1300   
  1288   1301   local b = `lib.store.backend {
  1289   1302   	id = "pgsql";
  1290   1303   	open = [terra(src: &lib.store.source): &opaque
  1291   1304   		lib.report('connecting to postgres database: ', src.string.ptr)
  1292   1305   		var [con] = lib.pq.PQconnectdb(src.string.ptr)
................................................................................
  1348   1361   		key: binblob
  1349   1362   	): {}
  1350   1363   		queries.server_setup_self.exec(src,domain,key,lib.osclock.time(nil))
  1351   1364   	end];
  1352   1365   
  1353   1366   	dbsetup = [terra(src: &lib.store.source): bool
  1354   1367   		var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), schema)
         1368  +		var r = true
  1355   1369   		if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then
  1356   1370   			lib.report('successfully instantiated schema in database')
  1357         -			return true
  1358   1371   		else
  1359   1372   			lib.warn('backend pgsql - failed to initialize database: \n', lib.pq.PQresultErrorMessage(res))
  1360         -			return false
         1373  +			r = false
  1361   1374   		end
         1375  +		lib.pq.PQclear(res)
         1376  +		return r
  1362   1377   	end];
  1363   1378   
  1364   1379   	obliterate_everything = [terra(src: &lib.store.source): bool
  1365   1380   		var res = lib.pq.PQexec([&lib.pq.PGconn](src.handle), obliterator)
         1381  +		var r = true
  1366   1382   		if lib.pq.PQresultStatus(res) == lib.pq.PGRES_COMMAND_OK then
  1367   1383   			lib.report('successfully wiped out everything parsav-related in database')
  1368         -			return true
  1369   1384   		else
  1370   1385   			lib.warn('backend pgsql - failed to obliterate database: \n', lib.pq.PQresultErrorMessage(res))
  1371   1386   			return false
  1372   1387   		end
         1388  +		lib.pq.PQclear(res)
         1389  +		return r
  1373   1390   	end];
  1374   1391   
  1375         -	conf_get = [terra(src: &lib.store.source, key: pstring)
         1392  +	conf_get = [terra(src: &lib.store.source, pool: &lib.mem.pool, key: pstring)
  1376   1393   		var r = queries.conf_get.exec(src, key)
  1377   1394   		if r.sz == 0 then return [lib.mem.ptr(int8)] { ptr = nil, ct = 0 } else
  1378   1395   			defer r:free()
  1379         -			return r:String(0,0)
         1396  +			return r:_string(0,0):pdup(pool)
  1380   1397   		end
  1381   1398   	end];
  1382   1399   	conf_set = [terra(src: &lib.store.source, key: pstring, val: pstring)
  1383         -		queries.conf_set.exec(src, key, val):free() end];
         1400  +		queries.conf_set.exec(src, key, val) end];
  1384   1401   	conf_reset = [terra(src: &lib.store.source, key: rawstring)
  1385         -		queries.conf_reset.exec(src, key):free() end];
         1402  +		queries.conf_reset.exec(src, key) end];
  1386   1403   	
  1387   1404   	actor_fetch_uid = [terra(src: &lib.store.source, uid: uint64)
  1388   1405   		var r = queries.actor_fetch_uid.exec(src, uid)
  1389   1406   		if r.sz == 0 then
  1390   1407   			return [lib.mem.ptr(lib.store.actor)] { ct = 0, ptr = nil }
  1391   1408   		else defer r:free()
  1392   1409   			var a = row_to_actor(&r, 0)
................................................................................
  1511   1528   		::fail::return 0, 0, pstring.null()
  1512   1529   	end];
  1513   1530   
  1514   1531   
  1515   1532   	actor_stats = [terra(src: &lib.store.source, uid: uint64)
  1516   1533   		var r = queries.actor_stats.exec(src, uid)
  1517   1534   		if r.sz == 0 then lib.bail('error fetching actor stats!') end
         1535  +		defer r:free()
  1518   1536   		var s: lib.store.actor_stats
  1519   1537   		s.posts = r:int(uint64, 0, 0)
  1520   1538   		s.follows = r:int(uint64, 0, 1)
  1521   1539   		s.followers = r:int(uint64, 0, 2)
  1522   1540   		s.mutuals = r:int(uint64, 0, 3)
  1523   1541   		return s
  1524   1542   	end];
................................................................................
  1587   1605   
  1588   1606   	post_fetch = [terra(
  1589   1607   		src: &lib.store.source,
  1590   1608   		post: uint64
  1591   1609   	): lib.mem.ptr(lib.store.post)
  1592   1610   		var r = queries.post_fetch.exec(src, post)
  1593   1611   		if r.sz == 0 then return [lib.mem.ptr(lib.store.post)].null() end
         1612  +		defer r:free()
  1594   1613   		var p = row_to_post(&r, 0)
  1595   1614   		p.ptr.source = src
  1596   1615   		return p
  1597   1616   	end];
  1598   1617   
  1599   1618   	post_act_cancel = [terra(
  1600   1619   		src: &lib.store.source,
................................................................................
  1646   1665   		r = queries.timeline_instance_fetch.exec(src,A,B,C,D)
  1647   1666   		
  1648   1667   		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
  1649   1668   		for i=0,r.sz do
  1650   1669   			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
  1651   1670   			ret.ptr[i].ptr.source = src
  1652   1671   		end
         1672  +		r:free()
  1653   1673   
  1654   1674   		return ret
  1655   1675   	end];
  1656   1676   
  1657   1677   	timeline_circle_fetch = [terra(
  1658   1678   		src: &lib.store.source,
  1659   1679   		cid: uint64,
................................................................................
  1664   1684   		r = queries.timeline_circle_fetch.exec(src,cid,A,B,C,D)
  1665   1685   		
  1666   1686   		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
  1667   1687   		for i=0,r.sz do
  1668   1688   			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
  1669   1689   			ret.ptr[i].ptr.source = src
  1670   1690   		end
         1691  +		r:free()
  1671   1692   
  1672   1693   		return ret
  1673   1694   	end];
  1674   1695   
  1675   1696   	timeline_actor_fetch_uid = [terra(
  1676   1697   		src: &lib.store.source,
  1677   1698   		uid: uint64,
................................................................................
  1682   1703   		r = queries.timeline_actor_fetch.exec(src,uid,A,B,C,D)
  1683   1704   		
  1684   1705   		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
  1685   1706   		for i=0,r.sz do
  1686   1707   			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
  1687   1708   			ret.ptr[i].ptr.source = src
  1688   1709   		end
         1710  +		r:free()
  1689   1711   
  1690   1712   		return ret
  1691   1713   	end];
  1692   1714   
  1693   1715   	post_enum_author_uid = [terra(
  1694   1716   		src: &lib.store.source,
  1695   1717   		uid: uint64,
................................................................................
  1700   1722   		r = queries.post_enum_author_uid.exec(src,A,B,C,D,uid)
  1701   1723   		
  1702   1724   		var ret: lib.mem.ptr(lib.mem.ptr(lib.store.post)) ret:init(r.sz)
  1703   1725   		for i=0,r.sz do
  1704   1726   			ret.ptr[i] = row_to_post(&r, i) -- MUST FREE ALL
  1705   1727   			ret.ptr[i].ptr.source = src
  1706   1728   		end
         1729  +		r:free()
  1707   1730   
  1708   1731   		return ret
  1709   1732   	end];
  1710   1733   
  1711   1734   	actor_powers_fetch = getpow;
  1712   1735   	actor_save = [terra(
  1713   1736   		src: &lib.store.source,
................................................................................
  1732   1755   		ac.id = r:int(uint64,0,0)
  1733   1756   
  1734   1757   		-- check against default rights, insert records for wherever powers differ
  1735   1758   		lib.dbg('created new actor, establishing powers')
  1736   1759   		privupdate(src,ac)
  1737   1760   
  1738   1761   		lib.dbg('powers established')
         1762  +		r:free()
  1739   1763   		return ac.id
  1740   1764   	end];
  1741   1765   
  1742   1766   	actor_rel_create = [terra(
  1743   1767   		src: &lib.store.source,
  1744   1768   		kind:    uint16,
  1745   1769   		relator: uint64,
................................................................................
  1818   1842   
  1819   1843   	auth_fetch_aid = [terra(
  1820   1844   		src: &lib.store.source,
  1821   1845   		aid: uint64
  1822   1846   	): lib.mem.ptr(lib.store.auth)
  1823   1847   		var r = queries.auth_fetch_aid.exec(src,aid)
  1824   1848   		if r.sz == 0 then return [lib.mem.ptr(lib.store.auth)].null() end
         1849  +		defer r:free()
  1825   1850   		var kind = r:_string(0, 2)
  1826   1851   		var comment = r:_string(0, 3)
  1827   1852   		var a = [ lib.str.encapsulate(lib.store.auth, {
  1828   1853   			kind = {`kind.ptr, `kind.ct+1};
  1829   1854   			comment = {`comment.ptr, `comment.ct+1};
  1830   1855   		}) ]
  1831   1856   		a.ptr.aid = r:int(uint64, 0, 0)
................................................................................
  1840   1865   
  1841   1866   	auth_enum_uid = [terra(
  1842   1867   		src: &lib.store.source,
  1843   1868   		uid: uint64
  1844   1869   	): lib.mem.lstptr(lib.store.auth)
  1845   1870   		var r = queries.auth_enum_uid.exec(src,uid)
  1846   1871   		if r.sz == 0 then return [lib.mem.lstptr(lib.store.auth)].null() end
         1872  +		defer r:free()
  1847   1873   		var ret = lib.mem.heapa([lib.mem.ptr(lib.store.auth)], r.sz)
  1848   1874   		for i=0, r.sz do
  1849   1875   			var kind = r:_string(i, 1)
  1850   1876   			var comment = r:_string(i, 2)
  1851   1877   			var a = [ lib.str.encapsulate(lib.store.auth, {
  1852   1878   				kind = {`kind.ptr, `kind.ct+1};
  1853   1879   				comment = {`comment.ptr, `comment.ct+1};
................................................................................
  2004   2030   
  2005   2031   	artifact_enum_uid = [terra(
  2006   2032   		src: &lib.store.source,
  2007   2033   		uid: uint64,
  2008   2034   		folder: pstring
  2009   2035   	)
  2010   2036   		var res = queries.artifact_enum_uid.exec(src,uid,folder)
  2011         -		if res.sz > 0 then
         2037  +		if res.sz > 0 then defer res:free()
  2012   2038   			var m = lib.mem.heapa([lib.mem.ptr(lib.store.artifact)], res.sz)
  2013   2039   			for i=0,res.sz do
  2014   2040   				m.ptr[i] = row_to_artifact(&res, i)
  2015   2041   				m(i).ptr.owner = uid
  2016   2042   			end
  2017   2043   			return m
  2018   2044   		else return [lib.mem.lstptr(lib.store.artifact)].null() end
................................................................................
  2160   2186   	actor_conf_str_enum = nil;
  2161   2187   	actor_conf_str_get = [terra(
  2162   2188   		src: &lib.store.source,
  2163   2189   		pool: &lib.mem.pool,
  2164   2190   		uid: uint64,
  2165   2191   		key: pstring
  2166   2192   	): pstring
  2167         -			var r = queries.actor_conf_str_get.exec(src, uid, key)
  2168         -			if r.sz > 0 then
  2169         -				return r:_string(0,0):pdup(pool)
  2170         -			else return pstring.null() end
  2171         -		end];
         2193  +		var r = queries.actor_conf_str_get.exec(src, uid, key)
         2194  +		if r.sz > 0 then defer r:free()
         2195  +			return r:_string(0,0):pdup(pool)
         2196  +		else return pstring.null() end
         2197  +	end];
  2172   2198   	actor_conf_str_set = [terra(src: &lib.store.source, uid: uint64, key: pstring, value: pstring): {}
  2173         -			queries.actor_conf_str_set.exec(src,uid,key,value) end];
         2199  +		queries.actor_conf_str_set.exec(src,uid,key,value) end];
  2174   2200   	actor_conf_str_reset = [terra(src: &lib.store.source, uid: uint64, key: pstring): {}
  2175         -			queries.actor_conf_str_reset.exec(src,uid,key) end];
         2201  +		queries.actor_conf_str_reset.exec(src,uid,key) end];
  2176   2202   
  2177   2203   	actor_conf_int_enum = nil;
  2178   2204   	actor_conf_int_get = [terra(src: &lib.store.source, uid: uint64, key: pstring)
  2179   2205   			var r = queries.actor_conf_int_get.exec(src, uid, key)
  2180   2206   			if r.sz > 0 then
  2181   2207   				var ret = r:int(uint64,0,0)
  2182   2208   				r:free()

Modified convo.t from [ff68c1adfe] to [5c6e342d23].

    14     14   	method: lib.http.method.t
    15     15   	live_last: lib.store.timepoint
    16     16   	uploads: lib.mem.vec(lib.http.upload)
    17     17   	body: pstring
    18     18   -- cache
    19     19   	ui_hue: uint16
    20     20   	navbar: pstring
    21         -	actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries
           21  +	actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32,true) -- naive cache to avoid unnecessary queries
    22     22   -- private
    23     23   	varbuf: pstring
    24     24   	vbofs: &int8
    25     25   }
    26     26   
    27     27   struct convo.page {
    28     28   	title: pstring

Modified mem.t from [d10508934e] to [8aa8839430].

    15     15   	local p = m.ptr(ty:astype())
    16     16   	return `p {
    17     17   		ptr = [&ty:astype()](m.heapa_raw(sizeof(ty) * sz));
    18     18   		ct = sz;
    19     19   	}
    20     20   end)
    21     21   
    22         -function m.cache(ty,sz)
           22  +function m.cache(ty,sz,autofree)
    23     23   	sz = sz or 32
    24     24   	local struct c {
    25     25   		store: ty[sz]
    26     26   		top: intptr
    27     27   		cur: intptr
    28     28   	}
    29     29   	c.name = string.format('cache<%s,%u>', tostring(ty), sz)
................................................................................
    33     33   		end
    34     34   		self.store[self.cur] = v
    35     35   		self.top = lib.math.biggest(self.top, self.cur + 1)
    36     36   		self.cur = (self.cur + 1) % sz
    37     37   		return v
    38     38   	end
    39     39   	c.metamethods.__apply = terra(self: &c, idx: intptr) return &self.store[idx] end
    40         -	if ty.ptr_basetype then
           40  +	if autofree then
    41     41   		terra c:free()
    42     42   			for i=0,self.top do self.store[i]:free() end
    43     43   		end
    44     44   	end
    45     45   	return c
    46     46   end
    47     47   

Modified mgtool.t from [aa223ca2fb] to [f2643e6a8b].

    54     54   
    55     55   	all: bool
    56     56   	src: &lib.store.source
    57     57   	srv: &lib.srv.overlord
    58     58   
    59     59   	sid: uint64
    60     60   	iname: rawstring
           61  +
           62  +	cfgpool: lib.mem.pool
    61     63   }
    62     64   idelegate.metamethods.__methodmissing = macro(function(meth, self, ...)
    63     65   	local expr = {...}
    64     66   	local rt
    65     67   
    66     68   	for _,f in pairs(lib.store.backend.entries) do
    67     69   		local fn = f.field or f[1]
................................................................................
    74     76   		if self.all or (self.srv ~= nil and self.srv.sources.ct == 1)
    75     77   			then r=self.srv:[meth]([expr])
    76     78   			elseif self.src ~= nil then r=self.src:[meth]([expr])
    77     79   			else lib.bail('no data source specified')
    78     80   		end
    79     81   	in r end
    80     82   end)
           83  +
           84  +terra idelegate:conf(key: lib.str.t)
           85  +	return self:conf_get(&self.cfgpool, key)
           86  +end
    81     87   
    82     88   terra idelegate:ipc_send(cmd: lib.ipc.cmd.t, operand: uint64)
    83     89   	var emp = self.emperor
    84     90   	var acks: lib.mem.ptr(lib.ipc.ack)
    85     91   	if self.sid == 0 and self.iname == nil then
    86     92   		if not self.all and emp:countpeers() > 1 then
    87     93   			lib.bail('either specify the instance to control or pass --all to control all instances')
................................................................................
   155    161   	[lib.init]
   156    162   
   157    163   	var srv: lib.srv.overlord
   158    164   	var dlg = idelegate {
   159    165   		emperor = &emp, srv = &srv;
   160    166   		src = nil, sid = 0, iname = nil, all = false;
   161    167   	}
          168  +	dlg.cfgpool:init(128)
   162    169   
   163    170   	var mode: ctloptions
   164    171   	mode:parse(argc,argv) defer mode:free()
   165    172   	if mode.version then version() return 0 end
   166    173   	if mode.help then
   167    174   		[ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ]
   168    175   		return 0
................................................................................
   378    385   			if lib.str.cmp(mode.arglist(0),'mkroot') == 0 then
   379    386   				var cfmode: pbasic cfmode:parse(mode.arglist.ct, &mode.arglist(0))
   380    387   				if cfmode.help then
   381    388   					[ lib.emit(false, 1, 'usage: ', `argv[0], ' mkroot ', cfmode.type.helptxt.flags, ' <handle>', cfmode.type.helptxt.opts) ]
   382    389   					return 1
   383    390   				end
   384    391   				if cfmode.arglist.ct == 1 then
   385         -					var am = dlg:conf_get('credential-store')
          392  +					var am = dlg:conf('credential-store')
   386    393   					var mg: bool
   387    394   					if (not am) or am:cmp('managed') then
   388    395   						mg = true
   389    396   					elseif am:cmp('unmanaged') then
   390    397   						lib.warn('credential store is unmanaged; you will need to create credentials for the new root user manually!')
   391    398   						mg = false
   392    399   					else lib.bail('unknown credential store mode "',{am.ptr,am.ct},'"; should be either "managed" or "unmanaged"') end

Modified mime.t from [8a0a5cf230] to [16ec90c72f].

    56     56   	if type(ty.id) == 'string' then ty.id = {ty.id} end
    57     57   	for i, mime in ipairs(ty.id) do
    58     58   		idcache[mime] = ty
    59     59   	end
    60     60   
    61     61   	local op = lib.http.mime[typecode]
    62     62   	if op == nil then op = lib.http.mime.none end
    63         -	print(typecode,op)
    64     63   
    65     64   	ty.offset = #typestore
    66     65   	typestore[#typestore + 1] = `mime {
    67     66   		key = typecode;
    68     67   		canonical = [ty.id[1]];
    69     68   		safe = [not ty.unsafe];
    70     69   		ext = [ty.ext or `pstr{nil,0}];
................................................................................
    96     95   	type = mime;
    97     96   	types = knowntypes;
    98     97   	tbl = idcache;
    99     98   	typedex = typedex;
   100     99   	lookup = terra(m: pstr): &mime
   101    100   		for i=0, [#typemap_l] do
   102    101   			if m:cmp(typemap[i].string) then
   103         -				lib.io.fmt('returning type %s %u\n', typemap[i].type.key, typemap[i].type.output)
   104    102   				return typemap[i].type
   105    103   			end
   106    104   		end
   107    105   		return nil
   108    106   	end;
   109    107   }

Modified parsav.t from [3c7c1240d3] to [584b173afe].

   640    640   			elseif d.cmd == lib.ipc.cmd.enumerate then
   641    641   				if srv.id ~= nil then
   642    642   					lib.str.ncpy(&a.iname[0], srv.id, [(`a.iname).tree.type.N])
   643    643   				else a.iname[0] = 0 end
   644    644   			elseif d.cmd == lib.ipc.cmd.chnoise then
   645    645   				lib.noise.level = d.operand
   646    646   			elseif d.cmd == lib.ipc.cmd.cfgrefresh then
   647         -				srv.cfg:free()
          647  +				srv.cfg:purge()
   648    648   				srv.cfg:load()
   649    649   			end
   650    650   			d:ack(&lib.ipc.global_emperor, &a)
   651    651   		end
   652    652   	end
   653    653   	srv:shutdown()
   654    654   

Modified route.t from [1bb0eb41f3] to [5d2607bf9b].

   517    517   				return quote
   518    518   					var [me]
   519    519   					[check]
   520    520   				in [me] end
   521    521   			end)()]
   522    522   			if privs:sz() > 0 then
   523    523   				lib.dbg('installing credential restrictions')
   524         -				lib.io.fmt('on priv %llu\n',aid)
   525    524   				co.srv:auth_privs_set(aid, privs)
   526    525   			end
   527    526   
   528    527   			lib.dbg('setting netmask restrictions')
   529    528   			var nm = co:pgetv('netmask')
   530    529   		end
   531    530   		co:reroute('?')
................................................................................
   905    904   	end
   906    905   end
   907    906   
   908    907   
   909    908   terra http.local_avatar(co: &lib.srv.convo, handle: lib.mem.ptr(int8))
   910    909   	-- TODO retrieve user avatars
   911    910   	var usr = co.srv:actor_fetch_xid(handle)
   912         -	if not usr then
   913         -	goto default end
   914         -	if usr(0).origin == 0 then
   915         -		if usr(0).avatarid == 0 then goto default end
   916         -		var avi, mime = co.srv:artifact_load(usr(0).avatarid)
   917         -		if not avi then goto default end
   918         -		defer avi:free() defer mime:free()
   919         -		co:bytestream(mime,avi)
   920         -	else
   921         -		co:reroute(usr(0).avatar)
   922         -	end
   923         -	do return end
          911  +	if not usr then goto default end
          912  +	do defer usr:free()
          913  +		if usr(0).origin == 0 then
          914  +			if usr(0).avatarid == 0 then goto default end
          915  +			var avi, mime = co.srv:artifact_load(usr(0).avatarid)
          916  +			if not avi then goto default end
          917  +			defer avi:free() defer mime:free()
          918  +			co:bytestream(mime,avi)
          919  +		else
          920  +			co:reroute(usr(0).avatar)
          921  +		end
          922  +	return end
   924    923   	::default:: co:reroute('/s/default-avatar.webp')
   925    924   end
   926    925   
   927    926   terra http.file_serve_raw(co: &lib.srv.convo, id: lib.mem.ptr(int8))
   928    927   	var id, idok = lib.math.shorthand.parse(id.ptr, id.ct)
   929    928   	if not idok then goto e404 end
   930    929   	var data, mime = co.srv:artifact_load(id)

Modified session.t from [c79e9ffb10] to [15e824caf3].

    22     22   		[lib.mem.ptr(uint8)] {ptr = [&uint8](secret.ptr), ct = secret.ct},
    23     23   		[lib.mem.ptr( int8)] {ptr = out, ct = len},
    24     24   	&hash[0])
    25     25   	ptr = ptr + lib.math.shorthand.gen(lib.math.truncate64(hash, [hash.type.N]), ptr)
    26     26   	return ptr - out
    27     27   end
    28     28   
    29         -terra m.cookie_interpret(secret: lib.mem.ptr(int8), c: lib.mem.ptr(int8), now: uint64) -- returns either 0,0 or a valid {authid, timepoint}
    30         -	var authid_sz = lib.str.cspan(c.ptr, lib.str.lit '.', c.ct)
           29  +terra m.cookie_interpret(secret: lib.mem.ptr(int8), c: lib.mem.ptr(int8), now: uint64)
           30  + -- returns either 0,0 or a valid {authid, timepoint}
           31  +	var authid_sz = lib.str.cspan(c.ptr, '.', c.ct)
    31     32   	if authid_sz == 0 then return 0,0 end
    32     33   	if authid_sz + 1 > c.ct then return 0,0 end
    33         -	var time_sz = lib.str.cspan(c.ptr+authid_sz+1, lib.str.lit '.', c.ct - (authid_sz+1))
           34  +	var time_sz = lib.str.cspan(c.ptr+authid_sz+1, '.', c.ct - (authid_sz+1))
    34     35   	if time_sz == 0 then return 0,0 end
    35     36   	if (authid_sz + time_sz + 2) > c.ct then return 0,0 end
    36     37   	var hash_sz = c.ct - (authid_sz + time_sz + 2)
    37     38   
    38     39   	var knownhash: uint8[lib.crypt.algsz.sha256]
    39     40   	lib.crypt.hmac(lib.crypt.alg.sha256,
    40     41   		[lib.mem.ptr(uint8)] {ptr = [&uint8](secret.ptr), ct = secret.ct},

Modified srv.t from [dafa2dc374] to [1938b717c7].

     1      1   -- vim: ft=terra
     2      2   local util = lib.util
     3      3   local secmode = lib.enum { 'public', 'private', 'lockdown', 'isolate' }
     4      4   local pstring = lib.mem.ptr(int8)
     5      5   
     6      6   local struct srv
     7      7   local struct cfgcache {
            8  +	_pool: lib.mem.pool
     8      9   	secret: pstring
     9     10   	pol_sec: secmode.t
    10     11   	pol_reg: bool
    11     12   	pol_autoherald: bool
    12     13   	credmgd: bool
    13     14   	maxupsz: intptr
    14     15   	poolinitsz: intptr
................................................................................
    30     31   	webmgr: lib.net.mg_mgr
    31     32   	webcon: &lib.net.mg_connection
    32     33   	cfg: cfgcache
    33     34   	id: rawstring
    34     35   	pool: lib.mem.pool
    35     36   }
    36     37   
    37         -terra cfgcache:free() -- :/ TODO replace with pool
    38         -	self.secret:free()
    39         -	self.instance:free()
    40         -	self.domain:free()
    41         -	self.ui_cue_staff:free()
    42         -	self.ui_cue_founder:free()
    43         -	self.usrdef_pol_follow:free()
    44         -	self.usrdef_pol_follow_req:free()
           38  +terra cfgcache:purge()
           39  +	self._pool:clear()
           40  +end
           41  +
           42  +terra cfgcache:free()
           43  +	self._pool:free()
    45     44   end
    46     45   
    47     46   terra srv:post_enum_author_uid(uid: uint64, r: lib.store.range): lib.mem.vec(lib.mem.ptr(lib.store.post))
    48     47   	var all: lib.mem.vec(lib.mem.ptr(lib.store.post)) all:init(64)
    49     48   	for i=0,self.sources.ct do var src = self.sources.ptr + i
    50     49   		if src.handle ~= nil and src.backend.timeline_instance_fetch ~= nil then
    51     50   			var lst = src:post_enum_author_uid(uid,r)
................................................................................
   375    374   								co:complain(400,'bad request','unrecognized content-type')
   376    375   								goto fail
   377    376   							end
   378    377   							var boundary = pstring {ptr=p+9,ct=ctt.ct - ((p - ctt.ptr) + 9)}
   379    378   							co.method = lib.http.method.post_file
   380    379   							co.uploads:init(8)
   381    380   
   382         -							var bsr = (lib.str.acc{}):compose('\r\n--',boundary,'\r\n'):finalize()
          381  +							var bsr = co:qstr('\r\n--',boundary,'\r\n')
   383    382   
   384    383   							var upmap = lib.str.splitmap(co.body,bsr,8)
   385    384   							-- first entry may not be preceded by header-break
   386    385   							if lib.str.find(upmap(0), pstring {
   387    386   								ptr = bsr.ptr + 2, ct = bsr.ct - 2
   388    387   							}):ref() then
   389    388   								upmap(0).ptr = upmap(0).ptr + (bsr.ct - 2)
................................................................................
   451    450   												nextup.field = fld
   452    451   												nextup.filename = file
   453    452   											end
   454    453   										end
   455    454   									end
   456    455   								end
   457    456   							end
   458         -							bsr:free()
   459    457   							upmap:free()
   460    458   						end
   461    459   					end
   462    460   				end
   463    461   
   464         -				var mtt = lib.http.mime._str(co.reqtype)
   465         -				lib.dbg('routing with negotiated type of ', {mtt.ptr,mtt.ct})
   466    462   				route.dispatch_http(&co, uri)
   467    463   
   468    464   				::fail::
   469    465   				if co.uploads.run > 0 then
   470    466   					for i=0,co.uploads.sz do
   471    467   						co.uploads(i).filename:free()
   472    468   						co.uploads(i).field:free()
................................................................................
   654    650   --
   655    651   --	return 0
   656    652   --end
   657    653   
   658    654   terra cfgcache.methods.load :: {&cfgcache} -> {}
   659    655   terra cfgcache:init(o: &srv)
   660    656   	self.overlord = o
          657  +	self._pool:init(256)
   661    658   	self:load()
   662    659   end
   663    660   
   664    661   terra srv:setup(befile: rawstring)
   665    662   	cfg(self, befile)
   666    663   	var success = false
   667    664   	if self.sources.ct == 0 then lib.bail('no data sources specified') end
................................................................................
   675    672   	end
   676    673   end
   677    674   
   678    675   terra srv:start(iname: rawstring)
   679    676   	self:conprep(lib.store.prepmode.full)
   680    677   	self.cfg:init(self)
   681    678   	self.pool:init(self.cfg.poolinitsz)
   682         -	var dbbind = self:conf_get('bind')
          679  +	var dbbind = self:conf_get(&self.pool, 'bind')
   683    680   	if iname == nil then iname = lib.proc.getenv('parsav_instance') end
   684    681   	if iname == nil then
   685    682   		self.id = self.cfg.instance.ptr;
   686    683   		-- let this leak -- it'll be needed for the lifetime of the process anyway
   687    684   	else self.id = iname end 
   688    685   
   689    686   	if iname ~= nil then
................................................................................
   698    695   		bind = dbbind.ptr
   699    696   	else bind = '[::1]:10917' end
   700    697   
   701    698   	lib.report('binding to ', bind)
   702    699   	lib.net.mg_mgr_init(&self.webmgr)
   703    700   	self.webcon = lib.net.mg_http_listen(&self.webmgr, bind, handle.http, self)
   704    701   
   705         -	if dbbind.ptr ~= nil then dbbind:free() end
          702  +	--if dbbind.ptr ~= nil then dbbind:free() end
   706    703   end
   707    704   
   708    705   terra srv:poll()
   709    706   	lib.net.mg_mgr_poll(&self.webmgr,300)
   710    707   end
   711    708   
   712    709   terra srv:shutdown()
................................................................................
   715    712   		lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')')
   716    713   		src:close()
   717    714   	end
   718    715   	self.sources:free()
   719    716   	self.pool:free()
   720    717   end
   721    718   
   722         -terra cfgcache:cfint(name: rawstring, default: intptr)
   723         -	var str = self.overlord:conf_get(name)
          719  +terra cfgcache:cfstr(name: pstring)
          720  +	return self.overlord:conf_get(&self._pool, name)
          721  +end
          722  +
          723  +terra cfgcache:cfint(name: pstring, default: intptr)
          724  +	var f = self._pool:frame()
          725  +	var str = self:cfstr(name)
          726  +	defer self._pool:reset(f)
   724    727   	if str.ptr ~= nil then
   725    728   		var i,ok = lib.math.decparse(str)
   726    729   		if ok then default = i else
   727         -			lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected integer; using default value instead')
          730  +			lib.warn('invalid configuration setting ',{name.ptr,name.ct},'="',{str.ptr,str.ct},'", expected integer; using default value instead')
   728    731   		end
   729         -		str:free()
   730    732   	end
   731    733   	return default
   732    734   end
   733    735   
   734         -terra cfgcache:cffsz(name: rawstring, default: intptr)
   735         -	var str = self.overlord:conf_get(name)
          736  +terra cfgcache:cffsz(name: pstring, default: intptr)
          737  +	var f = self._pool:frame()
          738  +	var str = self:cfstr(name)
          739  +	defer self._pool:reset(f)
   736    740   	if str:ref() then
   737    741   		var sz, ok = lib.math.fsz_parse(str)
   738    742   		if ok then default = sz else
   739         -			lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected byte length; using default value instead')
          743  +			lib.warn('invalid configuration setting ',{name.ptr,name.ct},'="',{str.ptr,str.ct},'", expected byte length; using default value instead')
   740    744   		end
   741         -		str:free()
   742    745   	end
   743    746   	return default
   744    747   end
   745    748   
   746         -terra cfgcache:cfbool(name: rawstring, default: bool)
   747         -	var str = self.overlord:conf_get(name)
          749  +terra cfgcache:cfbool(name: pstring, default: bool)
          750  +	var f = self._pool:frame()
          751  +	var str = self:cfstr(name)
          752  +	defer self._pool:reset(f)
   748    753   	if str.ptr ~= nil then
   749    754   		if str:cmp('true') or str:cmp('on') or
   750    755   		   str:cmp('yes')  or str:cmp('1') then
   751    756   			default = true
   752    757   		elseif str:cmp('false') or str:cmp('off') or
   753    758   		       str:cmp('no')    or str:cmp('0') then
   754    759   			default = false
   755    760   		else
   756         -			lib.warn('invalid configuration setting ',name,'="',{str.ptr,str.ct},'", expected boolean; using default value instead')
          761  +			lib.warn('invalid configuration setting ',{name.ptr,name.ct},'="',{str.ptr,str.ct},'", expected boolean; using default value instead')
   757    762   		end
   758         -		str:free()
   759    763   	end
   760    764   	return default
   761    765   end
   762    766   
   763    767   terra cfgcache:load()
   764         -	self.instance = self.overlord:conf_get('instance-name')
   765         -	self.domain = self.overlord:conf_get('domain')
   766         -	self.secret = self.overlord:conf_get('server-secret')
          768  +	
          769  +	self.instance = self:cfstr('instance-name')
          770  +	self.domain = self:cfstr('domain')
          771  +	self.secret = self:cfstr('server-secret')
   767    772   
   768    773   	self.pol_reg = self:cfbool('policy-self-register', false)
   769    774   	self.pol_autoherald = self:cfbool('policy-self-herald', true)
   770    775   
   771    776   	do self.credmgd = false
   772         -	var sreg = self.overlord:conf_get('credential-store')
          777  +	var fr = self._pool:frame()
          778  +	var sreg = self:cfstr('credential-store')
   773    779   	if sreg:ref() then
   774    780   		if lib.str.cmp(sreg.ptr, 'managed') == 0
   775    781   			then self.credmgd = true
   776    782   			else self.credmgd = false
   777    783   		end
   778         -		sreg:free()
          784  +		self._pool:reset(fr)
   779    785   	end end
   780    786   
   781    787   	self.maxupsz = self:cffsz('maximum-artifact-size', [1024 * 100]) -- 100 kilobyte default
   782    788   	self.poolinitsz = self:cffsz('server-pool-size-initial', [1024 * 10]) -- 10 kilobyte default
   783    789   	
   784    790   	self.pol_sec = secmode.lockdown
   785         -	var smode = self.overlord:conf_get('policy-security')
          791  +	do var fr = self._pool:frame()
          792  +	var smode = self:cfstr('policy-security')
   786    793   	if smode.ptr ~= nil then
   787    794   		if lib.str.cmp(smode.ptr, 'public') == 0 then
   788    795   			self.pol_sec = secmode.public
   789    796   		elseif lib.str.cmp(smode.ptr, 'private') == 0 then
   790    797   			self.pol_sec = secmode.private
   791    798   		elseif lib.str.cmp(smode.ptr, 'lockdown') == 0 then
   792    799   			self.pol_sec = secmode.lockdown
   793    800   		elseif lib.str.cmp(smode.ptr, 'isolate') == 0 then
   794    801   			self.pol_sec = secmode.isolate
   795    802   		end
   796         -		smode:free()
   797         -	end
          803  +		self._pool:reset(fr)
          804  +	end end
   798    805   
   799    806   	self.ui_hue = self:cfint('ui-accent',config.default_ui_accent)
   800    807   	self.nranks = self:cfint('user-ranks',10)
   801    808   	self.maxinvites = self:cfint('max-invites',64)
   802    809   	
   803         -	var webmaster = self.overlord:conf_get('master')
   804         -	if webmaster:ref() then defer webmaster:free()
          810  +	do var fr = self._pool:frame()
          811  +	var webmaster = self:cfstr('master')
          812  +	defer self._pool:reset(fr)
          813  +	if webmaster:ref() then 
   805    814   		var wma = self.overlord:actor_fetch_xid(webmaster)
   806    815   		if not wma then
   807    816   			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')
   808    817   		else
   809    818   			self.master = wma(0).id
   810    819   			wma:free()
   811    820   		end
   812         -	end
          821  +	end end
   813    822   
   814         -	self.ui_cue_staff = self.overlord:conf_get('ui-profile-cue-staff')
   815         -	self.ui_cue_founder = self.overlord:conf_get('ui-profile-cue-master')
          823  +	self.ui_cue_staff = self:cfstr('ui-profile-cue-staff')
          824  +	self.ui_cue_founder = self:cfstr('ui-profile-cue-master')
   816    825   
   817         -	self.usrdef_pol_follow = self.overlord:conf_get('user-default-acl-follow')
   818         -	self.usrdef_pol_follow_req = self.overlord:conf_get('user-default-acl-follow-req')
          826  +	self.usrdef_pol_follow = self:cfstr('user-default-acl-follow')
          827  +	self.usrdef_pol_follow_req = self:cfstr('user-default-acl-follow-req')
   819    828   end
   820    829   
   821    830   return {
   822    831   	overlord = srv;
   823    832   	convo = convo;
   824    833   	route = route;
   825    834   	secmode = secmode;
   826    835   }

Modified store.t from [6e43eba049] to [54bd5bc381].

   372    372   	-- these two functions are special, in that they should be called
   373    373   	-- directly on a specific backend, rather than passed down to the
   374    374   	-- backends by the server; that is pathological behavior that will
   375    375   	-- not have the desired effect
   376    376   
   377    377   	server_setup_self: {&m.source, rawstring, lib.mem.ptr(uint8)} -> {}
   378    378   
   379         -	conf_get: {&m.source, lib.str.t} -> lib.mem.ptr(int8)
          379  +	conf_get: {&m.source, &lib.mem.pool, lib.str.t} -> lib.mem.ptr(int8)
   380    380   	conf_set: {&m.source, lib.str.t, lib.str.t} -> {}
   381    381   	conf_reset: {&m.source, rawstring} -> {}
   382    382   
   383    383   	actor_create: {&m.source, &m.actor} -> uint64
   384    384   	actor_save: {&m.source, &m.actor} -> {}
   385    385   	actor_save_privs: {&m.source, &m.actor} -> {}
   386    386   	actor_purge_uid: {&m.source, uint64} -> {}