pg_query 4.2.2 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (486) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/README.md +6 -8
  4. data/Rakefile +3 -3
  5. data/ext/pg_query/extconf.rb +1 -3
  6. data/ext/pg_query/include/access/amapi.h +3 -1
  7. data/ext/pg_query/include/access/attmap.h +5 -3
  8. data/ext/pg_query/include/access/attnum.h +1 -1
  9. data/ext/pg_query/include/access/clog.h +1 -1
  10. data/ext/pg_query/include/access/commit_ts.h +1 -1
  11. data/ext/pg_query/include/access/detoast.h +1 -1
  12. data/ext/pg_query/include/access/genam.h +7 -5
  13. data/ext/pg_query/include/access/gin.h +16 -3
  14. data/ext/pg_query/include/access/htup.h +1 -1
  15. data/ext/pg_query/include/access/htup_details.h +6 -2
  16. data/ext/pg_query/include/access/itup.h +61 -58
  17. data/ext/pg_query/include/access/parallel.h +2 -2
  18. data/ext/pg_query/include/access/printtup.h +1 -1
  19. data/ext/pg_query/include/access/relation.h +1 -1
  20. data/ext/pg_query/include/access/relscan.h +1 -1
  21. data/ext/pg_query/include/access/rmgrlist.h +2 -2
  22. data/ext/pg_query/include/access/sdir.h +12 -3
  23. data/ext/pg_query/include/access/skey.h +1 -1
  24. data/ext/pg_query/include/access/stratnum.h +1 -1
  25. data/ext/pg_query/include/access/sysattr.h +1 -1
  26. data/ext/pg_query/include/access/table.h +1 -1
  27. data/ext/pg_query/include/access/tableam.h +68 -45
  28. data/ext/pg_query/include/access/toast_compression.h +1 -1
  29. data/ext/pg_query/include/access/transam.h +1 -1
  30. data/ext/pg_query/include/access/tsmapi.h +82 -0
  31. data/ext/pg_query/include/access/tupconvert.h +5 -2
  32. data/ext/pg_query/include/access/tupdesc.h +2 -2
  33. data/ext/pg_query/include/access/tupmacs.h +58 -98
  34. data/ext/pg_query/include/access/twophase.h +2 -2
  35. data/ext/pg_query/include/access/xact.h +25 -18
  36. data/ext/pg_query/include/access/xlog.h +15 -16
  37. data/ext/pg_query/include/access/xlog_internal.h +100 -62
  38. data/ext/pg_query/include/access/xlogbackup.h +41 -0
  39. data/ext/pg_query/include/access/xlogdefs.h +6 -25
  40. data/ext/pg_query/include/access/xlogprefetcher.h +1 -1
  41. data/ext/pg_query/include/access/xlogreader.h +7 -6
  42. data/ext/pg_query/include/access/xlogrecord.h +17 -5
  43. data/ext/pg_query/include/access/xlogrecovery.h +4 -3
  44. data/ext/pg_query/include/archive/archive_module.h +59 -0
  45. data/ext/pg_query/include/c.h +144 -156
  46. data/ext/pg_query/include/catalog/catalog.h +4 -3
  47. data/ext/pg_query/include/catalog/catversion.h +6 -2
  48. data/ext/pg_query/include/catalog/dependency.h +5 -4
  49. data/ext/pg_query/include/catalog/genbki.h +7 -6
  50. data/ext/pg_query/include/catalog/index.h +4 -4
  51. data/ext/pg_query/include/catalog/indexing.h +1 -1
  52. data/ext/pg_query/include/catalog/namespace.h +2 -2
  53. data/ext/pg_query/include/catalog/objectaccess.h +10 -8
  54. data/ext/pg_query/include/catalog/objectaddress.h +3 -3
  55. data/ext/pg_query/include/catalog/pg_aggregate.h +1 -1
  56. data/ext/pg_query/include/catalog/pg_aggregate_d.h +1 -1
  57. data/ext/pg_query/include/catalog/pg_am.h +1 -1
  58. data/ext/pg_query/include/catalog/pg_am_d.h +1 -1
  59. data/ext/pg_query/include/catalog/pg_attribute.h +19 -17
  60. data/ext/pg_query/include/catalog/pg_attribute_d.h +19 -19
  61. data/ext/pg_query/include/catalog/pg_authid.h +1 -1
  62. data/ext/pg_query/include/catalog/pg_authid_d.h +3 -1
  63. data/ext/pg_query/include/catalog/pg_class.h +1 -1
  64. data/ext/pg_query/include/catalog/pg_class_d.h +1 -1
  65. data/ext/pg_query/include/catalog/pg_collation.h +3 -1
  66. data/ext/pg_query/include/catalog/pg_collation_d.h +4 -3
  67. data/ext/pg_query/include/catalog/pg_constraint.h +2 -2
  68. data/ext/pg_query/include/catalog/pg_constraint_d.h +1 -1
  69. data/ext/pg_query/include/catalog/pg_control.h +9 -1
  70. data/ext/pg_query/include/catalog/pg_conversion.h +2 -2
  71. data/ext/pg_query/include/catalog/pg_conversion_d.h +1 -1
  72. data/ext/pg_query/include/catalog/pg_database.h +124 -0
  73. data/ext/pg_query/include/catalog/pg_database_d.h +52 -0
  74. data/ext/pg_query/include/catalog/pg_depend.h +1 -1
  75. data/ext/pg_query/include/catalog/pg_depend_d.h +1 -1
  76. data/ext/pg_query/include/catalog/pg_event_trigger.h +1 -1
  77. data/ext/pg_query/include/catalog/pg_event_trigger_d.h +1 -1
  78. data/ext/pg_query/include/catalog/pg_index.h +1 -1
  79. data/ext/pg_query/include/catalog/pg_index_d.h +1 -1
  80. data/ext/pg_query/include/catalog/pg_language.h +1 -1
  81. data/ext/pg_query/include/catalog/pg_language_d.h +1 -1
  82. data/ext/pg_query/include/catalog/pg_namespace.h +1 -1
  83. data/ext/pg_query/include/catalog/pg_namespace_d.h +1 -1
  84. data/ext/pg_query/include/catalog/pg_opclass.h +1 -1
  85. data/ext/pg_query/include/catalog/pg_opclass_d.h +1 -1
  86. data/ext/pg_query/include/catalog/pg_operator.h +1 -1
  87. data/ext/pg_query/include/catalog/pg_operator_d.h +1 -1
  88. data/ext/pg_query/include/catalog/pg_opfamily.h +3 -2
  89. data/ext/pg_query/include/catalog/pg_opfamily_d.h +4 -2
  90. data/ext/pg_query/include/catalog/pg_partitioned_table.h +1 -1
  91. data/ext/pg_query/include/catalog/pg_partitioned_table_d.h +1 -1
  92. data/ext/pg_query/include/catalog/pg_proc.h +1 -1
  93. data/ext/pg_query/include/catalog/pg_proc_d.h +1 -1
  94. data/ext/pg_query/include/catalog/pg_publication.h +2 -5
  95. data/ext/pg_query/include/catalog/pg_publication_d.h +1 -1
  96. data/ext/pg_query/include/catalog/pg_replication_origin.h +1 -1
  97. data/ext/pg_query/include/catalog/pg_replication_origin_d.h +1 -1
  98. data/ext/pg_query/include/catalog/pg_statistic.h +1 -1
  99. data/ext/pg_query/include/catalog/pg_statistic_d.h +1 -1
  100. data/ext/pg_query/include/catalog/pg_statistic_ext.h +1 -1
  101. data/ext/pg_query/include/catalog/pg_statistic_ext_d.h +1 -1
  102. data/ext/pg_query/include/catalog/pg_transform.h +1 -1
  103. data/ext/pg_query/include/catalog/pg_transform_d.h +1 -1
  104. data/ext/pg_query/include/catalog/pg_trigger.h +1 -1
  105. data/ext/pg_query/include/catalog/pg_trigger_d.h +1 -1
  106. data/ext/pg_query/include/catalog/pg_ts_config.h +1 -1
  107. data/ext/pg_query/include/catalog/pg_ts_config_d.h +1 -1
  108. data/ext/pg_query/include/catalog/pg_ts_dict.h +1 -1
  109. data/ext/pg_query/include/catalog/pg_ts_dict_d.h +1 -1
  110. data/ext/pg_query/include/catalog/pg_ts_parser.h +1 -1
  111. data/ext/pg_query/include/catalog/pg_ts_parser_d.h +1 -1
  112. data/ext/pg_query/include/catalog/pg_ts_template.h +1 -1
  113. data/ext/pg_query/include/catalog/pg_ts_template_d.h +1 -1
  114. data/ext/pg_query/include/catalog/pg_type.h +1 -1
  115. data/ext/pg_query/include/catalog/pg_type_d.h +1 -1
  116. data/ext/pg_query/include/catalog/storage.h +6 -6
  117. data/ext/pg_query/include/commands/async.h +1 -1
  118. data/ext/pg_query/include/commands/dbcommands.h +2 -1
  119. data/ext/pg_query/include/commands/defrem.h +2 -1
  120. data/ext/pg_query/include/commands/event_trigger.h +1 -1
  121. data/ext/pg_query/include/commands/explain.h +3 -1
  122. data/ext/pg_query/include/commands/prepare.h +1 -1
  123. data/ext/pg_query/include/commands/tablespace.h +4 -4
  124. data/ext/pg_query/include/commands/trigger.h +15 -14
  125. data/ext/pg_query/include/commands/user.h +9 -3
  126. data/ext/pg_query/include/commands/vacuum.h +60 -14
  127. data/ext/pg_query/include/common/cryptohash.h +39 -0
  128. data/ext/pg_query/include/common/file_perm.h +1 -1
  129. data/ext/pg_query/include/common/hashfn.h +1 -1
  130. data/ext/pg_query/include/common/int.h +437 -0
  131. data/ext/pg_query/include/common/ip.h +4 -2
  132. data/ext/pg_query/include/common/keywords.h +1 -1
  133. data/ext/pg_query/include/common/kwlookup.h +2 -2
  134. data/ext/pg_query/include/common/pg_prng.h +3 -2
  135. data/ext/pg_query/include/common/relpath.h +20 -13
  136. data/ext/pg_query/include/common/scram-common.h +70 -0
  137. data/ext/pg_query/include/common/sha2.h +32 -0
  138. data/ext/pg_query/include/common/string.h +5 -3
  139. data/ext/pg_query/include/common/unicode_east_asian_fw_table.h +10 -10
  140. data/ext/pg_query/include/common/{unicode_combining_table.h → unicode_nonspacing_table.h} +31 -13
  141. data/ext/pg_query/include/copyfuncs.funcs.c +5013 -0
  142. data/ext/pg_query/include/copyfuncs.switch.c +938 -0
  143. data/ext/pg_query/include/datatype/timestamp.h +11 -4
  144. data/ext/pg_query/include/equalfuncs.funcs.c +3097 -0
  145. data/ext/pg_query/include/equalfuncs.switch.c +785 -0
  146. data/ext/pg_query/include/executor/execdesc.h +1 -1
  147. data/ext/pg_query/include/executor/executor.h +34 -17
  148. data/ext/pg_query/include/executor/functions.h +1 -1
  149. data/ext/pg_query/include/executor/instrument.h +1 -1
  150. data/ext/pg_query/include/executor/spi.h +2 -2
  151. data/ext/pg_query/include/executor/tablefunc.h +1 -1
  152. data/ext/pg_query/include/executor/tuptable.h +18 -11
  153. data/ext/pg_query/include/fmgr.h +21 -2
  154. data/ext/pg_query/include/foreign/fdwapi.h +294 -0
  155. data/ext/pg_query/include/funcapi.h +12 -12
  156. data/ext/pg_query/include/gram.h +1127 -0
  157. data/ext/pg_query/include/{parser/gramparse.h → gramparse.h} +4 -4
  158. data/ext/pg_query/include/jit/jit.h +2 -2
  159. data/ext/pg_query/include/kwlist_d.h +534 -510
  160. data/ext/pg_query/include/lib/dshash.h +4 -1
  161. data/ext/pg_query/include/lib/ilist.h +435 -22
  162. data/ext/pg_query/include/lib/pairingheap.h +1 -1
  163. data/ext/pg_query/include/lib/simplehash.h +9 -9
  164. data/ext/pg_query/include/lib/sort_template.h +1 -1
  165. data/ext/pg_query/include/lib/stringinfo.h +3 -3
  166. data/ext/pg_query/include/libpq/auth.h +8 -2
  167. data/ext/pg_query/include/libpq/crypt.h +1 -1
  168. data/ext/pg_query/include/libpq/hba.h +24 -17
  169. data/ext/pg_query/include/libpq/libpq-be.h +36 -25
  170. data/ext/pg_query/include/libpq/libpq.h +1 -1
  171. data/ext/pg_query/include/libpq/pqcomm.h +10 -41
  172. data/ext/pg_query/include/libpq/pqformat.h +2 -2
  173. data/ext/pg_query/include/libpq/pqsignal.h +22 -10
  174. data/ext/pg_query/include/libpq/sasl.h +136 -0
  175. data/ext/pg_query/include/libpq/scram.h +37 -0
  176. data/ext/pg_query/include/mb/pg_wchar.h +35 -18
  177. data/ext/pg_query/include/mb/stringinfo_mb.h +1 -1
  178. data/ext/pg_query/include/miscadmin.h +26 -14
  179. data/ext/pg_query/include/nodes/bitmapset.h +11 -7
  180. data/ext/pg_query/include/nodes/execnodes.h +83 -30
  181. data/ext/pg_query/include/nodes/extensible.h +5 -3
  182. data/ext/pg_query/include/nodes/lockoptions.h +1 -1
  183. data/ext/pg_query/include/nodes/makefuncs.h +14 -2
  184. data/ext/pg_query/include/nodes/memnodes.h +7 -4
  185. data/ext/pg_query/include/nodes/miscnodes.h +56 -0
  186. data/ext/pg_query/include/nodes/nodeFuncs.h +89 -29
  187. data/ext/pg_query/include/nodes/nodes.h +95 -510
  188. data/ext/pg_query/include/nodes/nodetags.h +471 -0
  189. data/ext/pg_query/include/nodes/params.h +3 -3
  190. data/ext/pg_query/include/nodes/parsenodes.h +377 -139
  191. data/ext/pg_query/include/nodes/pathnodes.h +1090 -440
  192. data/ext/pg_query/include/nodes/pg_list.h +30 -7
  193. data/ext/pg_query/include/nodes/plannodes.h +367 -124
  194. data/ext/pg_query/include/nodes/primnodes.h +670 -222
  195. data/ext/pg_query/include/nodes/print.h +1 -1
  196. data/ext/pg_query/include/{utils → nodes}/queryjumble.h +5 -7
  197. data/ext/pg_query/include/nodes/replnodes.h +111 -0
  198. data/ext/pg_query/include/nodes/supportnodes.h +346 -0
  199. data/ext/pg_query/include/nodes/tidbitmap.h +1 -1
  200. data/ext/pg_query/include/nodes/value.h +12 -2
  201. data/ext/pg_query/include/optimizer/cost.h +6 -4
  202. data/ext/pg_query/include/optimizer/geqo.h +1 -1
  203. data/ext/pg_query/include/optimizer/geqo_gene.h +1 -1
  204. data/ext/pg_query/include/optimizer/optimizer.h +8 -8
  205. data/ext/pg_query/include/optimizer/paths.h +16 -7
  206. data/ext/pg_query/include/optimizer/planmain.h +3 -6
  207. data/ext/pg_query/include/parser/analyze.h +4 -3
  208. data/ext/pg_query/include/parser/kwlist.h +12 -1
  209. data/ext/pg_query/include/parser/parse_agg.h +4 -2
  210. data/ext/pg_query/include/parser/parse_coerce.h +3 -1
  211. data/ext/pg_query/include/parser/parse_expr.h +1 -1
  212. data/ext/pg_query/include/parser/parse_func.h +1 -1
  213. data/ext/pg_query/include/parser/parse_node.h +22 -4
  214. data/ext/pg_query/include/parser/parse_oper.h +3 -3
  215. data/ext/pg_query/include/parser/parse_relation.h +8 -3
  216. data/ext/pg_query/include/parser/parse_type.h +4 -3
  217. data/ext/pg_query/include/parser/parser.h +1 -1
  218. data/ext/pg_query/include/parser/parsetree.h +1 -1
  219. data/ext/pg_query/include/parser/scanner.h +2 -2
  220. data/ext/pg_query/include/parser/scansup.h +1 -1
  221. data/ext/pg_query/include/partitioning/partdefs.h +1 -1
  222. data/ext/pg_query/include/pg_config.h +23 -217
  223. data/ext/pg_query/include/pg_config_manual.h +8 -46
  224. data/ext/pg_query/include/pg_getopt.h +1 -1
  225. data/ext/pg_query/include/pg_query.h +27 -3
  226. data/ext/pg_query/include/pg_query_enum_defs.c +311 -149
  227. data/ext/pg_query/include/pg_query_fingerprint_conds.c +545 -489
  228. data/ext/pg_query/include/pg_query_fingerprint_defs.c +5092 -4432
  229. data/ext/pg_query/include/pg_query_outfuncs_conds.c +385 -343
  230. data/ext/pg_query/include/pg_query_outfuncs_defs.c +1294 -1161
  231. data/ext/pg_query/include/pg_query_readfuncs_conds.c +137 -123
  232. data/ext/pg_query/include/pg_query_readfuncs_defs.c +1657 -1496
  233. data/ext/pg_query/include/pg_trace.h +1 -1
  234. data/ext/pg_query/include/pgstat.h +172 -93
  235. data/ext/pg_query/include/pgtime.h +3 -3
  236. data/ext/pg_query/include/pl_gram.h +64 -62
  237. data/ext/pg_query/include/pl_reserved_kwlist.h +1 -1
  238. data/ext/pg_query/include/pl_reserved_kwlist_d.h +1 -1
  239. data/ext/pg_query/include/pl_unreserved_kwlist.h +2 -1
  240. data/ext/pg_query/include/pl_unreserved_kwlist_d.h +48 -46
  241. data/ext/pg_query/include/plpgsql.h +17 -22
  242. data/ext/pg_query/include/port/atomics/arch-arm.h +3 -3
  243. data/ext/pg_query/include/port/atomics/arch-ppc.h +21 -21
  244. data/ext/pg_query/include/port/atomics/arch-x86.h +2 -2
  245. data/ext/pg_query/include/port/atomics/fallback.h +3 -3
  246. data/ext/pg_query/include/port/atomics/generic-gcc.h +1 -1
  247. data/ext/pg_query/include/port/atomics/generic.h +1 -1
  248. data/ext/pg_query/include/port/atomics.h +2 -7
  249. data/ext/pg_query/include/port/pg_bitutils.h +62 -25
  250. data/ext/pg_query/include/port/pg_bswap.h +1 -1
  251. data/ext/pg_query/include/port/pg_crc32c.h +1 -1
  252. data/ext/pg_query/include/port/simd.h +375 -0
  253. data/ext/pg_query/include/port.h +42 -75
  254. data/ext/pg_query/include/portability/instr_time.h +81 -140
  255. data/ext/pg_query/include/postgres.h +205 -434
  256. data/ext/pg_query/include/postgres_ext.h +0 -1
  257. data/ext/pg_query/include/postmaster/autovacuum.h +1 -4
  258. data/ext/pg_query/include/postmaster/auxprocess.h +1 -1
  259. data/ext/pg_query/include/postmaster/bgworker.h +2 -2
  260. data/ext/pg_query/include/postmaster/bgworker_internals.h +1 -1
  261. data/ext/pg_query/include/postmaster/bgwriter.h +2 -2
  262. data/ext/pg_query/include/postmaster/fork_process.h +1 -1
  263. data/ext/pg_query/include/postmaster/interrupt.h +1 -1
  264. data/ext/pg_query/include/postmaster/pgarch.h +1 -38
  265. data/ext/pg_query/include/postmaster/postmaster.h +5 -2
  266. data/ext/pg_query/include/postmaster/startup.h +3 -1
  267. data/ext/pg_query/include/postmaster/syslogger.h +2 -2
  268. data/ext/pg_query/include/postmaster/walwriter.h +3 -1
  269. data/ext/pg_query/include/protobuf/pg_query.pb-c.h +6186 -5585
  270. data/ext/pg_query/include/protobuf/pg_query.pb.h +112443 -91222
  271. data/ext/pg_query/include/regex/regex.h +9 -6
  272. data/ext/pg_query/include/replication/logicallauncher.h +6 -1
  273. data/ext/pg_query/include/replication/logicalproto.h +30 -10
  274. data/ext/pg_query/include/replication/logicalworker.h +14 -1
  275. data/ext/pg_query/include/replication/origin.h +4 -4
  276. data/ext/pg_query/include/replication/reorderbuffer.h +113 -45
  277. data/ext/pg_query/include/replication/slot.h +25 -6
  278. data/ext/pg_query/include/replication/syncrep.h +2 -8
  279. data/ext/pg_query/include/replication/walreceiver.h +15 -9
  280. data/ext/pg_query/include/replication/walsender.h +13 -13
  281. data/ext/pg_query/include/rewrite/prs2lock.h +1 -1
  282. data/ext/pg_query/include/rewrite/rewriteHandler.h +1 -4
  283. data/ext/pg_query/include/rewrite/rewriteManip.h +11 -2
  284. data/ext/pg_query/include/rewrite/rewriteSupport.h +1 -1
  285. data/ext/pg_query/include/src_backend_nodes_copyfuncs.funcs.c +5321 -0
  286. data/ext/pg_query/include/src_backend_nodes_equalfuncs.funcs.c +3354 -0
  287. data/ext/pg_query/include/storage/backendid.h +1 -1
  288. data/ext/pg_query/include/storage/block.h +24 -31
  289. data/ext/pg_query/include/storage/buf.h +1 -1
  290. data/ext/pg_query/include/storage/bufmgr.h +183 -87
  291. data/ext/pg_query/include/storage/bufpage.h +146 -93
  292. data/ext/pg_query/include/storage/condition_variable.h +2 -2
  293. data/ext/pg_query/include/storage/dsm.h +3 -6
  294. data/ext/pg_query/include/storage/dsm_impl.h +4 -1
  295. data/ext/pg_query/include/storage/fd.h +24 -20
  296. data/ext/pg_query/include/storage/fileset.h +1 -1
  297. data/ext/pg_query/include/storage/ipc.h +1 -1
  298. data/ext/pg_query/include/storage/item.h +1 -1
  299. data/ext/pg_query/include/storage/itemid.h +1 -1
  300. data/ext/pg_query/include/storage/itemptr.h +94 -57
  301. data/ext/pg_query/include/storage/large_object.h +1 -1
  302. data/ext/pg_query/include/storage/latch.h +9 -1
  303. data/ext/pg_query/include/storage/lmgr.h +6 -1
  304. data/ext/pg_query/include/storage/lock.h +21 -13
  305. data/ext/pg_query/include/storage/lockdefs.h +3 -3
  306. data/ext/pg_query/include/storage/lwlock.h +16 -2
  307. data/ext/pg_query/include/storage/off.h +1 -1
  308. data/ext/pg_query/include/storage/pg_sema.h +1 -1
  309. data/ext/pg_query/include/storage/pg_shmem.h +1 -1
  310. data/ext/pg_query/include/storage/pmsignal.h +1 -1
  311. data/ext/pg_query/include/storage/predicate.h +2 -2
  312. data/ext/pg_query/include/storage/proc.h +22 -17
  313. data/ext/pg_query/include/storage/procarray.h +3 -2
  314. data/ext/pg_query/include/storage/proclist_types.h +1 -1
  315. data/ext/pg_query/include/storage/procsignal.h +3 -1
  316. data/ext/pg_query/include/storage/relfilelocator.h +99 -0
  317. data/ext/pg_query/include/storage/s_lock.h +66 -309
  318. data/ext/pg_query/include/storage/sharedfileset.h +1 -1
  319. data/ext/pg_query/include/storage/shm_mq.h +1 -1
  320. data/ext/pg_query/include/storage/shm_toc.h +1 -1
  321. data/ext/pg_query/include/storage/shmem.h +1 -23
  322. data/ext/pg_query/include/storage/sinval.h +3 -3
  323. data/ext/pg_query/include/storage/sinvaladt.h +4 -2
  324. data/ext/pg_query/include/storage/smgr.h +12 -10
  325. data/ext/pg_query/include/storage/spin.h +1 -1
  326. data/ext/pg_query/include/storage/standby.h +9 -8
  327. data/ext/pg_query/include/storage/standbydefs.h +1 -1
  328. data/ext/pg_query/include/storage/sync.h +3 -3
  329. data/ext/pg_query/include/tcop/cmdtag.h +7 -2
  330. data/ext/pg_query/include/tcop/cmdtaglist.h +1 -1
  331. data/ext/pg_query/include/tcop/deparse_utility.h +1 -1
  332. data/ext/pg_query/include/tcop/dest.h +1 -3
  333. data/ext/pg_query/include/tcop/fastpath.h +1 -1
  334. data/ext/pg_query/include/tcop/pquery.h +1 -1
  335. data/ext/pg_query/include/tcop/tcopprot.h +1 -4
  336. data/ext/pg_query/include/tcop/utility.h +1 -1
  337. data/ext/pg_query/include/tsearch/ts_cache.h +2 -4
  338. data/ext/pg_query/include/utils/acl.h +26 -81
  339. data/ext/pg_query/include/utils/aclchk_internal.h +1 -1
  340. data/ext/pg_query/include/utils/array.h +19 -1
  341. data/ext/pg_query/include/utils/backend_progress.h +2 -1
  342. data/ext/pg_query/include/utils/backend_status.h +24 -3
  343. data/ext/pg_query/include/utils/builtins.h +14 -5
  344. data/ext/pg_query/include/utils/bytea.h +1 -1
  345. data/ext/pg_query/include/utils/catcache.h +1 -1
  346. data/ext/pg_query/include/utils/date.h +37 -9
  347. data/ext/pg_query/include/utils/datetime.h +41 -21
  348. data/ext/pg_query/include/utils/datum.h +1 -1
  349. data/ext/pg_query/include/utils/dsa.h +5 -1
  350. data/ext/pg_query/include/utils/elog.h +101 -26
  351. data/ext/pg_query/include/utils/expandeddatum.h +14 -3
  352. data/ext/pg_query/include/utils/expandedrecord.h +14 -4
  353. data/ext/pg_query/include/utils/float.h +7 -6
  354. data/ext/pg_query/include/utils/fmgroids.h +54 -1
  355. data/ext/pg_query/include/utils/fmgrprotos.h +45 -3
  356. data/ext/pg_query/include/utils/fmgrtab.h +1 -1
  357. data/ext/pg_query/include/utils/guc.h +55 -82
  358. data/ext/pg_query/include/utils/guc_hooks.h +163 -0
  359. data/ext/pg_query/include/utils/guc_tables.h +49 -3
  360. data/ext/pg_query/include/utils/hsearch.h +1 -1
  361. data/ext/pg_query/include/utils/inval.h +3 -3
  362. data/ext/pg_query/include/utils/logtape.h +77 -0
  363. data/ext/pg_query/include/utils/lsyscache.h +5 -1
  364. data/ext/pg_query/include/utils/memdebug.h +1 -1
  365. data/ext/pg_query/include/utils/memutils.h +5 -49
  366. data/ext/pg_query/include/utils/memutils_internal.h +136 -0
  367. data/ext/pg_query/include/utils/memutils_memorychunk.h +237 -0
  368. data/ext/pg_query/include/utils/numeric.h +20 -5
  369. data/ext/pg_query/include/utils/palloc.h +8 -1
  370. data/ext/pg_query/include/utils/partcache.h +3 -2
  371. data/ext/pg_query/include/utils/pg_locale.h +22 -14
  372. data/ext/pg_query/include/utils/pgstat_internal.h +37 -7
  373. data/ext/pg_query/include/utils/pidfile.h +1 -1
  374. data/ext/pg_query/include/utils/plancache.h +1 -1
  375. data/ext/pg_query/include/utils/portal.h +1 -1
  376. data/ext/pg_query/include/utils/probes.h +6 -6
  377. data/ext/pg_query/include/utils/ps_status.h +23 -1
  378. data/ext/pg_query/include/utils/queryenvironment.h +1 -1
  379. data/ext/pg_query/include/utils/regproc.h +3 -3
  380. data/ext/pg_query/include/utils/rel.h +60 -43
  381. data/ext/pg_query/include/utils/relcache.h +13 -8
  382. data/ext/pg_query/include/utils/reltrigger.h +1 -1
  383. data/ext/pg_query/include/utils/resowner.h +1 -1
  384. data/ext/pg_query/include/utils/ruleutils.h +6 -1
  385. data/ext/pg_query/include/utils/sharedtuplestore.h +1 -1
  386. data/ext/pg_query/include/utils/snapmgr.h +4 -2
  387. data/ext/pg_query/include/utils/snapshot.h +1 -1
  388. data/ext/pg_query/include/utils/sortsupport.h +2 -2
  389. data/ext/pg_query/include/utils/syscache.h +4 -1
  390. data/ext/pg_query/include/utils/timeout.h +1 -1
  391. data/ext/pg_query/include/utils/timestamp.h +41 -11
  392. data/ext/pg_query/include/utils/tuplesort.h +189 -35
  393. data/ext/pg_query/include/utils/tuplestore.h +1 -1
  394. data/ext/pg_query/include/utils/typcache.h +1 -1
  395. data/ext/pg_query/include/utils/varlena.h +13 -1
  396. data/ext/pg_query/include/utils/wait_event.h +9 -4
  397. data/ext/pg_query/include/utils/xml.h +15 -5
  398. data/ext/pg_query/include/varatt.h +358 -0
  399. data/ext/pg_query/pg_query.c +1 -1
  400. data/ext/pg_query/pg_query.pb-c.c +19755 -17757
  401. data/ext/pg_query/pg_query_fingerprint.c +8 -3
  402. data/ext/pg_query/pg_query_fingerprint.h +1 -1
  403. data/ext/pg_query/pg_query_internal.h +1 -1
  404. data/ext/pg_query/pg_query_json_plpgsql.c +1 -0
  405. data/ext/pg_query/pg_query_normalize.c +1 -1
  406. data/ext/pg_query/pg_query_outfuncs_protobuf.c +2 -2
  407. data/ext/pg_query/pg_query_parse.c +46 -4
  408. data/ext/pg_query/pg_query_parse_plpgsql.c +1 -1
  409. data/ext/pg_query/pg_query_scan.c +1 -1
  410. data/ext/pg_query/pg_query_split.c +2 -2
  411. data/ext/pg_query/postgres_deparse.c +511 -109
  412. data/ext/pg_query/src_backend_catalog_namespace.c +7 -2
  413. data/ext/pg_query/src_backend_catalog_pg_proc.c +1 -1
  414. data/ext/pg_query/src_backend_commands_define.c +1 -1
  415. data/ext/pg_query/src_backend_nodes_bitmapset.c +11 -70
  416. data/ext/pg_query/src_backend_nodes_copyfuncs.c +96 -6202
  417. data/ext/pg_query/src_backend_nodes_equalfuncs.c +95 -4068
  418. data/ext/pg_query/src_backend_nodes_extensible.c +6 -29
  419. data/ext/pg_query/src_backend_nodes_list.c +14 -2
  420. data/ext/pg_query/src_backend_nodes_makefuncs.c +95 -1
  421. data/ext/pg_query/src_backend_nodes_nodeFuncs.c +283 -132
  422. data/ext/pg_query/src_backend_nodes_value.c +1 -1
  423. data/ext/pg_query/src_backend_parser_gram.c +33208 -31806
  424. data/ext/pg_query/src_backend_parser_parser.c +28 -2
  425. data/ext/pg_query/src_backend_parser_scan.c +4318 -3329
  426. data/ext/pg_query/src_backend_parser_scansup.c +1 -1
  427. data/ext/pg_query/src_backend_postmaster_postmaster.c +129 -110
  428. data/ext/pg_query/src_backend_storage_ipc_ipc.c +1 -1
  429. data/ext/pg_query/src_backend_tcop_postgres.c +66 -87
  430. data/ext/pg_query/src_backend_utils_activity_pgstat_database.c +1 -1
  431. data/ext/pg_query/src_backend_utils_adt_datum.c +5 -7
  432. data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +1 -1
  433. data/ext/pg_query/src_backend_utils_adt_format_type.c +1 -1
  434. data/ext/pg_query/src_backend_utils_adt_numutils.c +489 -0
  435. data/ext/pg_query/src_backend_utils_adt_ruleutils.c +79 -5
  436. data/ext/pg_query/src_backend_utils_error_assert.c +4 -7
  437. data/ext/pg_query/src_backend_utils_error_elog.c +354 -97
  438. data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +33 -1
  439. data/ext/pg_query/src_backend_utils_init_globals.c +5 -2
  440. data/ext/pg_query/src_backend_utils_mb_mbutils.c +13 -4
  441. data/ext/pg_query/src_backend_utils_misc_guc_tables.c +494 -0
  442. data/ext/pg_query/src_backend_utils_mmgr_alignedalloc.c +163 -0
  443. data/ext/pg_query/src_backend_utils_mmgr_aset.c +449 -312
  444. data/ext/pg_query/src_backend_utils_mmgr_generation.c +1039 -0
  445. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +398 -49
  446. data/ext/pg_query/src_backend_utils_mmgr_slab.c +1021 -0
  447. data/ext/pg_query/src_common_encnames.c +4 -1
  448. data/ext/pg_query/src_common_hashfn.c +1 -1
  449. data/ext/pg_query/src_common_keywords.c +1 -1
  450. data/ext/pg_query/src_common_kwlist_d.h +534 -510
  451. data/ext/pg_query/src_common_kwlookup.c +1 -1
  452. data/ext/pg_query/src_common_psprintf.c +1 -1
  453. data/ext/pg_query/src_common_stringinfo.c +4 -4
  454. data/ext/pg_query/src_common_wchar.c +9 -8
  455. data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1 -1
  456. data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +3 -1
  457. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +661 -694
  458. data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +1 -1
  459. data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +1 -1
  460. data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +1 -1
  461. data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +48 -46
  462. data/ext/pg_query/src_port_pg_bitutils.c +1 -1
  463. data/ext/pg_query/src_port_pgstrcasecmp.c +29 -1
  464. data/ext/pg_query/src_port_snprintf.c +3 -7
  465. data/ext/pg_query/src_port_strerror.c +1 -1
  466. data/ext/pg_query/src_port_strnlen.c +1 -1
  467. data/lib/pg_query/pg_query_pb.rb +166 -3191
  468. data/lib/pg_query/treewalker.rb +7 -2
  469. data/lib/pg_query/version.rb +1 -1
  470. metadata +43 -24
  471. data/ext/pg_query/include/catalog/pg_parameter_acl.h +0 -60
  472. data/ext/pg_query/include/catalog/pg_parameter_acl_d.h +0 -34
  473. data/ext/pg_query/include/commands/variable.h +0 -38
  474. data/ext/pg_query/include/getaddrinfo.h +0 -162
  475. data/ext/pg_query/include/parser/gram.h +0 -1101
  476. data/ext/pg_query/include/storage/relfilenode.h +0 -99
  477. data/ext/pg_query/include/utils/dynahash.h +0 -20
  478. data/ext/pg_query/include/utils/pg_lsn.h +0 -29
  479. data/ext/pg_query/include/utils/rls.h +0 -50
  480. data/ext/pg_query/include/utils/tzparser.h +0 -39
  481. data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +0 -371
  482. data/ext/pg_query/src_backend_utils_hash_dynahash.c +0 -1116
  483. data/ext/pg_query/src_backend_utils_misc_guc.c +0 -1993
  484. data/ext/pg_query/src_common_pg_prng.c +0 -152
  485. data/ext/pg_query/src_common_string.c +0 -92
  486. data/ext/pg_query/src_port_pgsleep.c +0 -69
