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
@@ -0,0 +1,1021 @@
1
+ /*--------------------------------------------------------------------
2
+ * Symbols referenced in this file:
3
+ * - SlabAlloc
4
+ * - SlabBlocklistIndex
5
+ * - SlabGetNextFreeChunk
6
+ * - SlabFindNextBlockListIndex
7
+ * - SlabFree
8
+ * - SlabRealloc
9
+ * - SlabReset
10
+ * - SlabDelete
11
+ * - SlabGetChunkContext
12
+ * - SlabGetChunkSpace
13
+ * - SlabIsEmpty
14
+ * - SlabStats
15
+ * - SlabCheck
16
+ *--------------------------------------------------------------------
17
+ */
18
+
19
+ /*-------------------------------------------------------------------------
20
+ *
21
+ * slab.c
22
+ * SLAB allocator definitions.
23
+ *
24
+ * SLAB is a MemoryContext implementation designed for cases where large
25
+ * numbers of equally-sized objects can be allocated and freed efficiently
26
+ * with minimal memory wastage and fragmentation.
27
+ *
28
+ *
29
+ * Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group
30
+ *
31
+ * IDENTIFICATION
32
+ * src/backend/utils/mmgr/slab.c
33
+ *
34
+ *
35
+ * NOTE:
36
+ * The constant allocation size allows significant simplification and various
37
+ * optimizations over more general purpose allocators. The blocks are carved
38
+ * into chunks of exactly the right size, wasting only the space required to
39
+ * MAXALIGN the allocated chunks.
40
+ *
41
+ * Slab can also help reduce memory fragmentation in cases where longer-lived
42
+ * chunks remain stored on blocks while most of the other chunks have already
43
+ * been pfree'd. We give priority to putting new allocations into the
44
+ * "fullest" block. This help avoid having too many sparsely used blocks
45
+ * around and allows blocks to more easily become completely unused which
46
+ * allows them to be eventually free'd.
47
+ *
48
+ * We identify the "fullest" block to put new allocations on by using a block
49
+ * from the lowest populated element of the context's "blocklist" array.
50
+ * This is an array of dlists containing blocks which we partition by the
51
+ * number of free chunks which block has. Blocks with fewer free chunks are
52
+ * stored in a lower indexed dlist array slot. Full blocks go on the 0th
53
+ * element of the blocklist array. So that we don't have to have too many
54
+ * elements in the array, each dlist in the array is responsible for a range
55
+ * of free chunks. When a chunk is palloc'd or pfree'd we may need to move
56
+ * the block onto another dlist if the number of free chunks crosses the
57
+ * range boundary that the current list is responsible for. Having just a
58
+ * few blocklist elements reduces the number of times we must move the block
59
+ * onto another dlist element.
60
+ *
61
+ * We keep track of free chunks within each block by using a block-level free
62
+ * list. We consult this list when we allocate a new chunk in the block.
63
+ * The free list is a linked list, the head of which is pointed to with
64
+ * SlabBlock's freehead field. Each subsequent list item is stored in the
65
+ * free chunk's memory. We ensure chunks are large enough to store this
66
+ * address.
67
+ *
68
+ * When we allocate a new block, technically all chunks are free, however, to
69
+ * avoid having to write out the entire block to set the linked list for the
70
+ * free chunks for every chunk in the block, we instead store a pointer to
71
+ * the next "unused" chunk on the block and keep track of how many of these
72
+ * unused chunks there are. When a new block is malloc'd, all chunks are
73
+ * unused. The unused pointer starts with the first chunk on the block and
74
+ * as chunks are allocated, the unused pointer is incremented. As chunks are
75
+ * pfree'd, the unused pointer never goes backwards. The unused pointer can
76
+ * be thought of as a high watermark for the maximum number of chunks in the
77
+ * block which have been in use concurrently. When a chunk is pfree'd the
78
+ * chunk is put onto the head of the free list and the unused pointer is not
79
+ * changed. We only consume more unused chunks if we run out of free chunks
80
+ * on the free list. This method effectively gives priority to using
81
+ * previously used chunks over previously unused chunks, which should perform
82
+ * better due to CPU caching effects.
83
+ *
84
+ *-------------------------------------------------------------------------
85
+ */
86
+
87
+ #include "postgres.h"
88
+
89
+ #include "lib/ilist.h"
90
+ #include "utils/memdebug.h"
91
+ #include "utils/memutils.h"
92
+ #include "utils/memutils_memorychunk.h"
93
+ #include "utils/memutils_internal.h"
94
+
95
+ #define Slab_BLOCKHDRSZ MAXALIGN(sizeof(SlabBlock))
96
+
97
+ #ifdef MEMORY_CONTEXT_CHECKING
98
+ /*
99
+ * Size of the memory required to store the SlabContext.
100
+ * MEMORY_CONTEXT_CHECKING builds need some extra memory for the isChunkFree
101
+ * array.
102
+ */
103
+ #define Slab_CONTEXT_HDRSZ(chunksPerBlock) \
104
+ (sizeof(SlabContext) + ((chunksPerBlock) * sizeof(bool)))
105
+ #else
106
+ #define Slab_CONTEXT_HDRSZ(chunksPerBlock) sizeof(SlabContext)
107
+ #endif
108
+
109
+ /*
110
+ * The number of partitions to divide the blocklist into based their number of
111
+ * free chunks. There must be at least 2.
112
+ */
113
+ #define SLAB_BLOCKLIST_COUNT 3
114
+
115
+ /* The maximum number of completely empty blocks to keep around for reuse. */
116
+ #define SLAB_MAXIMUM_EMPTY_BLOCKS 10
117
+
118
+ /*
119
+ * SlabContext is a specialized implementation of MemoryContext.
120
+ */
121
+ typedef struct SlabContext
122
+ {
123
+ MemoryContextData header; /* Standard memory-context fields */
124
+ /* Allocation parameters for this context: */
125
+ Size chunkSize; /* the requested (non-aligned) chunk size */
126
+ Size fullChunkSize; /* chunk size with chunk header and alignment */
127
+ Size blockSize; /* the size to make each block of chunks */
128
+ int32 chunksPerBlock; /* number of chunks that fit in 1 block */
129
+ int32 curBlocklistIndex; /* index into the blocklist[] element
130
+ * containing the fullest, blocks */
131
+ #ifdef MEMORY_CONTEXT_CHECKING
132
+ bool *isChunkFree; /* array to mark free chunks in a block during
133
+ * SlabCheck */
134
+ #endif
135
+
136
+ int32 blocklist_shift; /* number of bits to shift the nfree count
137
+ * by to get the index into blocklist[] */
138
+ dclist_head emptyblocks; /* empty blocks to use up first instead of
139
+ * mallocing new blocks */
140
+
141
+ /*
142
+ * Blocks with free space, grouped by the number of free chunks they
143
+ * contain. Completely full blocks are stored in the 0th element.
144
+ * Completely empty blocks are stored in emptyblocks or free'd if we have
145
+ * enough empty blocks already.
146
+ */
147
+ dlist_head blocklist[SLAB_BLOCKLIST_COUNT];
148
+ } SlabContext;
149
+
150
+ /*
151
+ * SlabBlock
152
+ * Structure of a single slab block.
153
+ *
154
+ * slab: pointer back to the owning MemoryContext
155
+ * nfree: number of chunks on the block which are unallocated
156
+ * nunused: number of chunks on the block unallocated and not on the block's
157
+ * freelist.
158
+ * freehead: linked-list header storing a pointer to the first free chunk on
159
+ * the block. Subsequent pointers are stored in the chunk's memory. NULL
160
+ * indicates the end of the list.
161
+ * unused: pointer to the next chunk which has yet to be used.
162
+ * node: doubly-linked list node for the context's blocklist
163
+ */
164
+ typedef struct SlabBlock
165
+ {
166
+ SlabContext *slab; /* owning context */
167
+ int32 nfree; /* number of chunks on free + unused chunks */
168
+ int32 nunused; /* number of unused chunks */
169
+ MemoryChunk *freehead; /* pointer to the first free chunk */
170
+ MemoryChunk *unused; /* pointer to the next unused chunk */
171
+ dlist_node node; /* doubly-linked list for blocklist[] */
172
+ } SlabBlock;
173
+
174
+
175
+ #define Slab_CHUNKHDRSZ sizeof(MemoryChunk)
176
+ #define SlabChunkGetPointer(chk) \
177
+ ((void *) (((char *) (chk)) + sizeof(MemoryChunk)))
178
+
179
+ /*
180
+ * SlabBlockGetChunk
181
+ * Obtain a pointer to the nth (0-based) chunk in the block
182
+ */
183
+ #define SlabBlockGetChunk(slab, block, n) \
184
+ ((MemoryChunk *) ((char *) (block) + Slab_BLOCKHDRSZ \
185
+ + ((n) * (slab)->fullChunkSize)))
186
+
187
+ #if defined(MEMORY_CONTEXT_CHECKING) || defined(USE_ASSERT_CHECKING)
188
+
189
+ /*
190
+ * SlabChunkIndex
191
+ * Get the 0-based index of how many chunks into the block the given
192
+ * chunk is.
193
+ */
194
+ #define SlabChunkIndex(slab, block, chunk) \
195
+ (((char *) (chunk) - (char *) SlabBlockGetChunk(slab, block, 0)) / \
196
+ (slab)->fullChunkSize)
197
+
198
+ /*
199
+ * SlabChunkMod
200
+ * A MemoryChunk should always be at an address which is a multiple of
201
+ * fullChunkSize starting from the 0th chunk position. This will return
202
+ * non-zero if it's not.
203
+ */
204
+ #define SlabChunkMod(slab, block, chunk) \
205
+ (((char *) (chunk) - (char *) SlabBlockGetChunk(slab, block, 0)) % \
206
+ (slab)->fullChunkSize)
207
+
208
+ #endif
209
+
210
+ /*
211
+ * SlabIsValid
212
+ * True iff set is a valid slab allocation set.
213
+ */
214
+ #define SlabIsValid(set) (PointerIsValid(set) && IsA(set, SlabContext))
215
+
216
+ /*
217
+ * SlabBlockIsValid
218
+ * True iff block is a valid block of slab allocation set.
219
+ */
220
+ #define SlabBlockIsValid(block) \
221
+ (PointerIsValid(block) && SlabIsValid((block)->slab))
222
+
223
+ /*
224
+ * SlabBlocklistIndex
225
+ * Determine the blocklist index that a block should be in for the given
226
+ * number of free chunks.
227
+ */
228
+ static inline int32
229
+ SlabBlocklistIndex(SlabContext *slab, int nfree)
230
+ {
231
+ int32 index;
232
+ int32 blocklist_shift = slab->blocklist_shift;
233
+
234
+ Assert(nfree >= 0 && nfree <= slab->chunksPerBlock);
235
+
236
+ /*
237
+ * Determine the blocklist index based on the number of free chunks. We
238
+ * must ensure that 0 free chunks is dedicated to index 0. Everything
239
+ * else must be >= 1 and < SLAB_BLOCKLIST_COUNT.
240
+ *
241
+ * To make this as efficient as possible, we exploit some two's complement
242
+ * arithmetic where we reverse the sign before bit shifting. This results
243
+ * in an nfree of 0 using index 0 and anything non-zero staying non-zero.
244
+ * This is exploiting 0 and -0 being the same in two's complement. When
245
+ * we're done, we just need to flip the sign back over again for a
246
+ * positive index.
247
+ */
248
+ index = -((-nfree) >> blocklist_shift);
249
+
250
+ if (nfree == 0)
251
+ Assert(index == 0);
252
+ else
253
+ Assert(index >= 1 && index < SLAB_BLOCKLIST_COUNT);
254
+
255
+ return index;
256
+ }
257
+
258
+ /*
259
+ * SlabFindNextBlockListIndex
260
+ * Search blocklist for blocks which have free chunks and return the
261
+ * index of the blocklist found containing at least 1 block with free
262
+ * chunks. If no block can be found we return 0.
263
+ *
264
+ * Note: We give priority to fuller blocks so that these are filled before
265
+ * emptier blocks. This is done to increase the chances that mostly-empty
266
+ * blocks will eventually become completely empty so they can be free'd.
267
+ */
268
+ static int32
269
+ SlabFindNextBlockListIndex(SlabContext *slab)
270
+ {
271
+ /* start at 1 as blocklist[0] is for full blocks. */
272
+ for (int i = 1; i < SLAB_BLOCKLIST_COUNT; i++)
273
+ {
274
+ /* return the first found non-empty index */
275
+ if (!dlist_is_empty(&slab->blocklist[i]))
276
+ return i;
277
+ }
278
+
279
+ /* no blocks with free space */
280
+ return 0;
281
+ }
282
+
283
+ /*
284
+ * SlabGetNextFreeChunk
285
+ * Return the next free chunk in block and update the block to account
286
+ * for the returned chunk now being used.
287
+ */
288
+ static inline MemoryChunk *
289
+ SlabGetNextFreeChunk(SlabContext *slab, SlabBlock *block)
290
+ {
291
+ MemoryChunk *chunk;
292
+
293
+ Assert(block->nfree > 0);
294
+
295
+ if (block->freehead != NULL)
296
+ {
297
+ chunk = block->freehead;
298
+
299
+ /*
300
+ * Pop the chunk from the linked list of free chunks. The pointer to
301
+ * the next free chunk is stored in the chunk itself.
302
+ */
303
+ VALGRIND_MAKE_MEM_DEFINED(SlabChunkGetPointer(chunk), sizeof(MemoryChunk *));
304
+ block->freehead = *(MemoryChunk **) SlabChunkGetPointer(chunk);
305
+
306
+ /* check nothing stomped on the free chunk's memory */
307
+ Assert(block->freehead == NULL ||
308
+ (block->freehead >= SlabBlockGetChunk(slab, block, 0) &&
309
+ block->freehead <= SlabBlockGetChunk(slab, block, slab->chunksPerBlock - 1) &&
310
+ SlabChunkMod(slab, block, block->freehead) == 0));
311
+ }
312
+ else
313
+ {
314
+ Assert(block->nunused > 0);
315
+
316
+ chunk = block->unused;
317
+ block->unused = (MemoryChunk *) (((char *) block->unused) + slab->fullChunkSize);
318
+ block->nunused--;
319
+ }
320
+
321
+ block->nfree--;
322
+
323
+ return chunk;
324
+ }
325
+
326
+ /*
327
+ * SlabContextCreate
328
+ * Create a new Slab context.
329
+ *
330
+ * parent: parent context, or NULL if top-level context
331
+ * name: name of context (must be statically allocated)
332
+ * blockSize: allocation block size
333
+ * chunkSize: allocation chunk size
334
+ *
335
+ * The MAXALIGN(chunkSize) may not exceed MEMORYCHUNK_MAX_VALUE
336
+ */
337
+ #ifdef MEMORY_CONTEXT_CHECKING
338
+ #else
339
+ #endif
340
+ #ifdef MEMORY_CONTEXT_CHECKING
341
+ #endif
342
+
343
+ /*
344
+ * SlabReset
345
+ * Frees all memory which is allocated in the given set.
346
+ *
347
+ * The code simply frees all the blocks in the context - we don't keep any
348
+ * keeper blocks or anything like that.
349
+ */
350
+ void
351
+ SlabReset(MemoryContext context)
352
+ {
353
+ SlabContext *slab = (SlabContext *) context;
354
+ dlist_mutable_iter miter;
355
+ int i;
356
+
357
+ Assert(SlabIsValid(slab));
358
+
359
+ #ifdef MEMORY_CONTEXT_CHECKING
360
+ /* Check for corruption and leaks before freeing */
361
+ SlabCheck(context);
362
+ #endif
363
+
364
+ /* release any retained empty blocks */
365
+ dclist_foreach_modify(miter, &slab->emptyblocks)
366
+ {
367
+ SlabBlock *block = dlist_container(SlabBlock, node, miter.cur);
368
+
369
+ dclist_delete_from(&slab->emptyblocks, miter.cur);
370
+
371
+ #ifdef CLOBBER_FREED_MEMORY
372
+ wipe_mem(block, slab->blockSize);
373
+ #endif
374
+ free(block);
375
+ context->mem_allocated -= slab->blockSize;
376
+ }
377
+
378
+ /* walk over blocklist and free the blocks */
379
+ for (i = 0; i < SLAB_BLOCKLIST_COUNT; i++)
380
+ {
381
+ dlist_foreach_modify(miter, &slab->blocklist[i])
382
+ {
383
+ SlabBlock *block = dlist_container(SlabBlock, node, miter.cur);
384
+
385
+ dlist_delete(miter.cur);
386
+
387
+ #ifdef CLOBBER_FREED_MEMORY
388
+ wipe_mem(block, slab->blockSize);
389
+ #endif
390
+ free(block);
391
+ context->mem_allocated -= slab->blockSize;
392
+ }
393
+ }
394
+
395
+ slab->curBlocklistIndex = 0;
396
+
397
+ Assert(context->mem_allocated == 0);
398
+ }
399
+
400
+ /*
401
+ * SlabDelete
402
+ * Free all memory which is allocated in the given context.
403
+ */
404
+ void
405
+ SlabDelete(MemoryContext context)
406
+ {
407
+ /* Reset to release all the SlabBlocks */
408
+ SlabReset(context);
409
+ /* And free the context header */
410
+ free(context);
411
+ }
412
+
413
+ /*
414
+ * SlabAlloc
415
+ * Returns a pointer to allocated memory of given size or NULL if
416
+ * request could not be completed; memory is added to the slab.
417
+ */
418
+ void *
419
+ SlabAlloc(MemoryContext context, Size size)
420
+ {
421
+ SlabContext *slab = (SlabContext *) context;
422
+ SlabBlock *block;
423
+ MemoryChunk *chunk;
424
+
425
+ Assert(SlabIsValid(slab));
426
+
427
+ /* sanity check that this is pointing to a valid blocklist */
428
+ Assert(slab->curBlocklistIndex >= 0);
429
+ Assert(slab->curBlocklistIndex <= SlabBlocklistIndex(slab, slab->chunksPerBlock));
430
+
431
+ /* make sure we only allow correct request size */
432
+ if (unlikely(size != slab->chunkSize))
433
+ elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
434
+ size, slab->chunkSize);
435
+
436
+ /*
437
+ * Handle the case when there are no partially filled blocks available.
438
+ * SlabFree() will have updated the curBlocklistIndex setting it to zero
439
+ * to indicate that it has freed the final block. Also later in
440
+ * SlabAlloc() we will set the curBlocklistIndex to zero if we end up
441
+ * filling the final block.
442
+ */
443
+ if (unlikely(slab->curBlocklistIndex == 0))
444
+ {
445
+ dlist_head *blocklist;
446
+ int blocklist_idx;
447
+
448
+ /* to save allocating a new one, first check the empty blocks list */
449
+ if (dclist_count(&slab->emptyblocks) > 0)
450
+ {
451
+ dlist_node *node = dclist_pop_head_node(&slab->emptyblocks);
452
+
453
+ block = dlist_container(SlabBlock, node, node);
454
+
455
+ /*
456
+ * SlabFree() should have left this block in a valid state with
457
+ * all chunks free. Ensure that's the case.
458
+ */
459
+ Assert(block->nfree == slab->chunksPerBlock);
460
+
461
+ /* fetch the next chunk from this block */
462
+ chunk = SlabGetNextFreeChunk(slab, block);
463
+ }
464
+ else
465
+ {
466
+ block = (SlabBlock *) malloc(slab->blockSize);
467
+
468
+ if (unlikely(block == NULL))
469
+ return NULL;
470
+
471
+ block->slab = slab;
472
+ context->mem_allocated += slab->blockSize;
473
+
474
+ /* use the first chunk in the new block */
475
+ chunk = SlabBlockGetChunk(slab, block, 0);
476
+
477
+ block->nfree = slab->chunksPerBlock - 1;
478
+ block->unused = SlabBlockGetChunk(slab, block, 1);
479
+ block->freehead = NULL;
480
+ block->nunused = slab->chunksPerBlock - 1;
481
+ }
482
+
483
+ /* find the blocklist element for storing blocks with 1 used chunk */
484
+ blocklist_idx = SlabBlocklistIndex(slab, block->nfree);
485
+ blocklist = &slab->blocklist[blocklist_idx];
486
+
487
+ /* this better be empty. We just added a block thinking it was */
488
+ Assert(dlist_is_empty(blocklist));
489
+
490
+ dlist_push_head(blocklist, &block->node);
491
+
492
+ slab->curBlocklistIndex = blocklist_idx;
493
+ }
494
+ else
495
+ {
496
+ dlist_head *blocklist = &slab->blocklist[slab->curBlocklistIndex];
497
+ int new_blocklist_idx;
498
+
499
+ Assert(!dlist_is_empty(blocklist));
500
+
501
+ /* grab the block from the blocklist */
502
+ block = dlist_head_element(SlabBlock, node, blocklist);
503
+
504
+ /* make sure we actually got a valid block, with matching nfree */
505
+ Assert(block != NULL);
506
+ Assert(slab->curBlocklistIndex == SlabBlocklistIndex(slab, block->nfree));
507
+ Assert(block->nfree > 0);
508
+
509
+ /* fetch the next chunk from this block */
510
+ chunk = SlabGetNextFreeChunk(slab, block);
511
+
512
+ /* get the new blocklist index based on the new free chunk count */
513
+ new_blocklist_idx = SlabBlocklistIndex(slab, block->nfree);
514
+
515
+ /*
516
+ * Handle the case where the blocklist index changes. This also deals
517
+ * with blocks becoming full as only full blocks go at index 0.
518
+ */
519
+ if (unlikely(slab->curBlocklistIndex != new_blocklist_idx))
520
+ {
521
+ dlist_delete_from(blocklist, &block->node);
522
+ dlist_push_head(&slab->blocklist[new_blocklist_idx], &block->node);
523
+
524
+ if (dlist_is_empty(blocklist))
525
+ slab->curBlocklistIndex = SlabFindNextBlockListIndex(slab);
526
+ }
527
+ }
528
+
529
+ /*
530
+ * Check that the chunk pointer is actually somewhere on the block and is
531
+ * aligned as expected.
532
+ */
533
+ Assert(chunk >= SlabBlockGetChunk(slab, block, 0));
534
+ Assert(chunk <= SlabBlockGetChunk(slab, block, slab->chunksPerBlock - 1));
535
+ Assert(SlabChunkMod(slab, block, chunk) == 0);
536
+
537
+ /* Prepare to initialize the chunk header. */
538
+ VALGRIND_MAKE_MEM_UNDEFINED(chunk, Slab_CHUNKHDRSZ);
539
+
540
+ MemoryChunkSetHdrMask(chunk, block, MAXALIGN(slab->chunkSize),
541
+ MCTX_SLAB_ID);
542
+ #ifdef MEMORY_CONTEXT_CHECKING
543
+ /* slab mark to catch clobber of "unused" space */
544
+ Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ));
545
+ set_sentinel(MemoryChunkGetPointer(chunk), size);
546
+ VALGRIND_MAKE_MEM_NOACCESS(((char *) chunk) +
547
+ Slab_CHUNKHDRSZ + slab->chunkSize,
548
+ slab->fullChunkSize -
549
+ (slab->chunkSize + Slab_CHUNKHDRSZ));
550
+ #endif
551
+
552
+ #ifdef RANDOMIZE_ALLOCATED_MEMORY
553
+ /* fill the allocated space with junk */
554
+ randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
555
+ #endif
556
+
557
+ /* Disallow access to the chunk header. */
558
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
559
+
560
+ return MemoryChunkGetPointer(chunk);
561
+ }
562
+
563
+ /*
564
+ * SlabFree
565
+ * Frees allocated memory; memory is removed from the slab.
566
+ */
567
+ void
568
+ SlabFree(void *pointer)
569
+ {
570
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
571
+ SlabBlock *block;
572
+ SlabContext *slab;
573
+ int curBlocklistIdx;
574
+ int newBlocklistIdx;
575
+
576
+ /* Allow access to the chunk header. */
577
+ VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
578
+
579
+ block = MemoryChunkGetBlock(chunk);
580
+
581
+ /*
582
+ * For speed reasons we just Assert that the referenced block is good.
583
+ * Future field experience may show that this Assert had better become a
584
+ * regular runtime test-and-elog check.
585
+ */
586
+ Assert(SlabBlockIsValid(block));
587
+ slab = block->slab;
588
+
589
+ #ifdef MEMORY_CONTEXT_CHECKING
590
+ /* Test for someone scribbling on unused space in chunk */
591
+ Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ));
592
+ if (!sentinel_ok(pointer, slab->chunkSize))
593
+ elog(WARNING, "detected write past chunk end in %s %p",
594
+ slab->header.name, chunk);
595
+ #endif
596
+
597
+ /* push this chunk onto the head of the block's free list */
598
+ *(MemoryChunk **) pointer = block->freehead;
599
+ block->freehead = chunk;
600
+
601
+ block->nfree++;
602
+
603
+ Assert(block->nfree > 0);
604
+ Assert(block->nfree <= slab->chunksPerBlock);
605
+
606
+ #ifdef CLOBBER_FREED_MEMORY
607
+ /* don't wipe the free list MemoryChunk pointer stored in the chunk */
608
+ wipe_mem((char *) pointer + sizeof(MemoryChunk *),
609
+ slab->chunkSize - sizeof(MemoryChunk *));
610
+ #endif
611
+
612
+ curBlocklistIdx = SlabBlocklistIndex(slab, block->nfree - 1);
613
+ newBlocklistIdx = SlabBlocklistIndex(slab, block->nfree);
614
+
615
+ /*
616
+ * Check if the block needs to be moved to another element on the
617
+ * blocklist based on it now having 1 more free chunk.
618
+ */
619
+ if (unlikely(curBlocklistIdx != newBlocklistIdx))
620
+ {
621
+ /* do the move */
622
+ dlist_delete_from(&slab->blocklist[curBlocklistIdx], &block->node);
623
+ dlist_push_head(&slab->blocklist[newBlocklistIdx], &block->node);
624
+
625
+ /*
626
+ * The blocklist[curBlocklistIdx] may now be empty or we may now be
627
+ * able to use a lower-element blocklist. We'll need to redetermine
628
+ * what the slab->curBlocklistIndex is if the current blocklist was
629
+ * changed or if a lower element one was changed. We must ensure we
630
+ * use the list with the fullest block(s).
631
+ */
632
+ if (slab->curBlocklistIndex >= curBlocklistIdx)
633
+ {
634
+ slab->curBlocklistIndex = SlabFindNextBlockListIndex(slab);
635
+
636
+ /*
637
+ * We know there must be a block with at least 1 unused chunk as
638
+ * we just pfree'd one. Ensure curBlocklistIndex reflects this.
639
+ */
640
+ Assert(slab->curBlocklistIndex > 0);
641
+ }
642
+ }
643
+
644
+ /* Handle when a block becomes completely empty */
645
+ if (unlikely(block->nfree == slab->chunksPerBlock))
646
+ {
647
+ /* remove the block */
648
+ dlist_delete_from(&slab->blocklist[newBlocklistIdx], &block->node);
649
+
650
+ /*
651
+ * To avoid thrashing malloc/free, we keep a list of empty blocks that
652
+ * we can reuse again instead of having to malloc a new one.
653
+ */
654
+ if (dclist_count(&slab->emptyblocks) < SLAB_MAXIMUM_EMPTY_BLOCKS)
655
+ dclist_push_head(&slab->emptyblocks, &block->node);
656
+ else
657
+ {
658
+ /*
659
+ * When we have enough empty blocks stored already, we actually
660
+ * free the block.
661
+ */
662
+ #ifdef CLOBBER_FREED_MEMORY
663
+ wipe_mem(block, slab->blockSize);
664
+ #endif
665
+ free(block);
666
+ slab->header.mem_allocated -= slab->blockSize;
667
+ }
668
+
669
+ /*
670
+ * Check if we need to reset the blocklist index. This is required
671
+ * when the blocklist this block is on has become completely empty.
672
+ */
673
+ if (slab->curBlocklistIndex == newBlocklistIdx &&
674
+ dlist_is_empty(&slab->blocklist[newBlocklistIdx]))
675
+ slab->curBlocklistIndex = SlabFindNextBlockListIndex(slab);
676
+ }
677
+ }
678
+
679
+ /*
680
+ * SlabRealloc
681
+ * Change the allocated size of a chunk.
682
+ *
683
+ * As Slab is designed for allocating equally-sized chunks of memory, it can't
684
+ * do an actual chunk size change. We try to be gentle and allow calls with
685
+ * exactly the same size, as in that case we can simply return the same
686
+ * chunk. When the size differs, we throw an error.
687
+ *
688
+ * We could also allow requests with size < chunkSize. That however seems
689
+ * rather pointless - Slab is meant for chunks of constant size, and moreover
690
+ * realloc is usually used to enlarge the chunk.
691
+ */
692
+ void *
693
+ SlabRealloc(void *pointer, Size size)
694
+ {
695
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
696
+ SlabBlock *block;
697
+ SlabContext *slab;
698
+
699
+ /* Allow access to the chunk header. */
700
+ VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
701
+
702
+ block = MemoryChunkGetBlock(chunk);
703
+
704
+ /* Disallow access to the chunk header. */
705
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
706
+
707
+ /*
708
+ * Try to verify that we have a sane block pointer: the block header
709
+ * should reference a slab context. (We use a test-and-elog, not just
710
+ * Assert, because it seems highly likely that we're here in error in the
711
+ * first place.)
712
+ */
713
+ if (!SlabBlockIsValid(block))
714
+ elog(ERROR, "could not find block containing chunk %p", chunk);
715
+ slab = block->slab;
716
+
717
+ /* can't do actual realloc with slab, but let's try to be gentle */
718
+ if (size == slab->chunkSize)
719
+ return pointer;
720
+
721
+ elog(ERROR, "slab allocator does not support realloc()");
722
+ return NULL; /* keep compiler quiet */
723
+ }
724
+
725
+ /*
726
+ * SlabGetChunkContext
727
+ * Return the MemoryContext that 'pointer' belongs to.
728
+ */
729
+ MemoryContext
730
+ SlabGetChunkContext(void *pointer)
731
+ {
732
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
733
+ SlabBlock *block;
734
+
735
+ /* Allow access to the chunk header. */
736
+ VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
737
+
738
+ block = MemoryChunkGetBlock(chunk);
739
+
740
+ /* Disallow access to the chunk header. */
741
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
742
+
743
+ Assert(SlabBlockIsValid(block));
744
+
745
+ return &block->slab->header;
746
+ }
747
+
748
+ /*
749
+ * SlabGetChunkSpace
750
+ * Given a currently-allocated chunk, determine the total space
751
+ * it occupies (including all memory-allocation overhead).
752
+ */
753
+ Size
754
+ SlabGetChunkSpace(void *pointer)
755
+ {
756
+ MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
757
+ SlabBlock *block;
758
+ SlabContext *slab;
759
+
760
+ /* Allow access to the chunk header. */
761
+ VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
762
+
763
+ block = MemoryChunkGetBlock(chunk);
764
+
765
+ /* Disallow access to the chunk header. */
766
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
767
+
768
+ Assert(SlabBlockIsValid(block));
769
+ slab = block->slab;
770
+
771
+ return slab->fullChunkSize;
772
+ }
773
+
774
+ /*
775
+ * SlabIsEmpty
776
+ * Is the slab empty of any allocated space?
777
+ */
778
+ bool
779
+ SlabIsEmpty(MemoryContext context)
780
+ {
781
+ Assert(SlabIsValid((SlabContext *) context));
782
+
783
+ return (context->mem_allocated == 0);
784
+ }
785
+
786
+ /*
787
+ * SlabStats
788
+ * Compute stats about memory consumption of a Slab context.
789
+ *
790
+ * printfunc: if not NULL, pass a human-readable stats string to this.
791
+ * passthru: pass this pointer through to printfunc.
792
+ * totals: if not NULL, add stats about this context into *totals.
793
+ * print_to_stderr: print stats to stderr if true, elog otherwise.
794
+ */
795
+ void
796
+ SlabStats(MemoryContext context,
797
+ MemoryStatsPrintFunc printfunc, void *passthru,
798
+ MemoryContextCounters *totals,
799
+ bool print_to_stderr)
800
+ {
801
+ SlabContext *slab = (SlabContext *) context;
802
+ Size nblocks = 0;
803
+ Size freechunks = 0;
804
+ Size totalspace;
805
+ Size freespace = 0;
806
+ int i;
807
+
808
+ Assert(SlabIsValid(slab));
809
+
810
+ /* Include context header in totalspace */
811
+ totalspace = Slab_CONTEXT_HDRSZ(slab->chunksPerBlock);
812
+
813
+ /* Add the space consumed by blocks in the emptyblocks list */
814
+ totalspace += dclist_count(&slab->emptyblocks) * slab->blockSize;
815
+
816
+ for (i = 0; i < SLAB_BLOCKLIST_COUNT; i++)
817
+ {
818
+ dlist_iter iter;
819
+
820
+ dlist_foreach(iter, &slab->blocklist[i])
821
+ {
822
+ SlabBlock *block = dlist_container(SlabBlock, node, iter.cur);
823
+
824
+ nblocks++;
825
+ totalspace += slab->blockSize;
826
+ freespace += slab->fullChunkSize * block->nfree;
827
+ freechunks += block->nfree;
828
+ }
829
+ }
830
+
831
+ if (printfunc)
832
+ {
833
+ char stats_string[200];
834
+
835
+ /* XXX should we include free chunks on empty blocks? */
836
+ snprintf(stats_string, sizeof(stats_string),
837
+ "%zu total in %zu blocks; %u empty blocks; %zu free (%zu chunks); %zu used",
838
+ totalspace, nblocks, dclist_count(&slab->emptyblocks),
839
+ freespace, freechunks, totalspace - freespace);
840
+ printfunc(context, passthru, stats_string, print_to_stderr);
841
+ }
842
+
843
+ if (totals)
844
+ {
845
+ totals->nblocks += nblocks;
846
+ totals->freechunks += freechunks;
847
+ totals->totalspace += totalspace;
848
+ totals->freespace += freespace;
849
+ }
850
+ }
851
+
852
+
853
+ #ifdef MEMORY_CONTEXT_CHECKING
854
+
855
+ /*
856
+ * SlabCheck
857
+ * Walk through all blocks looking for inconsistencies.
858
+ *
859
+ * NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll
860
+ * find yourself in an infinite loop when trouble occurs, because this
861
+ * routine will be entered again when elog cleanup tries to release memory!
862
+ */
863
+ void
864
+ SlabCheck(MemoryContext context)
865
+ {
866
+ SlabContext *slab = (SlabContext *) context;
867
+ int i;
868
+ int nblocks = 0;
869
+ const char *name = slab->header.name;
870
+ dlist_iter iter;
871
+
872
+ Assert(SlabIsValid(slab));
873
+ Assert(slab->chunksPerBlock > 0);
874
+
875
+ /*
876
+ * Have a look at the empty blocks. These should have all their chunks
877
+ * marked as free. Ensure that's the case.
878
+ */
879
+ dclist_foreach(iter, &slab->emptyblocks)
880
+ {
881
+ SlabBlock *block = dlist_container(SlabBlock, node, iter.cur);
882
+
883
+ if (block->nfree != slab->chunksPerBlock)
884
+ elog(WARNING, "problem in slab %s: empty block %p should have %d free chunks but has %d chunks free",
885
+ name, block, slab->chunksPerBlock, block->nfree);
886
+ }
887
+
888
+ /* walk the non-empty block lists */
889
+ for (i = 0; i < SLAB_BLOCKLIST_COUNT; i++)
890
+ {
891
+ int j,
892
+ nfree;
893
+
894
+ /* walk all blocks on this blocklist */
895
+ dlist_foreach(iter, &slab->blocklist[i])
896
+ {
897
+ SlabBlock *block = dlist_container(SlabBlock, node, iter.cur);
898
+ MemoryChunk *cur_chunk;
899
+
900
+ /*
901
+ * Make sure the number of free chunks (in the block header)
902
+ * matches the position in the blocklist.
903
+ */
904
+ if (SlabBlocklistIndex(slab, block->nfree) != i)
905
+ elog(WARNING, "problem in slab %s: block %p is on blocklist %d but should be on blocklist %d",
906
+ name, block, i, SlabBlocklistIndex(slab, block->nfree));
907
+
908
+ /* make sure the block is not empty */
909
+ if (block->nfree >= slab->chunksPerBlock)
910
+ elog(WARNING, "problem in slab %s: empty block %p incorrectly stored on blocklist element %d",
911
+ name, block, i);
912
+
913
+ /* make sure the slab pointer correctly points to this context */
914
+ if (block->slab != slab)
915
+ elog(WARNING, "problem in slab %s: bogus slab link in block %p",
916
+ name, block);
917
+
918
+ /* reset the array of free chunks for this block */
919
+ memset(slab->isChunkFree, 0, (slab->chunksPerBlock * sizeof(bool)));
920
+ nfree = 0;
921
+
922
+ /* walk through the block's free list chunks */
923
+ cur_chunk = block->freehead;
924
+ while (cur_chunk != NULL)
925
+ {
926
+ int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
927
+
928
+ /*
929
+ * Ensure the free list link points to something on the block
930
+ * at an address aligned according to the full chunk size.
931
+ */
932
+ if (cur_chunk < SlabBlockGetChunk(slab, block, 0) ||
933
+ cur_chunk > SlabBlockGetChunk(slab, block, slab->chunksPerBlock - 1) ||
934
+ SlabChunkMod(slab, block, cur_chunk) != 0)
935
+ elog(WARNING, "problem in slab %s: bogus free list link %p in block %p",
936
+ name, cur_chunk, block);
937
+
938
+ /* count the chunk and mark it free on the free chunk array */
939
+ nfree++;
940
+ slab->isChunkFree[chunkidx] = true;
941
+
942
+ /* read pointer of the next free chunk */
943
+ VALGRIND_MAKE_MEM_DEFINED(MemoryChunkGetPointer(cur_chunk), sizeof(MemoryChunk *));
944
+ cur_chunk = *(MemoryChunk **) SlabChunkGetPointer(cur_chunk);
945
+ }
946
+
947
+ /* check that the unused pointer matches what nunused claims */
948
+ if (SlabBlockGetChunk(slab, block, slab->chunksPerBlock - block->nunused) !=
949
+ block->unused)
950
+ elog(WARNING, "problem in slab %s: mismatch detected between nunused chunks and unused pointer in block %p",
951
+ name, block);
952
+
953
+ /*
954
+ * count the remaining free chunks that have yet to make it onto
955
+ * the block's free list.
956
+ */
957
+ cur_chunk = block->unused;
958
+ for (j = 0; j < block->nunused; j++)
959
+ {
960
+ int chunkidx = SlabChunkIndex(slab, block, cur_chunk);
961
+
962
+
963
+ /* count the chunk as free and mark it as so in the array */
964
+ nfree++;
965
+ if (chunkidx < slab->chunksPerBlock)
966
+ slab->isChunkFree[chunkidx] = true;
967
+
968
+ /* move forward 1 chunk */
969
+ cur_chunk = (MemoryChunk *) (((char *) cur_chunk) + slab->fullChunkSize);
970
+ }
971
+
972
+ for (j = 0; j < slab->chunksPerBlock; j++)
973
+ {
974
+ if (!slab->isChunkFree[j])
975
+ {
976
+ MemoryChunk *chunk = SlabBlockGetChunk(slab, block, j);
977
+ SlabBlock *chunkblock;
978
+
979
+ /* Allow access to the chunk header. */
980
+ VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
981
+
982
+ chunkblock = (SlabBlock *) MemoryChunkGetBlock(chunk);
983
+
984
+ /* Disallow access to the chunk header. */
985
+ VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
986
+
987
+ /*
988
+ * check the chunk's blockoffset correctly points back to
989
+ * the block
990
+ */
991
+ if (chunkblock != block)
992
+ elog(WARNING, "problem in slab %s: bogus block link in block %p, chunk %p",
993
+ name, block, chunk);
994
+
995
+ /* check the sentinel byte is intact */
996
+ Assert(slab->chunkSize < (slab->fullChunkSize - Slab_CHUNKHDRSZ));
997
+ if (!sentinel_ok(chunk, Slab_CHUNKHDRSZ + slab->chunkSize))
998
+ elog(WARNING, "problem in slab %s: detected write past chunk end in block %p, chunk %p",
999
+ name, block, chunk);
1000
+ }
1001
+ }
1002
+
1003
+ /*
1004
+ * Make sure we got the expected number of free chunks (as tracked
1005
+ * in the block header).
1006
+ */
1007
+ if (nfree != block->nfree)
1008
+ elog(WARNING, "problem in slab %s: nfree in block %p is %d but %d chunk were found as free",
1009
+ name, block, block->nfree, nfree);
1010
+
1011
+ nblocks++;
1012
+ }
1013
+ }
1014
+
1015
+ /* the stored empty blocks are tracked in mem_allocated too */
1016
+ nblocks += dclist_count(&slab->emptyblocks);
1017
+
1018
+ Assert(nblocks * slab->blockSize == context->mem_allocated);
1019
+ }
1020
+
1021
+ #endif /* MEMORY_CONTEXT_CHECKING */