@@ -1,18 +1,18 @@
1
1
  /*--------------------------------------------------------------------
2
2
  * Symbols referenced in this file:
3
- * - AllocSetContextCreateInternal
4
- * - context_freelists
5
- * - AllocSetMethods
6
3
  * - AllocSetAlloc
7
4
  * - AllocSetFreeIndex
8
5
  * - AllocSetFree
9
6
  * - AllocSetRealloc
10
7
  * - AllocSetReset
11
8
  * - AllocSetDelete
9
+ * - context_freelists
10
+ * - AllocSetGetChunkContext
12
11
  * - AllocSetGetChunkSpace
13
12
  * - AllocSetIsEmpty
14
13
  * - AllocSetStats
15
14
  * - AllocSetCheck
15
+ * - AllocSetContextCreateInternal
16
16
  * - AllocSetDeleteFreeList
17
17
  *--------------------------------------------------------------------
18
18
  */
@@ -26,7 +26,7 @@
26
26
  * type.
27
27
  *
28
28
  *
29
- * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
29
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
30
30
  * Portions Copyright (c) 1994, Regents of the University of California
31
31
  *
32
32
  * IDENTIFICATION
@@ -68,6 +68,8 @@
68
68
  #include "port/pg_bitutils.h"
69
69
  #include "utils/memdebug.h"
70
70
  #include "utils/memutils.h"
71
+ #include "utils/memutils_memorychunk.h"
72
+ #include "utils/memutils_internal.h"
71
73
 
72
74
  /*--------------------
73
75
  * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
@@ -85,7 +87,9 @@
85
87
  * CAUTION: ALLOC_MINBITS must be large enough so that
86
88
  * 1<<ALLOC_MINBITS is at least MAXALIGN,
87
89
  * or we may fail to align the smallest chunks adequately.
88
- * 8-byte alignment is enough on all currently known machines.
90
+ * 8-byte alignment is enough on all currently known machines. This 8-byte
91
+ * minimum also allows us to store a pointer to the next freelist item within
92
+ * the chunk of memory itself.
89
93
  *
90
94
  * With the current parameters, request sizes up to 8K are treated as chunks,
91
95
  * larger requests go into dedicated blocks. Change ALLOCSET_NUM_FREELISTS
@@ -117,10 +121,9 @@
117
121
  */
118
122
 
119
123
  #define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
120
- #define ALLOC_CHUNKHDRSZ sizeof(struct AllocChunkData)
124
+ #define ALLOC_CHUNKHDRSZ sizeof(MemoryChunk)
121
125
 
122
126
  typedef struct AllocBlockData *AllocBlock; /* forward reference */
123
- typedef struct AllocChunkData *AllocChunk;
124
127
 
125
128
  /*
126
129
  * AllocPointer
@@ -128,6 +131,34 @@ typedef struct AllocChunkData *AllocChunk;
128
131
  */
129
132
  typedef void *AllocPointer;
130
133
 
134
+ /*
135
+ * AllocFreeListLink
136
+ * When pfreeing memory, if we maintain a freelist for the given chunk's
137
+ * size then we use a AllocFreeListLink to point to the current item in
138
+ * the AllocSetContext's freelist and then set the given freelist element
139
+ * to point to the chunk being freed.
140
+ */
141
+ typedef struct AllocFreeListLink
142
+ {
143
+ MemoryChunk *next;
144
+ } AllocFreeListLink;
145
+
146
+ /*
147
+ * Obtain a AllocFreeListLink for the given chunk. Allocation sizes are
148
+ * always at least sizeof(AllocFreeListLink), so we reuse the pointer's memory
149
+ * itself to store the freelist link.
150
+ */
151
+ #define GetFreeListLink(chkptr) \
152
+ (AllocFreeListLink *) ((char *) (chkptr) + ALLOC_CHUNKHDRSZ)
153
+
154
+ /* Validate a freelist index retrieved from a chunk header */
155
+ #define FreeListIdxIsValid(fidx) \
156
+ ((fidx) >= 0 && (fidx) < ALLOCSET_NUM_FREELISTS)
157
+
158
+ /* Determine the size of the chunk based on the freelist index */
159
+ #define GetChunkSizeFromFreeListIdx(fidx) \
160
+ ((((Size) 1) << ALLOC_MINBITS) << (fidx))
161
+
131
162
  /*
132
163
  * AllocSetContext is our standard implementation of MemoryContext.
133
164
  *
@@ -142,7 +173,7 @@ typedef struct AllocSetContext
142
173
  MemoryContextData header; /* Standard memory-context fields */
143
174
  /* Info about storage allocated in this context: */
144
175
  AllocBlock blocks; /* head of list of blocks in this set */
145
- AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
176
+ MemoryChunk *freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
146
177
  /* Allocation parameters for this context: */
147
178
  Size initBlockSize; /* initial block size */
148
179
  Size maxBlockSize; /* maximum block size */
@@ -158,8 +189,8 @@ typedef AllocSetContext *AllocSet;
158
189
  /*
159
190
  * AllocBlock
160
191
  * An AllocBlock is the unit of memory that is obtained by aset.c
161
- * from malloc(). It contains one or more AllocChunks, which are
162
- * the units requested by palloc() and freed by pfree(). AllocChunks
192
+ * from malloc(). It contains one or more MemoryChunks, which are
193
+ * the units requested by palloc() and freed by pfree(). MemoryChunks
163
194
  * cannot be returned to malloc() individually, instead they are put
164
195
  * on freelists by pfree() and re-used by the next palloc() that has
165
196
  * a matching request size.
@@ -176,50 +207,6 @@ typedef struct AllocBlockData
176
207
  char *endptr; /* end of space in this block */
177
208
  } AllocBlockData;
178
209
 
179
- /*
180
- * AllocChunk
181
- * The prefix of each piece of memory in an AllocBlock
182
- *
183
- * Note: to meet the memory context APIs, the payload area of the chunk must
184
- * be maxaligned, and the "aset" link must be immediately adjacent to the
185
- * payload area (cf. GetMemoryChunkContext). We simplify matters for this
186
- * module by requiring sizeof(AllocChunkData) to be maxaligned, and then
187
- * we can ensure things work by adding any required alignment padding before
188
- * the "aset" field. There is a static assertion below that the alignment
189
- * is done correctly.
190
- */
191
- typedef struct AllocChunkData
192
- {
193
- /* size is always the size of the usable space in the chunk */
194
- Size size;
195
- #ifdef MEMORY_CONTEXT_CHECKING
196
- /* when debugging memory usage, also store actual requested size */
197
- /* this is zero in a free chunk */
198
- Size requested_size;
199
-
200
- #define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P)
201
- #else
202
- #define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P)
203
- #endif /* MEMORY_CONTEXT_CHECKING */
204
-
205
- /* ensure proper alignment by adding padding if needed */
206
- #if (ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0
207
- char padding[MAXIMUM_ALIGNOF - ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF];
208
- #endif
209
-
210
- /* aset is the owning aset if allocated, or the freelist link if free */
211
- void *aset;
212
- /* there must not be any padding to reach a MAXALIGN boundary here! */
213
- } AllocChunkData;
214
-
215
- /*
216
- * Only the "aset" field should be accessed outside this module.
217
- * We keep the rest of an allocated chunk's header marked NOACCESS when using
218
- * valgrind. But note that chunk headers that are in a freelist are kept
219
- * accessible, for simplicity.
220
- */
221
- #define ALLOCCHUNK_PRIVATE_LEN offsetof(AllocChunkData, aset)
222
-
223
210
  /*
224
211
  * AllocPointerIsValid
225
212
  * True iff pointer is valid allocation pointer.
@@ -230,12 +217,23 @@ typedef struct AllocChunkData
230
217
  * AllocSetIsValid
231
218
  * True iff set is valid allocation set.
232
219
  */
233
- #define AllocSetIsValid(set) PointerIsValid(set)
220
+ #define AllocSetIsValid(set) \
221
+ (PointerIsValid(set) && IsA(set, AllocSetContext))
234
222
 
235
- #define AllocPointerGetChunk(ptr) \
236
- ((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
237
- #define AllocChunkGetPointer(chk) \
238
- ((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))
223
+ /*
224
+ * AllocBlockIsValid
225
+ * True iff block is valid block of allocation set.
226
+ */
227
+ #define AllocBlockIsValid(block) \
228
+ (PointerIsValid(block) && AllocSetIsValid((block)->aset))
229
+
230
+ /*
231
+ * We always store external chunks on a dedicated block. This makes fetching
232
+ * the block from an external chunk easy since it's always the first and only
233
+ * chunk on the block.
234
+ */
235
+ #define ExternalChunkGetBlock(chunk) \
236
+ (AllocBlock) ((char *) chunk - ALLOC_BLOCKHDRSZ)
239
237
 
240
238
  /*
241
239
  * Rather than repeatedly creating and deleting memory contexts, we keep some
@@ -280,42 +278,6 @@ static __thread AllocSetFreeList context_freelists[2] =
280
278
  };
281
279
 
282
280
 
283
- /*
284
- * These functions implement the MemoryContext API for AllocSet contexts.
285
- */
286
- static void *AllocSetAlloc(MemoryContext context, Size size);
287
- static void AllocSetFree(MemoryContext context, void *pointer);
288
- static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
289
- static void AllocSetReset(MemoryContext context);
290
- static void AllocSetDelete(MemoryContext context);
291
- static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer);
292
- static bool AllocSetIsEmpty(MemoryContext context);
293
- static void AllocSetStats(MemoryContext context,
294
- MemoryStatsPrintFunc printfunc, void *passthru,
295
- MemoryContextCounters *totals,
296
- bool print_to_stderr);
297
-
298
- #ifdef MEMORY_CONTEXT_CHECKING
299
- static void AllocSetCheck(MemoryContext context);
300
- #endif
301
-
302
- /*
303
- * This is the virtual function table for AllocSet contexts.
304
- */
305
- static const MemoryContextMethods AllocSetMethods = {
306
- AllocSetAlloc,
307
- AllocSetFree,
308
- AllocSetRealloc,
309
- AllocSetReset,
310
- AllocSetDelete,
311
- AllocSetGetChunkSpace,
312
- AllocSetIsEmpty,
313
- AllocSetStats
314
- #ifdef MEMORY_CONTEXT_CHECKING
315
- ,AllocSetCheck
316
- #endif
317
- };
318
-
319
281
 
320
282
  /* ----------
321
283
  * AllocSetFreeIndex -
@@ -339,7 +301,7 @@ AllocSetFreeIndex(Size size)
339
301
  * or equivalently
340
302
  * pg_leftmost_one_pos32(size - 1) - ALLOC_MINBITS + 1
341
303
  *
342
- * However, rather than just calling that function, we duplicate the
304
+ * However, for platforms without intrinsic support, we duplicate the
343
305
  * logic here, allowing an additional optimization. It's reasonable
344
306
  * to assume that ALLOC_CHUNK_LIMIT fits in 16 bits, so we can unroll
345
307
  * the byte-at-a-time loop in pg_leftmost_one_pos32 and just handle
@@ -349,14 +311,14 @@ AllocSetFreeIndex(Size size)
349
311
  * much trouble.
350
312
  *----------
351
313
  */
352
- #ifdef HAVE__BUILTIN_CLZ
353
- idx = 31 - __builtin_clz((uint32) size - 1) - ALLOC_MINBITS + 1;
314
+ #ifdef HAVE_BITSCAN_REVERSE
315
+ idx = pg_leftmost_one_pos32((uint32) size - 1) - ALLOC_MINBITS + 1;
354
316
  #else
355
317
  uint32 t,
356
318
  tsize;
357
319
 
358
320
  /* Statically assert that we only have a 16-bit input value. */
359
- StaticAssertStmt(ALLOC_CHUNK_LIMIT < (1 << 16),
321
+ StaticAssertDecl(ALLOC_CHUNK_LIMIT < (1 << 16),
360
322
  "ALLOC_CHUNK_LIMIT must be less than 64kB");
361
323
 
362
324
  tsize = size - 1;
@@ -407,18 +369,24 @@ AllocSetContextCreateInternal(MemoryContext parent,
407
369
  AllocSet set;
408
370
  AllocBlock block;
409
371
 
410
- /* Assert we padded AllocChunkData properly */
411
- StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
412
- "sizeof(AllocChunkData) is not maxaligned");
413
- StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
414
- ALLOC_CHUNKHDRSZ,
415
- "padding calculation in AllocChunkData is wrong");
372
+ /* ensure MemoryChunk's size is properly maxaligned */
373
+ StaticAssertDecl(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
374
+ "sizeof(MemoryChunk) is not maxaligned");
375
+ /* check we have enough space to store the freelist link */
376
+ StaticAssertDecl(sizeof(AllocFreeListLink) <= (1 << ALLOC_MINBITS),
377
+ "sizeof(AllocFreeListLink) larger than minimum allocation size");
416
378
 
417
379
  /*
418
380
  * First, validate allocation parameters. Once these were regular runtime
419
- * test and elog's, but in practice Asserts seem sufficient because nobody
420
- * varies their parameters at runtime. We somewhat arbitrarily enforce a
421
- * minimum 1K block size.
381
+ * tests and elog's, but in practice Asserts seem sufficient because
382
+ * nobody varies their parameters at runtime. We somewhat arbitrarily
383
+ * enforce a minimum 1K block size. We restrict the maximum block size to
384
+ * MEMORYCHUNK_MAX_BLOCKOFFSET as MemoryChunks are limited to this in
385
+ * regards to addressing the offset between the chunk and the block that
386
+ * the chunk is stored on. We would be unable to store the offset between
387
+ * the chunk and block for any chunks that were beyond
388
+ * MEMORYCHUNK_MAX_BLOCKOFFSET bytes into the block if the block was to be
389
+ * larger than this.
422
390
  */
423
391
  Assert(initBlockSize == MAXALIGN(initBlockSize) &&
424
392
  initBlockSize >= 1024);
@@ -429,6 +397,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
429
397
  (minContextSize == MAXALIGN(minContextSize) &&
430
398
  minContextSize >= 1024 &&
431
399
  minContextSize <= maxBlockSize));
400
+ Assert(maxBlockSize <= MEMORYCHUNK_MAX_BLOCKOFFSET);
432
401
 
433
402
  /*
434
403
  * Check whether the parameters match either available freelist. We do
@@ -463,7 +432,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
463
432
  /* Reinitialize its header, installing correct name and parent */
464
433
  MemoryContextCreate((MemoryContext) set,
465
434
  T_AllocSetContext,
466
- &AllocSetMethods,
435
+ MCTX_ASET_ID,
467
436
  parent,
468
437
  name);
469
438
 
@@ -537,15 +506,20 @@ AllocSetContextCreateInternal(MemoryContext parent,
537
506
  * requests that are all the maximum chunk size we will waste at most
538
507
  * 1/8th of the allocated space.
539
508
  *
540
- * We have to have allocChunkLimit a power of two, because the requested
541
- * and actually-allocated sizes of any chunk must be on the same side of
542
- * the limit, else we get confused about whether the chunk is "big".
543
- *
544
509
  * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD.
545
510
  */
546
511
  StaticAssertStmt(ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD,
547
512
  "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD");
548
513
 
514
+ /*
515
+ * Determine the maximum size that a chunk can be before we allocate an
516
+ * entire AllocBlock dedicated for that chunk. We set the absolute limit
517
+ * of that size as ALLOC_CHUNK_LIMIT but we reduce it further so that we
518
+ * can fit about ALLOC_CHUNK_FRACTION chunks this size on a maximally
519
+ * sized block. (We opt to keep allocChunkLimit a power-of-2 value
520
+ * primarily for legacy reasons rather than calculating it so that exactly
521
+ * ALLOC_CHUNK_FRACTION chunks fit on a maximally sized block.)
522
+ */
549
523
  set->allocChunkLimit = ALLOC_CHUNK_LIMIT;
550
524
  while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) >
551
525
  (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION))
@@ -554,7 +528,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
554
528
  /* Finally, do the type-independent part of context creation */
555
529
  MemoryContextCreate((MemoryContext) set,
556
530
  T_AllocSetContext,
557
- &AllocSetMethods,
531
+ MCTX_ASET_ID,
558
532
  parent,
559
533
  name);
560
534
 
@@ -575,21 +549,23 @@ AllocSetContextCreateInternal(MemoryContext parent,
575
549
  * thrash malloc() when a context is repeatedly reset after small allocations,
576
550
  * which is typical behavior for per-tuple contexts.
577
551
  */
578
- static void
552
+ void
579
553
  AllocSetReset(MemoryContext context)
580
554
  {
581
555
  AllocSet set = (AllocSet) context;
582
556
  AllocBlock block;
583
- Size keepersize PG_USED_FOR_ASSERTS_ONLY
584
- = set->keeper->endptr - ((char *) set);
557
+ Size keepersize PG_USED_FOR_ASSERTS_ONLY;
585
558
 
586
- AssertArg(AllocSetIsValid(set));
559
+ Assert(AllocSetIsValid(set));
587
560
 
588
561
  #ifdef MEMORY_CONTEXT_CHECKING
589
562
  /* Check for corruption and leaks before freeing */
590
563
  AllocSetCheck(context);
591
564
  #endif
592
565
 
566
+ /* Remember keeper block size for Assert below */
567
+ keepersize = set->keeper->endptr - ((char *) set);
568
+
593
569
  /* Clear chunk freelists */
594
570
  MemSetAligned(set->freelist, 0, sizeof(set->freelist));
595
571
 
@@ -643,21 +619,23 @@ AllocSetReset(MemoryContext context)
643
619
  *
644
620
  * Unlike AllocSetReset, this *must* free all resources of the set.
645
621
  */
646
- static void
622
+ void
647
623
  AllocSetDelete(MemoryContext context)
648
624
  {
649
625
  AllocSet set = (AllocSet) context;
650
626
  AllocBlock block = set->blocks;
651
- Size keepersize PG_USED_FOR_ASSERTS_ONLY
652
- = set->keeper->endptr - ((char *) set);
627
+ Size keepersize PG_USED_FOR_ASSERTS_ONLY;
653
628
 
654
- AssertArg(AllocSetIsValid(set));
629
+ Assert(AllocSetIsValid(set));
655
630
 
656
631
  #ifdef MEMORY_CONTEXT_CHECKING
657
632
  /* Check for corruption and leaks before freeing */
658
633
  AllocSetCheck(context);
659
634
  #endif
660
635
 
636
+ /* Remember keeper block size for Assert below */
637
+ keepersize = set->keeper->endptr - ((char *) set);
638
+
661
639
  /*
662
640
  * If the context is a candidate for a freelist, put it into that freelist
663
641
  * instead of destroying it.
@@ -737,17 +715,17 @@ AllocSetDelete(MemoryContext context)
737
715
  * is marked, as mcxt.c will set it to UNDEFINED. In some paths we will
738
716
  * return space that is marked NOACCESS - AllocSetRealloc has to beware!
739
717
  */
740
- static void *
718
+ void *
741
719
  AllocSetAlloc(MemoryContext context, Size size)
742
720
  {
743
721
  AllocSet set = (AllocSet) context;
744
722
  AllocBlock block;
745
- AllocChunk chunk;
723
+ MemoryChunk *chunk;
746
724
  int fidx;
747
725
  Size chunk_size;
748
726
  Size blksize;
749
727
 
750
- AssertArg(AllocSetIsValid(set));
728
+ Assert(AllocSetIsValid(set));
751
729
 
752
730
  /*
753
731
  * If requested size exceeds maximum for chunks, allocate an entire block
@@ -755,7 +733,13 @@ AllocSetAlloc(MemoryContext context, Size size)
755
733
  */
756
734
  if (size > set->allocChunkLimit)
757
735
  {
736
+ #ifdef MEMORY_CONTEXT_CHECKING
737
+ /* ensure there's always space for the sentinel byte */
738
+ chunk_size = MAXALIGN(size + 1);
739
+ #else
758
740
  chunk_size = MAXALIGN(size);
741
+ #endif
742
+
759
743
  blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
760
744
  block = (AllocBlock) malloc(blksize);
761
745
  if (block == NULL)
@@ -766,18 +750,20 @@ AllocSetAlloc(MemoryContext context, Size size)
766
750
  block->aset = set;
767
751
  block->freeptr = block->endptr = ((char *) block) + blksize;
768
752
 
769
- chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
770
- chunk->aset = set;
771
- chunk->size = chunk_size;
753
+ chunk = (MemoryChunk *) (((char *) block) + ALLOC_BLOCKHDRSZ);
754
+
755
+ /* mark the MemoryChunk as externally managed */
756
+ MemoryChunkSetHdrMaskExternal(chunk, MCTX_ASET_ID);
757
+
772
758
  #ifdef MEMORY_CONTEXT_CHECKING
773
759
  chunk->requested_size = size;
774
760
  /* set mark to catch clobber of "unused" space */
775
- if (size < chunk_size)
776
- set_sentinel(AllocChunkGetPointer(chunk), size);
761
+ Assert(size < chunk_size);
762
+ set_sentinel(MemoryChunkGetPointer(chunk), size);
777
763
  #endif
778
764
  #ifdef RANDOMIZE_ALLOCATED_MEMORY
779
765
  /* fill the allocated space with junk */
780
- randomize_mem((char *) AllocChunkGetPointer(chunk), size);
766
+ randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
781
767
  #endif
782
768
 
783
769
  /*
@@ -800,13 +786,13 @@ AllocSetAlloc(MemoryContext context, Size size)
800
786
  }
801
787
 
802
788
  /* Ensure any padding bytes are marked NOACCESS. */
803
- VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
789
+ VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
804
790
  chunk_size - size);
805
791
 
806
- /* Disallow external access to private part of chunk header. */
807
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
792
+ /* Disallow access to the chunk header. */
793
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
808
794
 
809
- return AllocChunkGetPointer(chunk);
795
+ return MemoryChunkGetPointer(chunk);
810
796
  }
811
797
 
812
798
  /*
@@ -814,42 +800,54 @@ AllocSetAlloc(MemoryContext context, Size size)
814
800
  * corresponding free list to see if there is a free chunk we could reuse.
815
801
  * If one is found, remove it from the free list, make it again a member
816
802
  * of the alloc set and return its data address.
803
+ *
804
+ * Note that we don't attempt to ensure there's space for the sentinel
805
+ * byte here. We expect a large proportion of allocations to be for sizes
806
+ * which are already a power of 2. If we were to always make space for a
807
+ * sentinel byte in MEMORY_CONTEXT_CHECKING builds, then we'd end up
808
+ * doubling the memory requirements for such allocations.
817
809
  */
818
810
  fidx = AllocSetFreeIndex(size);
819
811
  chunk = set->freelist[fidx];
820
812
  if (chunk != NULL)
821
813
  {
822
- Assert(chunk->size >= size);
814
+ AllocFreeListLink *link = GetFreeListLink(chunk);
815
+
816
+ /* Allow access to the chunk header. */
817
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
823
818
 
824
- set->freelist[fidx] = (AllocChunk) chunk->aset;
819
+ Assert(fidx == MemoryChunkGetValue(chunk));
825
820
 
826
- chunk->aset = (void *) set;
821
+ /* pop this chunk off the freelist */
822
+ VALGRIND_MAKE_MEM_DEFINED(link, sizeof(AllocFreeListLink));
823
+ set->freelist[fidx] = link->next;
824
+ VALGRIND_MAKE_MEM_NOACCESS(link, sizeof(AllocFreeListLink));
827
825
 
828
826
  #ifdef MEMORY_CONTEXT_CHECKING
829
827
  chunk->requested_size = size;
830
828
  /* set mark to catch clobber of "unused" space */
831
- if (size < chunk->size)
832
- set_sentinel(AllocChunkGetPointer(chunk), size);
829
+ if (size < GetChunkSizeFromFreeListIdx(fidx))
830
+ set_sentinel(MemoryChunkGetPointer(chunk), size);
833
831
  #endif
834
832
  #ifdef RANDOMIZE_ALLOCATED_MEMORY
835
833
  /* fill the allocated space with junk */
836
- randomize_mem((char *) AllocChunkGetPointer(chunk), size);
834
+ randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
837
835
  #endif
838
836
 
839
837
  /* Ensure any padding bytes are marked NOACCESS. */
840
- VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
841
- chunk->size - size);
838
+ VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
839
+ GetChunkSizeFromFreeListIdx(fidx) - size);
842
840
 
843
- /* Disallow external access to private part of chunk header. */
844
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
841
+ /* Disallow access to the chunk header. */
842
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
845
843
 
846
- return AllocChunkGetPointer(chunk);
844
+ return MemoryChunkGetPointer(chunk);
847
845
  }
848
846
 
849
847
  /*
850
848
  * Choose the actual chunk size to allocate.
851
849
  */
852
- chunk_size = (1 << ALLOC_MINBITS) << fidx;
850
+ chunk_size = GetChunkSizeFromFreeListIdx(fidx);
853
851
  Assert(chunk_size >= size);
854
852
 
855
853
  /*
@@ -876,6 +874,7 @@ AllocSetAlloc(MemoryContext context, Size size)
876
874
  */
877
875
  while (availspace >= ((1 << ALLOC_MINBITS) + ALLOC_CHUNKHDRSZ))
878
876
  {
877
+ AllocFreeListLink *link;
879
878
  Size availchunk = availspace - ALLOC_CHUNKHDRSZ;
880
879
  int a_fidx = AllocSetFreeIndex(availchunk);
881
880
 
@@ -884,29 +883,34 @@ AllocSetAlloc(MemoryContext context, Size size)
884
883
  * freelist than the one we need to put this chunk on. The
885
884
  * exception is when availchunk is exactly a power of 2.
886
885
  */
887
- if (availchunk != ((Size) 1 << (a_fidx + ALLOC_MINBITS)))
886
+ if (availchunk != GetChunkSizeFromFreeListIdx(a_fidx))
888
887
  {
889
888
  a_fidx--;
890
889
  Assert(a_fidx >= 0);
891
- availchunk = ((Size) 1 << (a_fidx + ALLOC_MINBITS));
890
+ availchunk = GetChunkSizeFromFreeListIdx(a_fidx);
892
891
  }
893
892
 
894
- chunk = (AllocChunk) (block->freeptr);
893
+ chunk = (MemoryChunk *) (block->freeptr);
895
894
 
896
895
  /* Prepare to initialize the chunk header. */
897
896
  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
898
-
899
897
  block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
900
898
  availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
901
899
 
902
- chunk->size = availchunk;
900
+ /* store the freelist index in the value field */
901
+ MemoryChunkSetHdrMask(chunk, block, a_fidx, MCTX_ASET_ID);
903
902
  #ifdef MEMORY_CONTEXT_CHECKING
904
- chunk->requested_size = 0; /* mark it free */
903
+ chunk->requested_size = InvalidAllocSize; /* mark it free */
905
904
  #endif
906
- chunk->aset = (void *) set->freelist[a_fidx];
905
+ /* push this chunk onto the free list */
906
+ link = GetFreeListLink(chunk);
907
+
908
+ VALGRIND_MAKE_MEM_DEFINED(link, sizeof(AllocFreeListLink));
909
+ link->next = set->freelist[a_fidx];
910
+ VALGRIND_MAKE_MEM_NOACCESS(link, sizeof(AllocFreeListLink));
911
+
907
912
  set->freelist[a_fidx] = chunk;
908
913
  }
909
-
910
914
  /* Mark that we need to create a new block */
911
915
  block = NULL;
912
916
  }
@@ -974,7 +978,7 @@ AllocSetAlloc(MemoryContext context, Size size)
974
978
  /*
975
979
  * OK, do the allocation
976
980
  */
977
- chunk = (AllocChunk) (block->freeptr);
981
+ chunk = (MemoryChunk *) (block->freeptr);
978
982
 
979
983
  /* Prepare to initialize the chunk header. */
980
984
  VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
@@ -982,69 +986,67 @@ AllocSetAlloc(MemoryContext context, Size size)
982
986
  block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
983
987
  Assert(block->freeptr <= block->endptr);
984
988
 
985
- chunk->aset = (void *) set;
986
- chunk->size = chunk_size;
989
+ /* store the free list index in the value field */
990
+ MemoryChunkSetHdrMask(chunk, block, fidx, MCTX_ASET_ID);
991
+
987
992
  #ifdef MEMORY_CONTEXT_CHECKING
988
993
  chunk->requested_size = size;
989
994
  /* set mark to catch clobber of "unused" space */
990
- if (size < chunk->size)
991
- set_sentinel(AllocChunkGetPointer(chunk), size);
995
+ if (size < chunk_size)
996
+ set_sentinel(MemoryChunkGetPointer(chunk), size);
992
997
  #endif
993
998
  #ifdef RANDOMIZE_ALLOCATED_MEMORY
994
999
  /* fill the allocated space with junk */
995
- randomize_mem((char *) AllocChunkGetPointer(chunk), size);
1000
+ randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
996
1001
  #endif
997
1002
 
998
1003
  /* Ensure any padding bytes are marked NOACCESS. */
999
- VALGRIND_MAKE_MEM_NOACCESS((char *) AllocChunkGetPointer(chunk) + size,
1004
+ VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
1000
1005
  chunk_size - size);
1001
1006
 
1002
- /* Disallow external access to private part of chunk header. */
1003
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1007
+ /* Disallow access to the chunk header. */
1008
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1004
1009
 
1005
- return AllocChunkGetPointer(chunk);
1010
+ return MemoryChunkGetPointer(chunk);
1006
1011
  }
1007
1012
 
1008
1013
  /*
1009
1014
  * AllocSetFree
1010
1015
  * Frees allocated memory; memory is removed from the set.
1011
1016
  */
1012
- static void
1013
- AllocSetFree(MemoryContext context, void *pointer)
1017
+ void
1018
+ AllocSetFree(void *pointer)
1014
1019
  {
1015
- AllocSet set = (AllocSet) context;
1016
- AllocChunk chunk = AllocPointerGetChunk(pointer);
1017
-
1018
- /* Allow access to private part of chunk header. */
1019
- VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
1020
+ AllocSet set;
1021
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
1020
1022
 
1021
- #ifdef MEMORY_CONTEXT_CHECKING
1022
- /* Test for someone scribbling on unused space in chunk */
1023
- if (chunk->requested_size < chunk->size)
1024
- if (!sentinel_ok(pointer, chunk->requested_size))
1025
- elog(WARNING, "detected write past chunk end in %s %p",
1026
- set->header.name, chunk);
1027
- #endif
1023
+ /* Allow access to the chunk header. */
1024
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1028
1025
 
1029
- if (chunk->size > set->allocChunkLimit)
1026
+ if (MemoryChunkIsExternal(chunk))
1030
1027
  {
1031
- /*
1032
- * Big chunks are certain to have been allocated as single-chunk
1033
- * blocks. Just unlink that block and return it to malloc().
1034
- */
1035
- AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
1028
+ /* Release single-chunk block. */
1029
+ AllocBlock block = ExternalChunkGetBlock(chunk);
1036
1030
 
1037
1031
  /*
1038
- * Try to verify that we have a sane block pointer: it should
1039
- * reference the correct aset, and freeptr and endptr should point
1040
- * just past the chunk.
1032
+ * Try to verify that we have a sane block pointer: the block header
1033
+ * should reference an aset and the freeptr should match the endptr.
1041
1034
  */
1042
- if (block->aset != set ||
1043
- block->freeptr != block->endptr ||
1044
- block->freeptr != ((char *) block) +
1045
- (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1035
+ if (!AllocBlockIsValid(block) || block->freeptr != block->endptr)
1046
1036
  elog(ERROR, "could not find block containing chunk %p", chunk);
1047
1037
 
1038
+ set = block->aset;
1039
+
1040
+ #ifdef MEMORY_CONTEXT_CHECKING
1041
+ {
1042
+ /* Test for someone scribbling on unused space in chunk */
1043
+ Assert(chunk->requested_size < (block->endptr - (char *) pointer));
1044
+ if (!sentinel_ok(pointer, chunk->requested_size))
1045
+ elog(WARNING, "detected write past chunk end in %s %p",
1046
+ set->header.name, chunk);
1047
+ }
1048
+ #endif
1049
+
1048
1050
  /* OK, remove block from aset's list and free it */
1049
1051
  if (block->prev)
1050
1052
  block->prev->next = block->next;
@@ -1053,7 +1055,7 @@ AllocSetFree(MemoryContext context, void *pointer)
1053
1055
  if (block->next)
1054
1056
  block->next->prev = block->prev;
1055
1057
 
1056
- context->mem_allocated -= block->endptr - ((char *) block);
1058
+ set->header.mem_allocated -= block->endptr - ((char *) block);
1057
1059
 
1058
1060
  #ifdef CLOBBER_FREED_MEMORY
1059
1061
  wipe_mem(block, block->freeptr - ((char *) block));
@@ -1062,20 +1064,48 @@ AllocSetFree(MemoryContext context, void *pointer)
1062
1064
  }
1063
1065
  else
1064
1066
  {
1065
- /* Normal case, put the chunk into appropriate freelist */
1066
- int fidx = AllocSetFreeIndex(chunk->size);
1067
+ AllocBlock block = MemoryChunkGetBlock(chunk);
1068
+ int fidx;
1069
+ AllocFreeListLink *link;
1070
+
1071
+ /*
1072
+ * In this path, for speed reasons we just Assert that the referenced
1073
+ * block is good. We can also Assert that the value field is sane.
1074
+ * Future field experience may show that these Asserts had better
1075
+ * become regular runtime test-and-elog checks.
1076
+ */
1077
+ Assert(AllocBlockIsValid(block));
1078
+ set = block->aset;
1067
1079
 
1068
- chunk->aset = (void *) set->freelist[fidx];
1080
+ fidx = MemoryChunkGetValue(chunk);
1081
+ Assert(FreeListIdxIsValid(fidx));
1082
+ link = GetFreeListLink(chunk);
1083
+
1084
+ #ifdef MEMORY_CONTEXT_CHECKING
1085
+ /* Test for someone scribbling on unused space in chunk */
1086
+ if (chunk->requested_size < GetChunkSizeFromFreeListIdx(fidx))
1087
+ if (!sentinel_ok(pointer, chunk->requested_size))
1088
+ elog(WARNING, "detected write past chunk end in %s %p",
1089
+ set->header.name, chunk);
1090
+ #endif
1069
1091
 
1070
1092
  #ifdef CLOBBER_FREED_MEMORY
1071
- wipe_mem(pointer, chunk->size);
1093
+ wipe_mem(pointer, GetChunkSizeFromFreeListIdx(fidx));
1072
1094
  #endif
1095
+ /* push this chunk onto the top of the free list */
1096
+ VALGRIND_MAKE_MEM_DEFINED(link, sizeof(AllocFreeListLink));
1097
+ link->next = set->freelist[fidx];
1098
+ VALGRIND_MAKE_MEM_NOACCESS(link, sizeof(AllocFreeListLink));
1099
+ set->freelist[fidx] = chunk;
1073
1100
 
1074
1101
  #ifdef MEMORY_CONTEXT_CHECKING
1075
- /* Reset requested_size to 0 in chunks that are on freelist */
1076
- chunk->requested_size = 0;
1102
+
1103
+ /*
1104
+ * Reset requested_size to InvalidAllocSize in chunks that are on free
1105
+ * list.
1106
+ */
1107
+ chunk->requested_size = InvalidAllocSize;
1077
1108
  #endif
1078
- set->freelist[fidx] = chunk;
1079
1109
  }
1080
1110
  }
1081
1111
 
@@ -1091,57 +1121,56 @@ AllocSetFree(MemoryContext context, void *pointer)
1091
1121
  * (In principle, we could use VALGRIND_GET_VBITS() to rediscover the old
1092
1122
  * request size.)
1093
1123
  */
1094
- static void *
1095
- AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1124
+ void *
1125
+ AllocSetRealloc(void *pointer, Size size)
1096
1126
  {
1097
- AllocSet set = (AllocSet) context;
1098
- AllocChunk chunk = AllocPointerGetChunk(pointer);
1099
- Size oldsize;
1100
-
1101
- /* Allow access to private part of chunk header. */
1102
- VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
1103
-
1104
- oldsize = chunk->size;
1127
+ AllocBlock block;
1128
+ AllocSet set;
1129
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
1130
+ Size oldchksize;
1131
+ int fidx;
1105
1132
 
1106
- #ifdef MEMORY_CONTEXT_CHECKING
1107
- /* Test for someone scribbling on unused space in chunk */
1108
- if (chunk->requested_size < oldsize)
1109
- if (!sentinel_ok(pointer, chunk->requested_size))
1110
- elog(WARNING, "detected write past chunk end in %s %p",
1111
- set->header.name, chunk);
1112
- #endif
1133
+ /* Allow access to the chunk header. */
1134
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1113
1135
 
1114
- if (oldsize > set->allocChunkLimit)
1136
+ if (MemoryChunkIsExternal(chunk))
1115
1137
  {
1116
1138
  /*
1117
1139
  * The chunk must have been allocated as a single-chunk block. Use
1118
1140
  * realloc() to make the containing block bigger, or smaller, with
1119
1141
  * minimum space wastage.
1120
1142
  */
1121
- AllocBlock block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
1122
1143
  Size chksize;
1123
1144
  Size blksize;
1124
1145
  Size oldblksize;
1125
1146
 
1147
+ block = ExternalChunkGetBlock(chunk);
1148
+
1126
1149
  /*
1127
- * Try to verify that we have a sane block pointer: it should
1128
- * reference the correct aset, and freeptr and endptr should point
1129
- * just past the chunk.
1150
+ * Try to verify that we have a sane block pointer: the block header
1151
+ * should reference an aset and the freeptr should match the endptr.
1130
1152
  */
1131
- if (block->aset != set ||
1132
- block->freeptr != block->endptr ||
1133
- block->freeptr != ((char *) block) +
1134
- (oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
1153
+ if (!AllocBlockIsValid(block) || block->freeptr != block->endptr)
1135
1154
  elog(ERROR, "could not find block containing chunk %p", chunk);
1136
1155
 
1137
- /*
1138
- * Even if the new request is less than set->allocChunkLimit, we stick
1139
- * with the single-chunk block approach. Therefore we need
1140
- * chunk->size to be bigger than set->allocChunkLimit, so we don't get
1141
- * confused about the chunk's status in future calls.
1142
- */
1143
- chksize = Max(size, set->allocChunkLimit + 1);
1144
- chksize = MAXALIGN(chksize);
1156
+ set = block->aset;
1157
+
1158
+ oldchksize = block->endptr - (char *) pointer;
1159
+
1160
+ #ifdef MEMORY_CONTEXT_CHECKING
1161
+ /* Test for someone scribbling on unused space in chunk */
1162
+ Assert(chunk->requested_size < oldchksize);
1163
+ if (!sentinel_ok(pointer, chunk->requested_size))
1164
+ elog(WARNING, "detected write past chunk end in %s %p",
1165
+ set->header.name, chunk);
1166
+ #endif
1167
+
1168
+ #ifdef MEMORY_CONTEXT_CHECKING
1169
+ /* ensure there's always space for the sentinel byte */
1170
+ chksize = MAXALIGN(size + 1);
1171
+ #else
1172
+ chksize = MAXALIGN(size);
1173
+ #endif
1145
1174
 
1146
1175
  /* Do the realloc */
1147
1176
  blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
@@ -1150,77 +1179,109 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1150
1179
  block = (AllocBlock) realloc(block, blksize);
1151
1180
  if (block == NULL)
1152
1181
  {
1153
- /* Disallow external access to private part of chunk header. */
1154
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1182
+ /* Disallow access to the chunk header. */
1183
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1155
1184
  return NULL;
1156
1185
  }
1157
1186
 
1158
1187
  /* updated separately, not to underflow when (oldblksize > blksize) */
1159
- context->mem_allocated -= oldblksize;
1160
- context->mem_allocated += blksize;
1188
+ set->header.mem_allocated -= oldblksize;
1189
+ set->header.mem_allocated += blksize;
1161
1190
 
1162
1191
  block->freeptr = block->endptr = ((char *) block) + blksize;
1163
1192
 
1164
1193
  /* Update pointers since block has likely been moved */
1165
- chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
1166
- pointer = AllocChunkGetPointer(chunk);
1194
+ chunk = (MemoryChunk *) (((char *) block) + ALLOC_BLOCKHDRSZ);
1195
+ pointer = MemoryChunkGetPointer(chunk);
1167
1196
  if (block->prev)
1168
1197
  block->prev->next = block;
1169
1198
  else
1170
1199
  set->blocks = block;
1171
1200
  if (block->next)
1172
1201
  block->next->prev = block;
1173
- chunk->size = chksize;
1174
1202
 
1175
1203
  #ifdef MEMORY_CONTEXT_CHECKING
1176
1204
  #ifdef RANDOMIZE_ALLOCATED_MEMORY
1177
- /* We can only fill the extra space if we know the prior request */
1205
+
1206
+ /*
1207
+ * We can only randomize the extra space if we know the prior request.
1208
+ * When using Valgrind, randomize_mem() also marks memory UNDEFINED.
1209
+ */
1178
1210
  if (size > chunk->requested_size)
1179
1211
  randomize_mem((char *) pointer + chunk->requested_size,
1180
1212
  size - chunk->requested_size);
1181
- #endif
1213
+ #else
1182
1214
 
1183
1215
  /*
1184
- * realloc() (or randomize_mem()) will have left any newly-allocated
1185
- * part UNDEFINED, but we may need to adjust trailing bytes from the
1186
- * old allocation.
1216
+ * If this is an increase, realloc() will have marked any
1217
+ * newly-allocated part (from oldchksize to chksize) UNDEFINED, but we
1218
+ * also need to adjust trailing bytes from the old allocation (from
1219
+ * chunk->requested_size to oldchksize) as they are marked NOACCESS.
1220
+ * Make sure not to mark too many bytes in case chunk->requested_size
1221
+ * < size < oldchksize.
1187
1222
  */
1188
1223
  #ifdef USE_VALGRIND
1189
- if (oldsize > chunk->requested_size)
1224
+ if (Min(size, oldchksize) > chunk->requested_size)
1190
1225
  VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + chunk->requested_size,
1191
- oldsize - chunk->requested_size);
1226
+ Min(size, oldchksize) - chunk->requested_size);
1227
+ #endif
1192
1228
  #endif
1193
1229
 
1194
1230
  chunk->requested_size = size;
1195
-
1196
1231
  /* set mark to catch clobber of "unused" space */
1197
- if (size < chunk->size)
1198
- set_sentinel(pointer, size);
1232
+ Assert(size < chksize);
1233
+ set_sentinel(pointer, size);
1199
1234
  #else /* !MEMORY_CONTEXT_CHECKING */
1200
1235
 
1201
1236
  /*
1202
- * We don't know how much of the old chunk size was the actual
1203
- * allocation; it could have been as small as one byte. We have to be
1204
- * conservative and just mark the entire old portion DEFINED.
1237
+ * We may need to adjust marking of bytes from the old allocation as
1238
+ * some of them may be marked NOACCESS. We don't know how much of the
1239
+ * old chunk size was the requested size; it could have been as small
1240
+ * as one byte. We have to be conservative and just mark the entire
1241
+ * old portion DEFINED. Make sure not to mark memory beyond the new
1242
+ * allocation in case it's smaller than the old one.
1205
1243
  */
1206
- VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1244
+ VALGRIND_MAKE_MEM_DEFINED(pointer, Min(size, oldchksize));
1207
1245
  #endif
1208
1246
 
1209
1247
  /* Ensure any padding bytes are marked NOACCESS. */
1210
1248
  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - size);
1211
1249
 
1212
- /* Disallow external access to private part of chunk header. */
1213
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1250
+ /* Disallow access to the chunk header . */
1251
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1214
1252
 
1215
1253
  return pointer;
1216
1254
  }
1217
1255
 
1256
+ block = MemoryChunkGetBlock(chunk);
1257
+
1258
+ /*
1259
+ * In this path, for speed reasons we just Assert that the referenced
1260
+ * block is good. We can also Assert that the value field is sane. Future
1261
+ * field experience may show that these Asserts had better become regular
1262
+ * runtime test-and-elog checks.
1263
+ */
1264
+ Assert(AllocBlockIsValid(block));
1265
+ set = block->aset;
1266
+
1267
+ fidx = MemoryChunkGetValue(chunk);
1268
+ Assert(FreeListIdxIsValid(fidx));
1269
+ oldchksize = GetChunkSizeFromFreeListIdx(fidx);
1270
+
1271
+ #ifdef MEMORY_CONTEXT_CHECKING
1272
+ /* Test for someone scribbling on unused space in chunk */
1273
+ if (chunk->requested_size < oldchksize)
1274
+ if (!sentinel_ok(pointer, chunk->requested_size))
1275
+ elog(WARNING, "detected write past chunk end in %s %p",
1276
+ set->header.name, chunk);
1277
+ #endif
1278
+
1218
1279
  /*
1219
1280
  * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
1220
1281
  * allocated area already is >= the new size. (In particular, we will
1221
1282
  * fall out here if the requested size is a decrease.)
1222
1283
  */
1223
- else if (oldsize >= size)
1284
+ if (oldchksize >= size)
1224
1285
  {
1225
1286
  #ifdef MEMORY_CONTEXT_CHECKING
1226
1287
  Size oldrequest = chunk->requested_size;
@@ -1243,10 +1304,10 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1243
1304
  size - oldrequest);
1244
1305
  else
1245
1306
  VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
1246
- oldsize - size);
1307
+ oldchksize - size);
1247
1308
 
1248
1309
  /* set mark to catch clobber of "unused" space */
1249
- if (size < oldsize)
1310
+ if (size < oldchksize)
1250
1311
  set_sentinel(pointer, size);
1251
1312
  #else /* !MEMORY_CONTEXT_CHECKING */
1252
1313
 
@@ -1255,12 +1316,12 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1255
1316
  * the old request or shrinking it, so we conservatively mark the
1256
1317
  * entire new allocation DEFINED.
1257
1318
  */
1258
- VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
1319
+ VALGRIND_MAKE_MEM_NOACCESS(pointer, oldchksize);
1259
1320
  VALGRIND_MAKE_MEM_DEFINED(pointer, size);
1260
1321
  #endif
1261
1322
 
1262
- /* Disallow external access to private part of chunk header. */
1263
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1323
+ /* Disallow access to the chunk header. */
1324
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1264
1325
 
1265
1326
  return pointer;
1266
1327
  }
@@ -1278,6 +1339,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1278
1339
  * memory indefinitely. See pgsql-hackers archives for 2007-08-11.)
1279
1340
  */
1280
1341
  AllocPointer newPointer;
1342
+ Size oldsize;
1281
1343
 
1282
1344
  /* allocate new chunk */
1283
1345
  newPointer = AllocSetAlloc((MemoryContext) set, size);
@@ -1285,8 +1347,8 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1285
1347
  /* leave immediately if request was not completed */
1286
1348
  if (newPointer == NULL)
1287
1349
  {
1288
- /* Disallow external access to private part of chunk header. */
1289
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1350
+ /* Disallow access to the chunk header. */
1351
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1290
1352
  return NULL;
1291
1353
  }
1292
1354
 
@@ -1302,6 +1364,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1302
1364
  #ifdef MEMORY_CONTEXT_CHECKING
1303
1365
  oldsize = chunk->requested_size;
1304
1366
  #else
1367
+ oldsize = oldchksize;
1305
1368
  VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
1306
1369
  #endif
1307
1370
 
@@ -1309,36 +1372,84 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
1309
1372
  memcpy(newPointer, pointer, oldsize);
1310
1373
 
1311
1374
  /* free old chunk */
1312
- AllocSetFree((MemoryContext) set, pointer);
1375
+ AllocSetFree(pointer);
1313
1376
 
1314
1377
  return newPointer;
1315
1378
  }
1316
1379
  }
1317
1380
 
1381
+ /*
1382
+ * AllocSetGetChunkContext
1383
+ * Return the MemoryContext that 'pointer' belongs to.
1384
+ */
1385
+ MemoryContext
1386
+ AllocSetGetChunkContext(void *pointer)
1387
+ {
1388
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
1389
+ AllocBlock block;
1390
+ AllocSet set;
1391
+
1392
+ /* Allow access to the chunk header. */
1393
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1394
+
1395
+ if (MemoryChunkIsExternal(chunk))
1396
+ block = ExternalChunkGetBlock(chunk);
1397
+ else
1398
+ block = (AllocBlock) MemoryChunkGetBlock(chunk);
1399
+
1400
+ /* Disallow access to the chunk header. */
1401
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1402
+
1403
+ Assert(AllocBlockIsValid(block));
1404
+ set = block->aset;
1405
+
1406
+ return &set->header;
1407
+ }
1408
+
1318
1409
  /*
1319
1410
  * AllocSetGetChunkSpace
1320
1411
  * Given a currently-allocated chunk, determine the total space
1321
1412
  * it occupies (including all memory-allocation overhead).
1322
1413
  */
1323
- static Size
1324
- AllocSetGetChunkSpace(MemoryContext context, void *pointer)
1414
+ Size
1415
+ AllocSetGetChunkSpace(void *pointer)
1325
1416
  {
1326
- AllocChunk chunk = AllocPointerGetChunk(pointer);
1327
- Size result;
1417
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
1418
+ int fidx;
1419
+
1420
+ /* Allow access to the chunk header. */
1421
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1422
+
1423
+ if (MemoryChunkIsExternal(chunk))
1424
+ {
1425
+ AllocBlock block = ExternalChunkGetBlock(chunk);
1328
1426
 
1329
- VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
1330
- result = chunk->size + ALLOC_CHUNKHDRSZ;
1331
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1332
- return result;
1427
+ /* Disallow access to the chunk header. */
1428
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1429
+
1430
+ Assert(AllocBlockIsValid(block));
1431
+
1432
+ return block->endptr - (char *) chunk;
1433
+ }
1434
+
1435
+ fidx = MemoryChunkGetValue(chunk);
1436
+ Assert(FreeListIdxIsValid(fidx));
1437
+
1438
+ /* Disallow access to the chunk header. */
1439
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1440
+
1441
+ return GetChunkSizeFromFreeListIdx(fidx) + ALLOC_CHUNKHDRSZ;
1333
1442
  }
1334
1443
 
1335
1444
  /*
1336
1445
  * AllocSetIsEmpty
1337
1446
  * Is an allocset empty of any allocated space?
1338
1447
  */
1339
- static bool
1448
+ bool
1340
1449
  AllocSetIsEmpty(MemoryContext context)
1341
1450
  {
1451
+ Assert(AllocSetIsValid(context));
1452
+
1342
1453
  /*
1343
1454
  * For now, we say "empty" only if the context is new or just reset. We
1344
1455
  * could examine the freelists to determine if all space has been freed,
@@ -1359,7 +1470,7 @@ AllocSetIsEmpty(MemoryContext context)
1359
1470
  * totals: if not NULL, add stats about this context into *totals.
1360
1471
  * print_to_stderr: print stats to stderr if true, elog otherwise.
1361
1472
  */
1362
- static void
1473
+ void
1363
1474
  AllocSetStats(MemoryContext context,
1364
1475
  MemoryStatsPrintFunc printfunc, void *passthru,
1365
1476
  MemoryContextCounters *totals, bool print_to_stderr)
@@ -1372,6 +1483,8 @@ AllocSetStats(MemoryContext context,
1372
1483
  AllocBlock block;
1373
1484
  int fidx;
1374
1485
 
1486
+ Assert(AllocSetIsValid(set));
1487
+
1375
1488
  /* Include context header in totalspace */
1376
1489
  totalspace = MAXALIGN(sizeof(AllocSetContext));
1377
1490
 
@@ -1383,13 +1496,24 @@ AllocSetStats(MemoryContext context,
1383
1496
  }
1384
1497
  for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
1385
1498
  {
1386
- AllocChunk chunk;
1499
+ Size chksz = GetChunkSizeFromFreeListIdx(fidx);
1500
+ MemoryChunk *chunk = set->freelist[fidx];
1387
1501
 
1388
- for (chunk = set->freelist[fidx]; chunk != NULL;
1389
- chunk = (AllocChunk) chunk->aset)
1502
+ while (chunk != NULL)
1390
1503
  {
1504
+ AllocFreeListLink *link = GetFreeListLink(chunk);
1505
+
1506
+ /* Allow access to the chunk header. */
1507
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1508
+ Assert(MemoryChunkGetValue(chunk) == fidx);
1509
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1510
+
1391
1511
  freechunks++;
1392
- freespace += chunk->size + ALLOC_CHUNKHDRSZ;
1512
+ freespace += chksz + ALLOC_CHUNKHDRSZ;
1513
+
1514
+ VALGRIND_MAKE_MEM_DEFINED(link, sizeof(AllocFreeListLink));
1515
+ chunk = link->next;
1516
+ VALGRIND_MAKE_MEM_NOACCESS(link, sizeof(AllocFreeListLink));
1393
1517
  }
1394
1518
  }
1395
1519
 
@@ -1424,7 +1548,7 @@ AllocSetStats(MemoryContext context,
1424
1548
  * find yourself in an infinite loop when trouble occurs, because this
1425
1549
  * routine will be entered again when elog cleanup tries to release memory!
1426
1550
  */
1427
- static void
1551
+ void
1428
1552
  AllocSetCheck(MemoryContext context)
1429
1553
  {
1430
1554
  AllocSet set = (AllocSet) context;
@@ -1441,6 +1565,7 @@ AllocSetCheck(MemoryContext context)
1441
1565
  long blk_used = block->freeptr - bpoz;
1442
1566
  long blk_data = 0;
1443
1567
  long nchunks = 0;
1568
+ bool has_external_chunk = false;
1444
1569
 
1445
1570
  if (set->keeper == block)
1446
1571
  total_allocated += block->endptr - ((char *) set);
@@ -1472,56 +1597,64 @@ AllocSetCheck(MemoryContext context)
1472
1597
  */
1473
1598
  while (bpoz < block->freeptr)
1474
1599
  {
1475
- AllocChunk chunk = (AllocChunk) bpoz;
1600
+ MemoryChunk *chunk = (MemoryChunk *) bpoz;
1476
1601
  Size chsize,
1477
1602
  dsize;
1478
1603
 
1479
- /* Allow access to private part of chunk header. */
1480
- VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
1604
+ /* Allow access to the chunk header. */
1605
+ VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
1606
+
1607
+ if (MemoryChunkIsExternal(chunk))
1608
+ {
1609
+ chsize = block->endptr - (char *) MemoryChunkGetPointer(chunk); /* aligned chunk size */
1610
+ has_external_chunk = true;
1611
+
1612
+ /* make sure this chunk consumes the entire block */
1613
+ if (chsize + ALLOC_CHUNKHDRSZ != blk_used)
1614
+ elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
1615
+ name, chunk, block);
1616
+ }
1617
+ else
1618
+ {
1619
+ int fidx = MemoryChunkGetValue(chunk);
1620
+
1621
+ if (!FreeListIdxIsValid(fidx))
1622
+ elog(WARNING, "problem in alloc set %s: bad chunk size for chunk %p in block %p",
1623
+ name, chunk, block);
1624
+
1625
+ chsize = GetChunkSizeFromFreeListIdx(fidx); /* aligned chunk size */
1481
1626
 
1482
- chsize = chunk->size; /* aligned chunk size */
1627
+ /*
1628
+ * Check the stored block offset correctly references this
1629
+ * block.
1630
+ */
1631
+ if (block != MemoryChunkGetBlock(chunk))
1632
+ elog(WARNING, "problem in alloc set %s: bad block offset for chunk %p in block %p",
1633
+ name, chunk, block);
1634
+ }
1483
1635
  dsize = chunk->requested_size; /* real data */
1484
1636
 
1485
- /*
1486
- * Check chunk size
1487
- */
1488
- if (dsize > chsize)
1637
+ /* an allocated chunk's requested size must be <= the chsize */
1638
+ if (dsize != InvalidAllocSize && dsize > chsize)
1489
1639
  elog(WARNING, "problem in alloc set %s: req size > alloc size for chunk %p in block %p",
1490
1640
  name, chunk, block);
1641
+
1642
+ /* chsize must not be smaller than the first freelist's size */
1491
1643
  if (chsize < (1 << ALLOC_MINBITS))
1492
1644
  elog(WARNING, "problem in alloc set %s: bad size %zu for chunk %p in block %p",
1493
1645
  name, chsize, chunk, block);
1494
1646
 
1495
- /* single-chunk block? */
1496
- if (chsize > set->allocChunkLimit &&
1497
- chsize + ALLOC_CHUNKHDRSZ != blk_used)
1498
- elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p",
1499
- name, chunk, block);
1500
-
1501
- /*
1502
- * If chunk is allocated, check for correct aset pointer. (If it's
1503
- * free, the aset is the freelist pointer, which we can't check as
1504
- * easily...) Note this is an incomplete test, since palloc(0)
1505
- * produces an allocated chunk with requested_size == 0.
1506
- */
1507
- if (dsize > 0 && chunk->aset != (void *) set)
1508
- elog(WARNING, "problem in alloc set %s: bogus aset link in block %p, chunk %p",
1509
- name, block, chunk);
1510
-
1511
1647
  /*
1512
1648
  * Check for overwrite of padding space in an allocated chunk.
1513
1649
  */
1514
- if (chunk->aset == (void *) set && dsize < chsize &&
1650
+ if (dsize != InvalidAllocSize && dsize < chsize &&
1515
1651
  !sentinel_ok(chunk, ALLOC_CHUNKHDRSZ + dsize))
1516
1652
  elog(WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p",
1517
1653
  name, block, chunk);
1518
1654
 
1519
- /*
1520
- * If chunk is allocated, disallow external access to private part
1521
- * of chunk header.
1522
- */
1523
- if (chunk->aset == (void *) set)
1524
- VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
1655
+ /* if chunk is allocated, disallow access to the chunk header */
1656
+ if (dsize != InvalidAllocSize)
1657
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
1525
1658
 
1526
1659
  blk_data += chsize;
1527
1660
  nchunks++;
@@ -1532,6 +1665,10 @@ AllocSetCheck(MemoryContext context)
1532
1665
  if ((blk_data + (nchunks * ALLOC_CHUNKHDRSZ)) != blk_used)
1533
1666
  elog(WARNING, "problem in alloc set %s: found inconsistent memory block %p",
1534
1667
  name, block);
1668
+
1669
+ if (has_external_chunk && nchunks > 1)
1670
+ elog(WARNING, "problem in alloc set %s: external chunk on non-dedicated block %p",
1671
+ name, block);
1535
1672
  }
1536
1673
 
1537
1674
  Assert(total_allocated == context->mem_allocated);