pg_query 2.0.3 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +165 -0
- data/README.md +67 -29
- data/Rakefile +8 -23
- data/ext/pg_query/extconf.rb +21 -3
- data/ext/pg_query/include/pg_query.h +29 -4
- data/ext/pg_query/include/pg_query_enum_defs.c +551 -272
- data/ext/pg_query/include/pg_query_fingerprint_conds.c +563 -470
- data/ext/pg_query/include/pg_query_fingerprint_defs.c +5403 -3945
- data/ext/pg_query/include/pg_query_outfuncs_conds.c +402 -330
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +1319 -1059
- data/ext/pg_query/include/pg_query_readfuncs_conds.c +141 -118
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +1685 -1379
- data/ext/pg_query/include/{access → postgres/access}/amapi.h +47 -1
- data/ext/pg_query/include/{access → postgres/access}/attmap.h +5 -3
- data/ext/pg_query/include/{access → postgres/access}/attnum.h +2 -2
- data/ext/pg_query/include/{access → postgres/access}/clog.h +4 -2
- data/ext/pg_query/include/{access → postgres/access}/commit_ts.h +6 -9
- data/ext/pg_query/include/{access → postgres/access}/detoast.h +1 -11
- data/ext/pg_query/include/{access → postgres/access}/genam.h +21 -16
- data/ext/pg_query/include/{access → postgres/access}/gin.h +17 -4
- data/ext/pg_query/include/{access → postgres/access}/htup.h +1 -1
- data/ext/pg_query/include/{access → postgres/access}/htup_details.h +80 -88
- data/ext/pg_query/include/{access → postgres/access}/itup.h +61 -52
- data/ext/pg_query/include/{access → postgres/access}/parallel.h +2 -2
- data/ext/pg_query/include/{access → postgres/access}/printtup.h +1 -1
- data/ext/pg_query/include/{access → postgres/access}/relation.h +1 -1
- data/ext/pg_query/include/{access → postgres/access}/relscan.h +17 -2
- data/ext/pg_query/include/postgres/access/rmgr.h +62 -0
- data/ext/pg_query/include/{access → postgres/access}/rmgrlist.h +24 -24
- data/ext/pg_query/include/{access → postgres/access}/sdir.h +12 -3
- data/ext/pg_query/include/{access → postgres/access}/skey.h +1 -1
- data/ext/pg_query/include/{access → postgres/access}/stratnum.h +4 -2
- data/ext/pg_query/include/{access → postgres/access}/sysattr.h +1 -1
- data/ext/pg_query/include/{access → postgres/access}/table.h +2 -1
- data/ext/pg_query/include/{access → postgres/access}/tableam.h +337 -62
- data/ext/pg_query/include/postgres/access/toast_compression.h +73 -0
- data/ext/pg_query/include/{access → postgres/access}/transam.h +123 -13
- data/ext/pg_query/include/postgres/access/tsmapi.h +82 -0
- data/ext/pg_query/include/{access → postgres/access}/tupconvert.h +5 -2
- data/ext/pg_query/include/{access → postgres/access}/tupdesc.h +2 -2
- data/ext/pg_query/include/{access → postgres/access}/tupmacs.h +60 -100
- data/ext/pg_query/include/{access → postgres/access}/twophase.h +5 -1
- data/ext/pg_query/include/{access → postgres/access}/xact.h +99 -32
- data/ext/pg_query/include/{access → postgres/access}/xlog.h +69 -165
- data/ext/pg_query/include/{access → postgres/access}/xlog_internal.h +147 -73
- data/ext/pg_query/include/postgres/access/xlogbackup.h +41 -0
- data/ext/pg_query/include/{access → postgres/access}/xlogdefs.h +13 -40
- data/ext/pg_query/include/postgres/access/xlogprefetcher.h +55 -0
- data/ext/pg_query/include/{access → postgres/access}/xlogreader.h +154 -37
- data/ext/pg_query/include/{access → postgres/access}/xlogrecord.h +34 -13
- data/ext/pg_query/include/postgres/access/xlogrecovery.h +158 -0
- data/ext/pg_query/include/postgres/archive/archive_module.h +59 -0
- data/ext/pg_query/include/{c.h → postgres/c.h} +245 -188
- data/ext/pg_query/include/{catalog → postgres/catalog}/catalog.h +6 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/catversion.h +6 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/dependency.h +14 -19
- data/ext/pg_query/include/postgres/catalog/genbki.h +143 -0
- data/ext/pg_query/include/{catalog → postgres/catalog}/index.h +20 -5
- data/ext/pg_query/include/postgres/catalog/indexing.h +54 -0
- data/ext/pg_query/include/{catalog → postgres/catalog}/namespace.h +5 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/objectaccess.h +73 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/objectaddress.h +12 -7
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_aggregate.h +14 -10
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_aggregate_d.h +2 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_am.h +4 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_am_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_attribute.h +45 -26
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_attribute_d.h +19 -16
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_authid.h +7 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_authid_d.h +19 -9
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_class.h +45 -15
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_class_d.h +31 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_collation.h +35 -8
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_collation_d.h +21 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_constraint.h +39 -13
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_constraint_d.h +10 -4
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_control.h +13 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_conversion.h +8 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_conversion_d.h +4 -1
- data/ext/pg_query/include/postgres/catalog/pg_database.h +124 -0
- data/ext/pg_query/include/postgres/catalog/pg_database_d.h +52 -0
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_depend.h +11 -7
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_depend_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_event_trigger.h +9 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_event_trigger_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_index.h +17 -7
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_index_d.h +20 -17
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_language.h +10 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_language_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_namespace.h +7 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_namespace_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_opclass.h +8 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_opclass_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_operator.h +21 -16
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_operator_d.h +37 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_opfamily.h +8 -4
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_opfamily_d.h +6 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_partitioned_table.h +20 -9
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_partitioned_table_d.h +2 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_proc.h +20 -11
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_proc_d.h +10 -8
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_publication.h +49 -6
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_publication_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_replication_origin.h +6 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_replication_origin_d.h +5 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_statistic.h +19 -12
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_statistic_d.h +2 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_statistic_ext.h +19 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_statistic_ext_d.h +7 -2
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_transform.h +8 -5
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_transform_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_trigger.h +24 -8
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_trigger_d.h +4 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_config.h +6 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_config_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_dict.h +8 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_dict_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_parser.h +6 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_parser_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_template.h +6 -3
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_ts_template_d.h +3 -1
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_type.h +56 -24
- data/ext/pg_query/include/{catalog → postgres/catalog}/pg_type_d.h +70 -31
- data/ext/pg_query/include/{catalog → postgres/catalog}/storage.h +9 -7
- data/ext/pg_query/include/{commands → postgres/commands}/async.h +4 -5
- data/ext/pg_query/include/{commands → postgres/commands}/dbcommands.h +3 -1
- data/ext/pg_query/include/{commands → postgres/commands}/defrem.h +12 -24
- data/ext/pg_query/include/{commands → postgres/commands}/event_trigger.h +2 -2
- data/ext/pg_query/include/{commands → postgres/commands}/explain.h +3 -1
- data/ext/pg_query/include/{commands → postgres/commands}/prepare.h +1 -1
- data/ext/pg_query/include/{commands → postgres/commands}/tablespace.h +6 -4
- data/ext/pg_query/include/{commands → postgres/commands}/trigger.h +36 -25
- data/ext/pg_query/include/{commands → postgres/commands}/user.h +10 -4
- data/ext/pg_query/include/{commands → postgres/commands}/vacuum.h +140 -47
- data/ext/pg_query/include/postgres/common/cryptohash.h +39 -0
- data/ext/pg_query/include/{common → postgres/common}/file_perm.h +4 -4
- data/ext/pg_query/include/{common → postgres/common}/hashfn.h +1 -1
- data/ext/pg_query/include/postgres/common/int.h +437 -0
- data/ext/pg_query/include/{common → postgres/common}/keywords.h +2 -6
- data/ext/pg_query/include/{common → postgres/common}/kwlookup.h +2 -2
- data/ext/pg_query/include/postgres/common/pg_prng.h +61 -0
- data/ext/pg_query/include/{common → postgres/common}/relpath.h +21 -14
- data/ext/pg_query/include/postgres/common/scram-common.h +70 -0
- data/ext/pg_query/include/postgres/common/sha2.h +32 -0
- data/ext/pg_query/include/postgres/common/string.h +44 -0
- data/ext/pg_query/include/postgres/common/unicode_east_asian_fw_table.h +125 -0
- data/ext/pg_query/include/{common/unicode_combining_table.h → postgres/common/unicode_nonspacing_table.h} +138 -8
- data/ext/pg_query/include/postgres/copyfuncs.funcs.c +5013 -0
- data/ext/pg_query/include/postgres/copyfuncs.switch.c +938 -0
- data/ext/pg_query/include/{datatype → postgres/datatype}/timestamp.h +50 -4
- data/ext/pg_query/include/postgres/equalfuncs.funcs.c +3097 -0
- data/ext/pg_query/include/postgres/equalfuncs.switch.c +785 -0
- data/ext/pg_query/include/{executor → postgres/executor}/execdesc.h +1 -1
- data/ext/pg_query/include/{executor → postgres/executor}/executor.h +98 -32
- data/ext/pg_query/include/{executor → postgres/executor}/functions.h +17 -3
- data/ext/pg_query/include/{executor → postgres/executor}/instrument.h +33 -16
- data/ext/pg_query/include/{executor → postgres/executor}/spi.h +42 -4
- data/ext/pg_query/include/{executor → postgres/executor}/tablefunc.h +1 -1
- data/ext/pg_query/include/{executor → postgres/executor}/tuptable.h +18 -11
- data/ext/pg_query/include/{fmgr.h → postgres/fmgr.h} +33 -8
- data/ext/pg_query/include/postgres/foreign/fdwapi.h +294 -0
- data/ext/pg_query/include/{funcapi.h → postgres/funcapi.h} +22 -10
- data/ext/pg_query/include/postgres/gram.h +1127 -0
- data/ext/pg_query/include/{parser → postgres}/gramparse.h +4 -4
- data/ext/pg_query/include/{jit → postgres/jit}/jit.h +12 -12
- data/ext/pg_query/include/postgres/kwlist_d.h +1119 -0
- data/ext/pg_query/include/postgres/lib/dshash.h +115 -0
- data/ext/pg_query/include/{lib → postgres/lib}/ilist.h +454 -22
- data/ext/pg_query/include/{lib → postgres/lib}/pairingheap.h +1 -1
- data/ext/pg_query/include/{lib → postgres/lib}/simplehash.h +158 -33
- data/ext/pg_query/include/postgres/lib/sort_template.h +432 -0
- data/ext/pg_query/include/{lib → postgres/lib}/stringinfo.h +3 -3
- data/ext/pg_query/include/{libpq → postgres/libpq}/auth.h +12 -4
- data/ext/pg_query/include/{libpq → postgres/libpq}/crypt.h +5 -4
- data/ext/pg_query/include/{libpq → postgres/libpq}/hba.h +54 -8
- data/ext/pg_query/include/{libpq → postgres/libpq}/libpq-be.h +45 -17
- data/ext/pg_query/include/{libpq → postgres/libpq}/libpq.h +31 -20
- data/ext/pg_query/include/{libpq → postgres/libpq}/pqcomm.h +26 -71
- data/ext/pg_query/include/{libpq → postgres/libpq}/pqformat.h +2 -2
- data/ext/pg_query/include/{libpq → postgres/libpq}/pqsignal.h +25 -13
- data/ext/pg_query/include/postgres/libpq/sasl.h +136 -0
- data/ext/pg_query/include/postgres/libpq/scram.h +37 -0
- data/ext/pg_query/include/{mb → postgres/mb}/pg_wchar.h +125 -25
- data/ext/pg_query/include/{mb → postgres/mb}/stringinfo_mb.h +1 -1
- data/ext/pg_query/include/{miscadmin.h → postgres/miscadmin.h} +96 -65
- data/ext/pg_query/include/{nodes → postgres/nodes}/bitmapset.h +11 -7
- data/ext/pg_query/include/{nodes → postgres/nodes}/execnodes.h +351 -103
- data/ext/pg_query/include/{nodes → postgres/nodes}/extensible.h +8 -4
- data/ext/pg_query/include/{nodes → postgres/nodes}/lockoptions.h +1 -1
- data/ext/pg_query/include/{nodes → postgres/nodes}/makefuncs.h +19 -6
- data/ext/pg_query/include/{nodes → postgres/nodes}/memnodes.h +11 -6
- data/ext/pg_query/include/postgres/nodes/miscnodes.h +56 -0
- data/ext/pg_query/include/{nodes → postgres/nodes}/nodeFuncs.h +89 -29
- data/ext/pg_query/include/{nodes → postgres/nodes}/nodes.h +100 -496
- data/ext/pg_query/include/postgres/nodes/nodetags.h +471 -0
- data/ext/pg_query/include/{nodes → postgres/nodes}/params.h +3 -3
- data/ext/pg_query/include/{nodes → postgres/nodes}/parsenodes.h +678 -207
- data/ext/pg_query/include/{nodes → postgres/nodes}/pathnodes.h +1282 -454
- data/ext/pg_query/include/{nodes → postgres/nodes}/pg_list.h +103 -73
- data/ext/pg_query/include/{nodes → postgres/nodes}/plannodes.h +474 -133
- data/ext/pg_query/include/{nodes → postgres/nodes}/primnodes.h +754 -254
- data/ext/pg_query/include/{nodes → postgres/nodes}/print.h +1 -1
- data/ext/pg_query/include/postgres/nodes/queryjumble.h +86 -0
- data/ext/pg_query/include/postgres/nodes/replnodes.h +111 -0
- data/ext/pg_query/include/postgres/nodes/supportnodes.h +346 -0
- data/ext/pg_query/include/{nodes → postgres/nodes}/tidbitmap.h +1 -1
- data/ext/pg_query/include/postgres/nodes/value.h +90 -0
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/cost.h +14 -5
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/geqo.h +9 -7
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/geqo_gene.h +1 -1
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/optimizer.h +31 -28
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/paths.h +29 -12
- data/ext/pg_query/include/{optimizer → postgres/optimizer}/planmain.h +15 -17
- data/ext/pg_query/include/{parser → postgres/parser}/analyze.h +20 -5
- data/ext/pg_query/include/postgres/parser/kwlist.h +498 -0
- data/ext/pg_query/include/{parser → postgres/parser}/parse_agg.h +5 -8
- data/ext/pg_query/include/{parser → postgres/parser}/parse_coerce.h +6 -1
- data/ext/pg_query/include/{parser → postgres/parser}/parse_expr.h +2 -3
- data/ext/pg_query/include/{parser → postgres/parser}/parse_func.h +2 -1
- data/ext/pg_query/include/{parser → postgres/parser}/parse_node.h +41 -11
- data/ext/pg_query/include/{parser → postgres/parser}/parse_oper.h +3 -5
- data/ext/pg_query/include/{parser → postgres/parser}/parse_relation.h +11 -5
- data/ext/pg_query/include/{parser → postgres/parser}/parse_type.h +4 -3
- data/ext/pg_query/include/postgres/parser/parser.h +68 -0
- data/ext/pg_query/include/{parser → postgres/parser}/parsetree.h +1 -1
- data/ext/pg_query/include/{parser → postgres/parser}/scanner.h +2 -2
- data/ext/pg_query/include/{parser → postgres/parser}/scansup.h +2 -5
- data/ext/pg_query/include/{partitioning → postgres/partitioning}/partdefs.h +1 -1
- data/ext/pg_query/include/{pg_config.h → postgres/pg_config.h} +216 -228
- data/ext/pg_query/include/{pg_config_manual.h → postgres/pg_config_manual.h} +80 -58
- data/ext/pg_query/include/postgres/pg_config_os.h +8 -0
- data/ext/pg_query/include/{pg_getopt.h → postgres/pg_getopt.h} +6 -6
- data/ext/pg_query/include/{pg_trace.h → postgres/pg_trace.h} +1 -1
- data/ext/pg_query/include/postgres/pgstat.h +778 -0
- data/ext/pg_query/include/{pgtime.h → postgres/pgtime.h} +16 -6
- data/ext/pg_query/include/{pl_gram.h → postgres/pl_gram.h} +116 -116
- data/ext/pg_query/include/{pl_reserved_kwlist.h → postgres/pl_reserved_kwlist.h} +1 -1
- data/ext/pg_query/include/{pl_reserved_kwlist_d.h → postgres/pl_reserved_kwlist_d.h} +10 -10
- data/ext/pg_query/include/{pl_unreserved_kwlist.h → postgres/pl_unreserved_kwlist.h} +3 -3
- data/ext/pg_query/include/{pl_unreserved_kwlist_d.h → postgres/pl_unreserved_kwlist_d.h} +60 -60
- data/ext/pg_query/include/{plerrcodes.h → postgres/plerrcodes.h} +9 -1
- data/ext/pg_query/include/{plpgsql.h → postgres/plpgsql.h} +79 -86
- data/ext/pg_query/include/{port → postgres/port}/atomics/arch-arm.h +9 -3
- data/ext/pg_query/include/postgres/port/atomics/arch-hppa.h +17 -0
- data/ext/pg_query/include/{port → postgres/port}/atomics/arch-ppc.h +21 -21
- data/ext/pg_query/include/{port → postgres/port}/atomics/arch-x86.h +2 -2
- data/ext/pg_query/include/{port → postgres/port}/atomics/fallback.h +3 -3
- data/ext/pg_query/include/{port → postgres/port}/atomics/generic-gcc.h +3 -3
- data/ext/pg_query/include/postgres/port/atomics/generic-msvc.h +101 -0
- data/ext/pg_query/include/postgres/port/atomics/generic-sunpro.h +106 -0
- data/ext/pg_query/include/{port → postgres/port}/atomics/generic.h +1 -1
- data/ext/pg_query/include/{port → postgres/port}/atomics.h +2 -7
- data/ext/pg_query/include/{port → postgres/port}/pg_bitutils.h +129 -16
- data/ext/pg_query/include/{port → postgres/port}/pg_bswap.h +1 -1
- data/ext/pg_query/include/{port → postgres/port}/pg_crc32c.h +1 -1
- data/ext/pg_query/include/postgres/port/simd.h +375 -0
- data/ext/pg_query/include/postgres/port/win32/arpa/inet.h +3 -0
- data/ext/pg_query/include/postgres/port/win32/dlfcn.h +1 -0
- data/ext/pg_query/include/postgres/port/win32/grp.h +1 -0
- data/ext/pg_query/include/postgres/port/win32/netdb.h +7 -0
- data/ext/pg_query/include/postgres/port/win32/netinet/in.h +3 -0
- data/ext/pg_query/include/postgres/port/win32/netinet/tcp.h +7 -0
- data/ext/pg_query/include/postgres/port/win32/pwd.h +3 -0
- data/ext/pg_query/include/postgres/port/win32/sys/resource.h +20 -0
- data/ext/pg_query/include/postgres/port/win32/sys/select.h +3 -0
- data/ext/pg_query/include/postgres/port/win32/sys/socket.h +26 -0
- data/ext/pg_query/include/postgres/port/win32/sys/un.h +17 -0
- data/ext/pg_query/include/postgres/port/win32/sys/wait.h +3 -0
- data/ext/pg_query/include/postgres/port/win32.h +59 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/dirent.h +34 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/sys/file.h +1 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/sys/param.h +1 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/sys/time.h +1 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/unistd.h +9 -0
- data/ext/pg_query/include/postgres/port/win32_msvc/utime.h +3 -0
- data/ext/pg_query/include/postgres/port/win32_port.h +594 -0
- data/ext/pg_query/include/{port.h → postgres/port.h} +107 -111
- data/ext/pg_query/include/postgres/portability/instr_time.h +197 -0
- data/ext/pg_query/include/postgres/postgres.h +579 -0
- data/ext/pg_query/include/{postgres_ext.h → postgres/postgres_ext.h} +0 -1
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/autovacuum.h +17 -20
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/bgworker.h +3 -2
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/bgworker_internals.h +2 -2
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/bgwriter.h +6 -6
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/interrupt.h +1 -1
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/pgarch.h +7 -10
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/postmaster.h +21 -17
- data/ext/pg_query/include/postgres/postmaster/startup.h +41 -0
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/syslogger.h +16 -11
- data/ext/pg_query/include/{postmaster → postgres/postmaster}/walwriter.h +5 -3
- data/ext/pg_query/include/{regex → postgres/regex}/regex.h +27 -22
- data/ext/pg_query/include/{replication → postgres/replication}/logicallauncher.h +8 -5
- data/ext/pg_query/include/postgres/replication/logicalproto.h +274 -0
- data/ext/pg_query/include/postgres/replication/logicalworker.h +32 -0
- data/ext/pg_query/include/{replication → postgres/replication}/origin.h +8 -8
- data/ext/pg_query/include/postgres/replication/reorderbuffer.h +753 -0
- data/ext/pg_query/include/{replication → postgres/replication}/slot.h +42 -12
- data/ext/pg_query/include/{replication → postgres/replication}/syncrep.h +6 -12
- data/ext/pg_query/include/{replication → postgres/replication}/walreceiver.h +158 -20
- data/ext/pg_query/include/{replication → postgres/replication}/walsender.h +20 -20
- data/ext/pg_query/include/{rewrite → postgres/rewrite}/prs2lock.h +1 -1
- data/ext/pg_query/include/{rewrite → postgres/rewrite}/rewriteHandler.h +1 -6
- data/ext/pg_query/include/{rewrite → postgres/rewrite}/rewriteManip.h +11 -2
- data/ext/pg_query/include/{rewrite → postgres/rewrite}/rewriteSupport.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/backendid.h +3 -3
- data/ext/pg_query/include/{storage → postgres/storage}/block.h +24 -37
- data/ext/pg_query/include/{storage → postgres/storage}/buf.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/bufmgr.h +196 -95
- data/ext/pg_query/include/{storage → postgres/storage}/bufpage.h +152 -101
- data/ext/pg_query/include/{storage → postgres/storage}/condition_variable.h +14 -3
- data/ext/pg_query/include/{storage → postgres/storage}/dsm.h +6 -6
- data/ext/pg_query/include/{storage → postgres/storage}/dsm_impl.h +6 -2
- data/ext/pg_query/include/{storage → postgres/storage}/fd.h +48 -14
- data/ext/pg_query/include/postgres/storage/fileset.h +40 -0
- data/ext/pg_query/include/{storage → postgres/storage}/ipc.h +5 -2
- data/ext/pg_query/include/{storage → postgres/storage}/item.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/itemid.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/itemptr.h +96 -57
- data/ext/pg_query/include/{storage → postgres/storage}/large_object.h +2 -2
- data/ext/pg_query/include/{storage → postgres/storage}/latch.h +17 -13
- data/ext/pg_query/include/{storage → postgres/storage}/lmgr.h +7 -1
- data/ext/pg_query/include/{storage → postgres/storage}/lock.h +37 -25
- data/ext/pg_query/include/{storage → postgres/storage}/lockdefs.h +4 -4
- data/ext/pg_query/include/{storage → postgres/storage}/lwlock.h +21 -33
- data/ext/pg_query/include/{storage → postgres/storage}/lwlocknames.h +0 -1
- data/ext/pg_query/include/{storage → postgres/storage}/off.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/pg_sema.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/pg_shmem.h +9 -7
- data/ext/pg_query/include/{storage → postgres/storage}/pmsignal.h +15 -4
- data/ext/pg_query/include/{storage → postgres/storage}/predicate.h +5 -5
- data/ext/pg_query/include/{storage → postgres/storage}/proc.h +200 -67
- data/ext/pg_query/include/postgres/storage/procarray.h +99 -0
- data/ext/pg_query/include/{storage → postgres/storage}/proclist_types.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/procsignal.h +5 -7
- data/ext/pg_query/include/postgres/storage/relfilelocator.h +99 -0
- data/ext/pg_query/include/{storage → postgres/storage}/s_lock.h +118 -298
- data/ext/pg_query/include/{storage → postgres/storage}/sharedfileset.h +3 -11
- data/ext/pg_query/include/{storage → postgres/storage}/shm_mq.h +5 -4
- data/ext/pg_query/include/{storage → postgres/storage}/shm_toc.h +1 -1
- data/ext/pg_query/include/{storage → postgres/storage}/shmem.h +1 -23
- data/ext/pg_query/include/{storage → postgres/storage}/sinval.h +5 -5
- data/ext/pg_query/include/{storage → postgres/storage}/sinvaladt.h +4 -2
- data/ext/pg_query/include/{storage → postgres/storage}/smgr.h +21 -17
- data/ext/pg_query/include/{storage → postgres/storage}/spin.h +2 -2
- data/ext/pg_query/include/{storage → postgres/storage}/standby.h +17 -9
- data/ext/pg_query/include/{storage → postgres/storage}/standbydefs.h +2 -2
- data/ext/pg_query/include/{storage → postgres/storage}/sync.h +9 -5
- data/ext/pg_query/include/{tcop → postgres/tcop}/cmdtag.h +7 -2
- data/ext/pg_query/include/{tcop → postgres/tcop}/cmdtaglist.h +3 -2
- data/ext/pg_query/include/{tcop → postgres/tcop}/deparse_utility.h +1 -1
- data/ext/pg_query/include/{tcop → postgres/tcop}/dest.h +1 -3
- data/ext/pg_query/include/{tcop → postgres/tcop}/fastpath.h +1 -2
- data/ext/pg_query/include/{tcop → postgres/tcop}/pquery.h +7 -1
- data/ext/pg_query/include/{tcop → postgres/tcop}/tcopprot.h +19 -14
- data/ext/pg_query/include/{tcop → postgres/tcop}/utility.h +7 -3
- data/ext/pg_query/include/{tsearch → postgres/tsearch}/ts_cache.h +3 -5
- data/ext/pg_query/include/{utils → postgres/utils}/acl.h +37 -71
- data/ext/pg_query/include/{utils → postgres/utils}/aclchk_internal.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/array.h +26 -2
- data/ext/pg_query/include/postgres/utils/backend_progress.h +45 -0
- data/ext/pg_query/include/postgres/utils/backend_status.h +342 -0
- data/ext/pg_query/include/{utils → postgres/utils}/builtins.h +20 -11
- data/ext/pg_query/include/{utils → postgres/utils}/bytea.h +3 -2
- data/ext/pg_query/include/{utils → postgres/utils}/catcache.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/date.h +37 -9
- data/ext/pg_query/include/{utils → postgres/utils}/datetime.h +48 -27
- data/ext/pg_query/include/{utils → postgres/utils}/datum.h +9 -1
- data/ext/pg_query/include/{utils → postgres/utils}/dsa.h +5 -1
- data/ext/pg_query/include/{utils → postgres/utils}/elog.h +154 -48
- data/ext/pg_query/include/{utils → postgres/utils}/errcodes.h +2 -0
- data/ext/pg_query/include/{utils → postgres/utils}/expandeddatum.h +14 -3
- data/ext/pg_query/include/{utils → postgres/utils}/expandedrecord.h +14 -4
- data/ext/pg_query/include/{utils → postgres/utils}/float.h +13 -12
- data/ext/pg_query/include/{utils → postgres/utils}/fmgroids.h +1353 -696
- data/ext/pg_query/include/{utils → postgres/utils}/fmgrprotos.h +243 -18
- data/ext/pg_query/include/{utils → postgres/utils}/fmgrtab.h +6 -5
- data/ext/pg_query/include/{utils → postgres/utils}/guc.h +120 -121
- data/ext/pg_query/include/postgres/utils/guc_hooks.h +163 -0
- data/ext/pg_query/include/{utils → postgres/utils}/guc_tables.h +71 -21
- data/ext/pg_query/include/{utils → postgres/utils}/hsearch.h +15 -11
- data/ext/pg_query/include/{utils → postgres/utils}/inval.h +7 -3
- data/ext/pg_query/include/postgres/utils/logtape.h +77 -0
- data/ext/pg_query/include/{utils → postgres/utils}/lsyscache.h +16 -1
- data/ext/pg_query/include/{utils → postgres/utils}/memdebug.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/memutils.h +14 -53
- data/ext/pg_query/include/postgres/utils/memutils_internal.h +136 -0
- data/ext/pg_query/include/postgres/utils/memutils_memorychunk.h +237 -0
- data/ext/pg_query/include/{utils → postgres/utils}/numeric.h +38 -9
- data/ext/pg_query/include/{utils → postgres/utils}/palloc.h +33 -4
- data/ext/pg_query/include/{utils → postgres/utils}/partcache.h +3 -2
- data/ext/pg_query/include/{utils → postgres/utils}/pg_locale.h +37 -21
- data/ext/pg_query/include/postgres/utils/pgstat_internal.h +814 -0
- data/ext/pg_query/include/{utils → postgres/utils}/plancache.h +6 -5
- data/ext/pg_query/include/{utils → postgres/utils}/portal.h +12 -1
- data/ext/pg_query/include/{utils → postgres/utils}/probes.h +59 -59
- data/ext/pg_query/include/postgres/utils/ps_status.h +47 -0
- data/ext/pg_query/include/{utils → postgres/utils}/queryenvironment.h +1 -1
- data/ext/pg_query/include/postgres/utils/regproc.h +39 -0
- data/ext/pg_query/include/{utils → postgres/utils}/rel.h +129 -61
- data/ext/pg_query/include/{utils → postgres/utils}/relcache.h +21 -14
- data/ext/pg_query/include/{utils → postgres/utils}/reltrigger.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/resowner.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/ruleutils.h +9 -1
- data/ext/pg_query/include/{utils → postgres/utils}/sharedtuplestore.h +1 -1
- data/ext/pg_query/include/{utils → postgres/utils}/snapmgr.h +38 -15
- data/ext/pg_query/include/{utils → postgres/utils}/snapshot.h +14 -1
- data/ext/pg_query/include/{utils → postgres/utils}/sortsupport.h +117 -2
- data/ext/pg_query/include/{utils → postgres/utils}/syscache.h +9 -1
- data/ext/pg_query/include/{utils → postgres/utils}/timeout.h +11 -4
- data/ext/pg_query/include/{utils → postgres/utils}/timestamp.h +46 -15
- data/ext/pg_query/include/{utils → postgres/utils}/tuplesort.h +209 -41
- data/ext/pg_query/include/{utils → postgres/utils}/tuplestore.h +2 -2
- data/ext/pg_query/include/{utils → postgres/utils}/typcache.h +24 -17
- data/ext/pg_query/include/{utils → postgres/utils}/varlena.h +17 -3
- data/ext/pg_query/include/postgres/utils/wait_event.h +294 -0
- data/ext/pg_query/include/{utils → postgres/utils}/xml.h +18 -8
- data/ext/pg_query/include/{postgres.h → postgres/varatt.h} +65 -471
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +7494 -6382
- data/ext/pg_query/include/protobuf/pg_query.pb.h +116922 -84792
- data/ext/pg_query/include/protobuf-c/protobuf-c.h +7 -3
- data/ext/pg_query/include/protobuf-c.h +7 -3
- data/ext/pg_query/pg_query.c +10 -1
- data/ext/pg_query/pg_query.pb-c.c +21026 -17002
- data/ext/pg_query/pg_query_deparse.c +1 -9896
- data/ext/pg_query/pg_query_fingerprint.c +162 -50
- data/ext/pg_query/pg_query_fingerprint.h +3 -1
- data/ext/pg_query/pg_query_internal.h +1 -1
- data/ext/pg_query/pg_query_json_plpgsql.c +56 -12
- data/ext/pg_query/pg_query_normalize.c +259 -64
- data/ext/pg_query/pg_query_outfuncs.h +1 -0
- data/ext/pg_query/pg_query_outfuncs_json.c +71 -16
- data/ext/pg_query/pg_query_outfuncs_protobuf.c +73 -12
- data/ext/pg_query/pg_query_parse.c +47 -5
- data/ext/pg_query/pg_query_parse_plpgsql.c +86 -21
- data/ext/pg_query/pg_query_readfuncs_protobuf.c +43 -8
- data/ext/pg_query/pg_query_ruby.c +6 -1
- data/ext/pg_query/pg_query_ruby_freebsd.sym +2 -0
- data/ext/pg_query/pg_query_scan.c +3 -2
- data/ext/pg_query/pg_query_split.c +6 -5
- data/ext/pg_query/postgres_deparse.c +11067 -0
- data/ext/pg_query/postgres_deparse.h +9 -0
- data/ext/pg_query/protobuf-c.c +34 -27
- data/ext/pg_query/src_backend_catalog_namespace.c +27 -10
- data/ext/pg_query/src_backend_catalog_pg_proc.c +4 -1
- data/ext/pg_query/src_backend_commands_define.c +11 -1
- data/ext/pg_query/src_backend_nodes_bitmapset.c +13 -70
- data/ext/pg_query/src_backend_nodes_copyfuncs.c +103 -5894
- data/ext/pg_query/src_backend_nodes_equalfuncs.c +102 -3830
- data/ext/pg_query/src_backend_nodes_extensible.c +6 -29
- data/ext/pg_query/src_backend_nodes_list.c +99 -12
- data/ext/pg_query/src_backend_nodes_makefuncs.c +99 -4
- data/ext/pg_query/src_backend_nodes_nodeFuncs.c +325 -131
- data/ext/pg_query/src_backend_nodes_nodes.c +38 -0
- data/ext/pg_query/src_backend_nodes_value.c +28 -19
- data/ext/pg_query/src_backend_parser_gram.c +36104 -32074
- data/ext/pg_query/src_backend_parser_parser.c +53 -8
- data/ext/pg_query/src_backend_parser_scan.c +4893 -3701
- data/ext/pg_query/src_backend_parser_scansup.c +4 -28
- data/ext/pg_query/src_backend_storage_ipc_ipc.c +13 -4
- data/ext/pg_query/src_backend_tcop_postgres.c +133 -105
- data/ext/pg_query/src_backend_utils_activity_pgstat_database.c +140 -0
- data/ext/pg_query/src_backend_utils_adt_datum.c +17 -7
- data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +1 -1
- data/ext/pg_query/src_backend_utils_adt_format_type.c +6 -2
- data/ext/pg_query/src_backend_utils_adt_numutils.c +489 -0
- data/ext/pg_query/src_backend_utils_adt_ruleutils.c +187 -19
- data/ext/pg_query/src_backend_utils_error_assert.c +17 -18
- data/ext/pg_query/src_backend_utils_error_elog.c +513 -318
- data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +44 -17
- data/ext/pg_query/src_backend_utils_init_globals.c +9 -6
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +74 -131
- data/ext/pg_query/src_backend_utils_misc_guc_tables.c +492 -0
- data/ext/pg_query/src_backend_utils_mmgr_alignedalloc.c +163 -0
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +453 -314
- data/ext/pg_query/src_backend_utils_mmgr_generation.c +1039 -0
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +549 -76
- data/ext/pg_query/src_backend_utils_mmgr_slab.c +1021 -0
- data/ext/pg_query/src_common_encnames.c +4 -1
- data/ext/pg_query/src_common_hashfn.c +420 -0
- data/ext/pg_query/src_common_keywords.c +15 -2
- data/ext/pg_query/src_common_kwlist_d.h +545 -498
- data/ext/pg_query/src_common_kwlookup.c +1 -1
- data/ext/pg_query/src_common_psprintf.c +1 -1
- data/ext/pg_query/src_common_stringinfo.c +4 -4
- data/ext/pg_query/src_common_wchar.c +717 -113
- data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +49 -22
- data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +3 -18
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +1136 -1195
- data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +1 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +10 -10
- data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +2 -2
- data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +60 -60
- data/ext/pg_query/src_port_pg_bitutils.c +103 -40
- data/ext/pg_query/src_port_pgstrcasecmp.c +29 -1
- data/ext/pg_query/src_port_qsort.c +12 -224
- data/ext/pg_query/src_port_snprintf.c +51 -29
- data/ext/pg_query/src_port_strerror.c +9 -19
- data/ext/pg_query/src_port_strlcpy.c +79 -0
- data/lib/pg_query/deparse.rb +7 -1
- data/lib/pg_query/filter_columns.rb +7 -5
- data/lib/pg_query/fingerprint.rb +21 -9
- data/lib/pg_query/node.rb +18 -13
- data/lib/pg_query/param_refs.rb +1 -1
- data/lib/pg_query/parse.rb +141 -50
- data/lib/pg_query/pg_query_pb.rb +175 -3031
- data/lib/pg_query/treewalker.rb +26 -2
- data/lib/pg_query/truncate.rb +54 -8
- data/lib/pg_query/version.rb +1 -1
- data/lib/pg_query.rb +0 -1
- metadata +443 -380
- data/ext/pg_query/guc-file.c +0 -0
- data/ext/pg_query/include/access/rmgr.h +0 -35
- data/ext/pg_query/include/access/xloginsert.h +0 -64
- data/ext/pg_query/include/bootstrap/bootstrap.h +0 -62
- data/ext/pg_query/include/catalog/genbki.h +0 -64
- data/ext/pg_query/include/catalog/indexing.h +0 -366
- data/ext/pg_query/include/commands/variable.h +0 -38
- data/ext/pg_query/include/common/ip.h +0 -37
- data/ext/pg_query/include/common/string.h +0 -19
- data/ext/pg_query/include/getaddrinfo.h +0 -162
- data/ext/pg_query/include/kwlist_d.h +0 -1072
- data/ext/pg_query/include/nodes/value.h +0 -61
- data/ext/pg_query/include/parser/gram.h +0 -1067
- data/ext/pg_query/include/parser/kwlist.h +0 -477
- data/ext/pg_query/include/parser/parse_clause.h +0 -54
- data/ext/pg_query/include/parser/parse_collate.h +0 -27
- data/ext/pg_query/include/parser/parse_target.h +0 -46
- data/ext/pg_query/include/parser/parser.h +0 -41
- data/ext/pg_query/include/pg_config_os.h +0 -8
- data/ext/pg_query/include/pgstat.h +0 -1487
- data/ext/pg_query/include/portability/instr_time.h +0 -256
- data/ext/pg_query/include/postmaster/fork_process.h +0 -17
- data/ext/pg_query/include/replication/logicalproto.h +0 -110
- data/ext/pg_query/include/replication/logicalworker.h +0 -19
- data/ext/pg_query/include/replication/reorderbuffer.h +0 -467
- data/ext/pg_query/include/storage/relfilenode.h +0 -99
- data/ext/pg_query/include/utils/dynahash.h +0 -19
- data/ext/pg_query/include/utils/pg_lsn.h +0 -29
- data/ext/pg_query/include/utils/pidfile.h +0 -56
- data/ext/pg_query/include/utils/ps_status.h +0 -25
- data/ext/pg_query/include/utils/regproc.h +0 -28
- data/ext/pg_query/include/utils/rls.h +0 -50
- data/ext/pg_query/include/utils/tzparser.h +0 -39
- data/ext/pg_query/src_backend_libpq_pqcomm.c +0 -651
- data/ext/pg_query/src_backend_parser_parse_expr.c +0 -313
- data/ext/pg_query/src_backend_postmaster_postmaster.c +0 -2230
- data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +0 -370
- data/ext/pg_query/src_backend_utils_hash_dynahash.c +0 -1086
- data/ext/pg_query/src_backend_utils_misc_guc.c +0 -1831
- data/ext/pg_query/src_common_string.c +0 -86
- data/ext/pg_query/src_port_erand48.c +0 -127
- data/ext/pg_query/src_port_pgsleep.c +0 -69
- data/ext/pg_query/src_port_random.c +0 -31
- data/ext/pg_query/src_port_strnlen.c +0 -39
- data/lib/pg_query/json_field_names.rb +0 -1402
- /data/ext/pg_query/include/{pg_config_ext.h → postgres/pg_config_ext.h} +0 -0
|
@@ -0,0 +1,1039 @@
|
|
|
1
|
+
/*--------------------------------------------------------------------
|
|
2
|
+
* Symbols referenced in this file:
|
|
3
|
+
* - GenerationAlloc
|
|
4
|
+
* - GenerationBlockFreeBytes
|
|
5
|
+
* - GenerationBlockIsEmpty
|
|
6
|
+
* - GenerationBlockInit
|
|
7
|
+
* - GenerationFree
|
|
8
|
+
* - GenerationBlockMarkEmpty
|
|
9
|
+
* - GenerationRealloc
|
|
10
|
+
* - GenerationReset
|
|
11
|
+
* - GenerationBlockFree
|
|
12
|
+
* - GenerationDelete
|
|
13
|
+
* - GenerationGetChunkContext
|
|
14
|
+
* - GenerationGetChunkSpace
|
|
15
|
+
* - GenerationIsEmpty
|
|
16
|
+
* - GenerationStats
|
|
17
|
+
* - GenerationCheck
|
|
18
|
+
*--------------------------------------------------------------------
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/*-------------------------------------------------------------------------
|
|
22
|
+
*
|
|
23
|
+
* generation.c
|
|
24
|
+
* Generational allocator definitions.
|
|
25
|
+
*
|
|
26
|
+
* Generation is a custom MemoryContext implementation designed for cases of
|
|
27
|
+
* chunks with similar lifespan.
|
|
28
|
+
*
|
|
29
|
+
* Portions Copyright (c) 2017-2023, PostgreSQL Global Development Group
|
|
30
|
+
*
|
|
31
|
+
* IDENTIFICATION
|
|
32
|
+
* src/backend/utils/mmgr/generation.c
|
|
33
|
+
*
|
|
34
|
+
*
|
|
35
|
+
* This memory context is based on the assumption that the chunks are freed
|
|
36
|
+
* roughly in the same order as they were allocated (FIFO), or in groups with
|
|
37
|
+
* similar lifespan (generations - hence the name of the context). This is
|
|
38
|
+
* typical for various queue-like use cases, i.e. when tuples are constructed,
|
|
39
|
+
* processed and then thrown away.
|
|
40
|
+
*
|
|
41
|
+
* The memory context uses a very simple approach to free space management.
|
|
42
|
+
* Instead of a complex global freelist, each block tracks a number
|
|
43
|
+
* of allocated and freed chunks. The block is classed as empty when the
|
|
44
|
+
* number of free chunks is equal to the number of allocated chunks. When
|
|
45
|
+
* this occurs, instead of freeing the block, we try to "recycle" it, i.e.
|
|
46
|
+
* reuse it for new allocations. This is done by setting the block in the
|
|
47
|
+
* context's 'freeblock' field. If the freeblock field is already occupied
|
|
48
|
+
* by another free block we simply return the newly empty block to malloc.
|
|
49
|
+
*
|
|
50
|
+
* This approach to free blocks requires fewer malloc/free calls for truly
|
|
51
|
+
* first allocated, first free'd allocation patterns.
|
|
52
|
+
*
|
|
53
|
+
*-------------------------------------------------------------------------
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
#include "postgres.h"
|
|
57
|
+
|
|
58
|
+
#include "lib/ilist.h"
|
|
59
|
+
#include "port/pg_bitutils.h"
|
|
60
|
+
#include "utils/memdebug.h"
|
|
61
|
+
#include "utils/memutils.h"
|
|
62
|
+
#include "utils/memutils_memorychunk.h"
|
|
63
|
+
#include "utils/memutils_internal.h"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
#define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock))
|
|
67
|
+
#define Generation_CHUNKHDRSZ sizeof(MemoryChunk)
|
|
68
|
+
|
|
69
|
+
#define Generation_CHUNK_FRACTION 8
|
|
70
|
+
|
|
71
|
+
typedef struct GenerationBlock GenerationBlock; /* forward reference */
|
|
72
|
+
|
|
73
|
+
typedef void *GenerationPointer;
|
|
74
|
+
|
|
75
|
+
/*
|
|
76
|
+
* GenerationContext is a simple memory context not reusing allocated chunks,
|
|
77
|
+
* and freeing blocks once all chunks are freed.
|
|
78
|
+
*/
|
|
79
|
+
typedef struct GenerationContext
|
|
80
|
+
{
|
|
81
|
+
MemoryContextData header; /* Standard memory-context fields */
|
|
82
|
+
|
|
83
|
+
/* Generational context parameters */
|
|
84
|
+
Size initBlockSize; /* initial block size */
|
|
85
|
+
Size maxBlockSize; /* maximum block size */
|
|
86
|
+
Size nextBlockSize; /* next block size to allocate */
|
|
87
|
+
Size allocChunkLimit; /* effective chunk size limit */
|
|
88
|
+
|
|
89
|
+
GenerationBlock *block; /* current (most recently allocated) block, or
|
|
90
|
+
* NULL if we've just freed the most recent
|
|
91
|
+
* block */
|
|
92
|
+
GenerationBlock *freeblock; /* pointer to a block that's being recycled,
|
|
93
|
+
* or NULL if there's no such block. */
|
|
94
|
+
GenerationBlock *keeper; /* keep this block over resets */
|
|
95
|
+
dlist_head blocks; /* list of blocks */
|
|
96
|
+
} GenerationContext;
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* GenerationBlock
|
|
100
|
+
* GenerationBlock is the unit of memory that is obtained by generation.c
|
|
101
|
+
* from malloc(). It contains zero or more MemoryChunks, which are the
|
|
102
|
+
* units requested by palloc() and freed by pfree(). MemoryChunks cannot
|
|
103
|
+
* be returned to malloc() individually, instead pfree() updates the free
|
|
104
|
+
* counter of the block and when all chunks in a block are free the whole
|
|
105
|
+
* block can be returned to malloc().
|
|
106
|
+
*
|
|
107
|
+
* GenerationBlock is the header data for a block --- the usable space
|
|
108
|
+
* within the block begins at the next alignment boundary.
|
|
109
|
+
*/
|
|
110
|
+
struct GenerationBlock
|
|
111
|
+
{
|
|
112
|
+
dlist_node node; /* doubly-linked list of blocks */
|
|
113
|
+
GenerationContext *context; /* pointer back to the owning context */
|
|
114
|
+
Size blksize; /* allocated size of this block */
|
|
115
|
+
int nchunks; /* number of chunks in the block */
|
|
116
|
+
int nfree; /* number of free chunks */
|
|
117
|
+
char *freeptr; /* start of free space in this block */
|
|
118
|
+
char *endptr; /* end of space in this block */
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/*
|
|
122
|
+
* GenerationIsValid
|
|
123
|
+
* True iff set is valid generation set.
|
|
124
|
+
*/
|
|
125
|
+
#define GenerationIsValid(set) \
|
|
126
|
+
(PointerIsValid(set) && IsA(set, GenerationContext))
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
* GenerationBlockIsValid
|
|
130
|
+
* True iff block is valid block of generation set.
|
|
131
|
+
*/
|
|
132
|
+
#define GenerationBlockIsValid(block) \
|
|
133
|
+
(PointerIsValid(block) && GenerationIsValid((block)->context))
|
|
134
|
+
|
|
135
|
+
/*
|
|
136
|
+
* We always store external chunks on a dedicated block. This makes fetching
|
|
137
|
+
* the block from an external chunk easy since it's always the first and only
|
|
138
|
+
* chunk on the block.
|
|
139
|
+
*/
|
|
140
|
+
#define ExternalChunkGetBlock(chunk) \
|
|
141
|
+
(GenerationBlock *) ((char *) chunk - Generation_BLOCKHDRSZ)
|
|
142
|
+
|
|
143
|
+
/* Inlined helper functions */
|
|
144
|
+
static inline void GenerationBlockInit(GenerationContext *context,
|
|
145
|
+
GenerationBlock *block,
|
|
146
|
+
Size blksize);
|
|
147
|
+
static inline bool GenerationBlockIsEmpty(GenerationBlock *block);
|
|
148
|
+
static inline void GenerationBlockMarkEmpty(GenerationBlock *block);
|
|
149
|
+
static inline Size GenerationBlockFreeBytes(GenerationBlock *block);
|
|
150
|
+
static inline void GenerationBlockFree(GenerationContext *set,
|
|
151
|
+
GenerationBlock *block);
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* Public routines
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* GenerationContextCreate
|
|
161
|
+
* Create a new Generation context.
|
|
162
|
+
*
|
|
163
|
+
* parent: parent context, or NULL if top-level context
|
|
164
|
+
* name: name of context (must be statically allocated)
|
|
165
|
+
* minContextSize: minimum context size
|
|
166
|
+
* initBlockSize: initial allocation block size
|
|
167
|
+
* maxBlockSize: maximum allocation block size
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
/*
|
|
172
|
+
* GenerationReset
|
|
173
|
+
* Frees all memory which is allocated in the given set.
|
|
174
|
+
*
|
|
175
|
+
* The code simply frees all the blocks in the context - we don't keep any
|
|
176
|
+
* keeper blocks or anything like that.
|
|
177
|
+
*/
|
|
178
|
+
void
|
|
179
|
+
GenerationReset(MemoryContext context)
|
|
180
|
+
{
|
|
181
|
+
GenerationContext *set = (GenerationContext *) context;
|
|
182
|
+
dlist_mutable_iter miter;
|
|
183
|
+
|
|
184
|
+
Assert(GenerationIsValid(set));
|
|
185
|
+
|
|
186
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
187
|
+
/* Check for corruption and leaks before freeing */
|
|
188
|
+
GenerationCheck(context);
|
|
189
|
+
#endif
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* NULLify the free block pointer. We must do this before calling
|
|
193
|
+
* GenerationBlockFree as that function never expects to free the
|
|
194
|
+
* freeblock.
|
|
195
|
+
*/
|
|
196
|
+
set->freeblock = NULL;
|
|
197
|
+
|
|
198
|
+
dlist_foreach_modify(miter, &set->blocks)
|
|
199
|
+
{
|
|
200
|
+
GenerationBlock *block = dlist_container(GenerationBlock, node, miter.cur);
|
|
201
|
+
|
|
202
|
+
if (block == set->keeper)
|
|
203
|
+
GenerationBlockMarkEmpty(block);
|
|
204
|
+
else
|
|
205
|
+
GenerationBlockFree(set, block);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* set it so new allocations to make use of the keeper block */
|
|
209
|
+
set->block = set->keeper;
|
|
210
|
+
|
|
211
|
+
/* Reset block size allocation sequence, too */
|
|
212
|
+
set->nextBlockSize = set->initBlockSize;
|
|
213
|
+
|
|
214
|
+
/* Ensure there is only 1 item in the dlist */
|
|
215
|
+
Assert(!dlist_is_empty(&set->blocks));
|
|
216
|
+
Assert(!dlist_has_next(&set->blocks, dlist_head_node(&set->blocks)));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
* GenerationDelete
|
|
221
|
+
* Free all memory which is allocated in the given context.
|
|
222
|
+
*/
|
|
223
|
+
void
|
|
224
|
+
GenerationDelete(MemoryContext context)
|
|
225
|
+
{
|
|
226
|
+
/* Reset to release all releasable GenerationBlocks */
|
|
227
|
+
GenerationReset(context);
|
|
228
|
+
/* And free the context header and keeper block */
|
|
229
|
+
free(context);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* GenerationAlloc
|
|
234
|
+
* Returns pointer to allocated memory of given size or NULL if
|
|
235
|
+
* request could not be completed; memory is added to the set.
|
|
236
|
+
*
|
|
237
|
+
* No request may exceed:
|
|
238
|
+
* MAXALIGN_DOWN(SIZE_MAX) - Generation_BLOCKHDRSZ - Generation_CHUNKHDRSZ
|
|
239
|
+
* All callers use a much-lower limit.
|
|
240
|
+
*
|
|
241
|
+
* Note: when using valgrind, it doesn't matter how the returned allocation
|
|
242
|
+
* is marked, as mcxt.c will set it to UNDEFINED. In some paths we will
|
|
243
|
+
* return space that is marked NOACCESS - GenerationRealloc has to beware!
|
|
244
|
+
*/
|
|
245
|
+
void *
|
|
246
|
+
GenerationAlloc(MemoryContext context, Size size)
|
|
247
|
+
{
|
|
248
|
+
GenerationContext *set = (GenerationContext *) context;
|
|
249
|
+
GenerationBlock *block;
|
|
250
|
+
MemoryChunk *chunk;
|
|
251
|
+
Size chunk_size;
|
|
252
|
+
Size required_size;
|
|
253
|
+
|
|
254
|
+
Assert(GenerationIsValid(set));
|
|
255
|
+
|
|
256
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
257
|
+
/* ensure there's always space for the sentinel byte */
|
|
258
|
+
chunk_size = MAXALIGN(size + 1);
|
|
259
|
+
#else
|
|
260
|
+
chunk_size = MAXALIGN(size);
|
|
261
|
+
#endif
|
|
262
|
+
required_size = chunk_size + Generation_CHUNKHDRSZ;
|
|
263
|
+
|
|
264
|
+
/* is it an over-sized chunk? if yes, allocate special block */
|
|
265
|
+
if (chunk_size > set->allocChunkLimit)
|
|
266
|
+
{
|
|
267
|
+
Size blksize = required_size + Generation_BLOCKHDRSZ;
|
|
268
|
+
|
|
269
|
+
block = (GenerationBlock *) malloc(blksize);
|
|
270
|
+
if (block == NULL)
|
|
271
|
+
return NULL;
|
|
272
|
+
|
|
273
|
+
context->mem_allocated += blksize;
|
|
274
|
+
|
|
275
|
+
/* block with a single (used) chunk */
|
|
276
|
+
block->context = set;
|
|
277
|
+
block->blksize = blksize;
|
|
278
|
+
block->nchunks = 1;
|
|
279
|
+
block->nfree = 0;
|
|
280
|
+
|
|
281
|
+
/* the block is completely full */
|
|
282
|
+
block->freeptr = block->endptr = ((char *) block) + blksize;
|
|
283
|
+
|
|
284
|
+
chunk = (MemoryChunk *) (((char *) block) + Generation_BLOCKHDRSZ);
|
|
285
|
+
|
|
286
|
+
/* mark the MemoryChunk as externally managed */
|
|
287
|
+
MemoryChunkSetHdrMaskExternal(chunk, MCTX_GENERATION_ID);
|
|
288
|
+
|
|
289
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
290
|
+
chunk->requested_size = size;
|
|
291
|
+
/* set mark to catch clobber of "unused" space */
|
|
292
|
+
Assert(size < chunk_size);
|
|
293
|
+
set_sentinel(MemoryChunkGetPointer(chunk), size);
|
|
294
|
+
#endif
|
|
295
|
+
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
|
296
|
+
/* fill the allocated space with junk */
|
|
297
|
+
randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
|
|
298
|
+
#endif
|
|
299
|
+
|
|
300
|
+
/* add the block to the list of allocated blocks */
|
|
301
|
+
dlist_push_head(&set->blocks, &block->node);
|
|
302
|
+
|
|
303
|
+
/* Ensure any padding bytes are marked NOACCESS. */
|
|
304
|
+
VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
|
|
305
|
+
chunk_size - size);
|
|
306
|
+
|
|
307
|
+
/* Disallow access to the chunk header. */
|
|
308
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
309
|
+
|
|
310
|
+
return MemoryChunkGetPointer(chunk);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*
|
|
314
|
+
* Not an oversized chunk. We try to first make use of the current block,
|
|
315
|
+
* but if there's not enough space in it, instead of allocating a new
|
|
316
|
+
* block, we look to see if the freeblock is empty and has enough space.
|
|
317
|
+
* If not, we'll also try the same using the keeper block. The keeper
|
|
318
|
+
* block may have become empty and we have no other way to reuse it again
|
|
319
|
+
* if we don't try to use it explicitly here.
|
|
320
|
+
*
|
|
321
|
+
* We don't want to start filling the freeblock before the current block
|
|
322
|
+
* is full, otherwise we may cause fragmentation in FIFO type workloads.
|
|
323
|
+
* We only switch to using the freeblock or keeper block if those blocks
|
|
324
|
+
* are completely empty. If we didn't do that we could end up fragmenting
|
|
325
|
+
* consecutive allocations over multiple blocks which would be a problem
|
|
326
|
+
* that would compound over time.
|
|
327
|
+
*/
|
|
328
|
+
block = set->block;
|
|
329
|
+
|
|
330
|
+
if (block == NULL ||
|
|
331
|
+
GenerationBlockFreeBytes(block) < required_size)
|
|
332
|
+
{
|
|
333
|
+
Size blksize;
|
|
334
|
+
GenerationBlock *freeblock = set->freeblock;
|
|
335
|
+
|
|
336
|
+
if (freeblock != NULL &&
|
|
337
|
+
GenerationBlockIsEmpty(freeblock) &&
|
|
338
|
+
GenerationBlockFreeBytes(freeblock) >= required_size)
|
|
339
|
+
{
|
|
340
|
+
block = freeblock;
|
|
341
|
+
|
|
342
|
+
/*
|
|
343
|
+
* Zero out the freeblock as we'll set this to the current block
|
|
344
|
+
* below
|
|
345
|
+
*/
|
|
346
|
+
set->freeblock = NULL;
|
|
347
|
+
}
|
|
348
|
+
else if (GenerationBlockIsEmpty(set->keeper) &&
|
|
349
|
+
GenerationBlockFreeBytes(set->keeper) >= required_size)
|
|
350
|
+
{
|
|
351
|
+
block = set->keeper;
|
|
352
|
+
}
|
|
353
|
+
else
|
|
354
|
+
{
|
|
355
|
+
/*
|
|
356
|
+
* The first such block has size initBlockSize, and we double the
|
|
357
|
+
* space in each succeeding block, but not more than maxBlockSize.
|
|
358
|
+
*/
|
|
359
|
+
blksize = set->nextBlockSize;
|
|
360
|
+
set->nextBlockSize <<= 1;
|
|
361
|
+
if (set->nextBlockSize > set->maxBlockSize)
|
|
362
|
+
set->nextBlockSize = set->maxBlockSize;
|
|
363
|
+
|
|
364
|
+
/* we'll need a block hdr too, so add that to the required size */
|
|
365
|
+
required_size += Generation_BLOCKHDRSZ;
|
|
366
|
+
|
|
367
|
+
/* round the size up to the next power of 2 */
|
|
368
|
+
if (blksize < required_size)
|
|
369
|
+
blksize = pg_nextpower2_size_t(required_size);
|
|
370
|
+
|
|
371
|
+
block = (GenerationBlock *) malloc(blksize);
|
|
372
|
+
|
|
373
|
+
if (block == NULL)
|
|
374
|
+
return NULL;
|
|
375
|
+
|
|
376
|
+
context->mem_allocated += blksize;
|
|
377
|
+
|
|
378
|
+
/* initialize the new block */
|
|
379
|
+
GenerationBlockInit(set, block, blksize);
|
|
380
|
+
|
|
381
|
+
/* add it to the doubly-linked list of blocks */
|
|
382
|
+
dlist_push_head(&set->blocks, &block->node);
|
|
383
|
+
|
|
384
|
+
/* Zero out the freeblock in case it's become full */
|
|
385
|
+
set->freeblock = NULL;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* and also use it as the current allocation block */
|
|
389
|
+
set->block = block;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* we're supposed to have a block with enough free space now */
|
|
393
|
+
Assert(block != NULL);
|
|
394
|
+
Assert((block->endptr - block->freeptr) >= Generation_CHUNKHDRSZ + chunk_size);
|
|
395
|
+
|
|
396
|
+
chunk = (MemoryChunk *) block->freeptr;
|
|
397
|
+
|
|
398
|
+
/* Prepare to initialize the chunk header. */
|
|
399
|
+
VALGRIND_MAKE_MEM_UNDEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
400
|
+
|
|
401
|
+
block->nchunks += 1;
|
|
402
|
+
block->freeptr += (Generation_CHUNKHDRSZ + chunk_size);
|
|
403
|
+
|
|
404
|
+
Assert(block->freeptr <= block->endptr);
|
|
405
|
+
|
|
406
|
+
MemoryChunkSetHdrMask(chunk, block, chunk_size, MCTX_GENERATION_ID);
|
|
407
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
408
|
+
chunk->requested_size = size;
|
|
409
|
+
/* set mark to catch clobber of "unused" space */
|
|
410
|
+
Assert(size < chunk_size);
|
|
411
|
+
set_sentinel(MemoryChunkGetPointer(chunk), size);
|
|
412
|
+
#endif
|
|
413
|
+
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
|
414
|
+
/* fill the allocated space with junk */
|
|
415
|
+
randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
|
|
416
|
+
#endif
|
|
417
|
+
|
|
418
|
+
/* Ensure any padding bytes are marked NOACCESS. */
|
|
419
|
+
VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
|
|
420
|
+
chunk_size - size);
|
|
421
|
+
|
|
422
|
+
/* Disallow access to the chunk header. */
|
|
423
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
424
|
+
|
|
425
|
+
return MemoryChunkGetPointer(chunk);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/*
|
|
429
|
+
* GenerationBlockInit
|
|
430
|
+
* Initializes 'block' assuming 'blksize'. Does not update the context's
|
|
431
|
+
* mem_allocated field.
|
|
432
|
+
*/
|
|
433
|
+
static inline void
|
|
434
|
+
GenerationBlockInit(GenerationContext *context, GenerationBlock *block,
|
|
435
|
+
Size blksize)
|
|
436
|
+
{
|
|
437
|
+
block->context = context;
|
|
438
|
+
block->blksize = blksize;
|
|
439
|
+
block->nchunks = 0;
|
|
440
|
+
block->nfree = 0;
|
|
441
|
+
|
|
442
|
+
block->freeptr = ((char *) block) + Generation_BLOCKHDRSZ;
|
|
443
|
+
block->endptr = ((char *) block) + blksize;
|
|
444
|
+
|
|
445
|
+
/* Mark unallocated space NOACCESS. */
|
|
446
|
+
VALGRIND_MAKE_MEM_NOACCESS(block->freeptr,
|
|
447
|
+
blksize - Generation_BLOCKHDRSZ);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/*
|
|
451
|
+
* GenerationBlockIsEmpty
|
|
452
|
+
* Returns true iff 'block' contains no chunks
|
|
453
|
+
*/
|
|
454
|
+
static inline bool
|
|
455
|
+
GenerationBlockIsEmpty(GenerationBlock *block)
|
|
456
|
+
{
|
|
457
|
+
return (block->nchunks == 0);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/*
|
|
461
|
+
* GenerationBlockMarkEmpty
|
|
462
|
+
* Set a block as empty. Does not free the block.
|
|
463
|
+
*/
|
|
464
|
+
static inline void
|
|
465
|
+
GenerationBlockMarkEmpty(GenerationBlock *block)
|
|
466
|
+
{
|
|
467
|
+
#if defined(USE_VALGRIND) || defined(CLOBBER_FREED_MEMORY)
|
|
468
|
+
char *datastart = ((char *) block) + Generation_BLOCKHDRSZ;
|
|
469
|
+
#endif
|
|
470
|
+
|
|
471
|
+
#ifdef CLOBBER_FREED_MEMORY
|
|
472
|
+
wipe_mem(datastart, block->freeptr - datastart);
|
|
473
|
+
#else
|
|
474
|
+
/* wipe_mem() would have done this */
|
|
475
|
+
VALGRIND_MAKE_MEM_NOACCESS(datastart, block->freeptr - datastart);
|
|
476
|
+
#endif
|
|
477
|
+
|
|
478
|
+
/* Reset the block, but don't return it to malloc */
|
|
479
|
+
block->nchunks = 0;
|
|
480
|
+
block->nfree = 0;
|
|
481
|
+
block->freeptr = ((char *) block) + Generation_BLOCKHDRSZ;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/*
|
|
485
|
+
* GenerationBlockFreeBytes
|
|
486
|
+
* Returns the number of bytes free in 'block'
|
|
487
|
+
*/
|
|
488
|
+
static inline Size
|
|
489
|
+
GenerationBlockFreeBytes(GenerationBlock *block)
|
|
490
|
+
{
|
|
491
|
+
return (block->endptr - block->freeptr);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/*
|
|
495
|
+
* GenerationBlockFree
|
|
496
|
+
* Remove 'block' from 'set' and release the memory consumed by it.
|
|
497
|
+
*/
|
|
498
|
+
static inline void
|
|
499
|
+
GenerationBlockFree(GenerationContext *set, GenerationBlock *block)
|
|
500
|
+
{
|
|
501
|
+
/* Make sure nobody tries to free the keeper block */
|
|
502
|
+
Assert(block != set->keeper);
|
|
503
|
+
/* We shouldn't be freeing the freeblock either */
|
|
504
|
+
Assert(block != set->freeblock);
|
|
505
|
+
|
|
506
|
+
/* release the block from the list of blocks */
|
|
507
|
+
dlist_delete(&block->node);
|
|
508
|
+
|
|
509
|
+
((MemoryContext) set)->mem_allocated -= block->blksize;
|
|
510
|
+
|
|
511
|
+
#ifdef CLOBBER_FREED_MEMORY
|
|
512
|
+
wipe_mem(block, block->blksize);
|
|
513
|
+
#endif
|
|
514
|
+
|
|
515
|
+
free(block);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/*
|
|
519
|
+
* GenerationFree
|
|
520
|
+
* Update number of chunks in the block, and if all chunks in the block
|
|
521
|
+
* are now free then discard the block.
|
|
522
|
+
*/
|
|
523
|
+
void
|
|
524
|
+
GenerationFree(void *pointer)
|
|
525
|
+
{
|
|
526
|
+
MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
|
|
527
|
+
GenerationBlock *block;
|
|
528
|
+
GenerationContext *set;
|
|
529
|
+
#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
|
|
530
|
+
|| defined(CLOBBER_FREED_MEMORY)
|
|
531
|
+
Size chunksize;
|
|
532
|
+
#endif
|
|
533
|
+
|
|
534
|
+
/* Allow access to the chunk header. */
|
|
535
|
+
VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
536
|
+
|
|
537
|
+
if (MemoryChunkIsExternal(chunk))
|
|
538
|
+
{
|
|
539
|
+
block = ExternalChunkGetBlock(chunk);
|
|
540
|
+
|
|
541
|
+
/*
|
|
542
|
+
* Try to verify that we have a sane block pointer: the block header
|
|
543
|
+
* should reference a generation context.
|
|
544
|
+
*/
|
|
545
|
+
if (!GenerationBlockIsValid(block))
|
|
546
|
+
elog(ERROR, "could not find block containing chunk %p", chunk);
|
|
547
|
+
|
|
548
|
+
#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
|
|
549
|
+
|| defined(CLOBBER_FREED_MEMORY)
|
|
550
|
+
chunksize = block->endptr - (char *) pointer;
|
|
551
|
+
#endif
|
|
552
|
+
}
|
|
553
|
+
else
|
|
554
|
+
{
|
|
555
|
+
block = MemoryChunkGetBlock(chunk);
|
|
556
|
+
|
|
557
|
+
/*
|
|
558
|
+
* In this path, for speed reasons we just Assert that the referenced
|
|
559
|
+
* block is good. Future field experience may show that this Assert
|
|
560
|
+
* had better become a regular runtime test-and-elog check.
|
|
561
|
+
*/
|
|
562
|
+
Assert(GenerationBlockIsValid(block));
|
|
563
|
+
|
|
564
|
+
#if (defined(MEMORY_CONTEXT_CHECKING) && defined(USE_ASSERT_CHECKING)) \
|
|
565
|
+
|| defined(CLOBBER_FREED_MEMORY)
|
|
566
|
+
chunksize = MemoryChunkGetValue(chunk);
|
|
567
|
+
#endif
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
571
|
+
/* Test for someone scribbling on unused space in chunk */
|
|
572
|
+
Assert(chunk->requested_size < chunksize);
|
|
573
|
+
if (!sentinel_ok(pointer, chunk->requested_size))
|
|
574
|
+
elog(WARNING, "detected write past chunk end in %s %p",
|
|
575
|
+
((MemoryContext) block->context)->name, chunk);
|
|
576
|
+
#endif
|
|
577
|
+
|
|
578
|
+
#ifdef CLOBBER_FREED_MEMORY
|
|
579
|
+
wipe_mem(pointer, chunksize);
|
|
580
|
+
#endif
|
|
581
|
+
|
|
582
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
583
|
+
/* Reset requested_size to InvalidAllocSize in freed chunks */
|
|
584
|
+
chunk->requested_size = InvalidAllocSize;
|
|
585
|
+
#endif
|
|
586
|
+
|
|
587
|
+
block->nfree += 1;
|
|
588
|
+
|
|
589
|
+
Assert(block->nchunks > 0);
|
|
590
|
+
Assert(block->nfree <= block->nchunks);
|
|
591
|
+
|
|
592
|
+
/* If there are still allocated chunks in the block, we're done. */
|
|
593
|
+
if (block->nfree < block->nchunks)
|
|
594
|
+
return;
|
|
595
|
+
|
|
596
|
+
set = block->context;
|
|
597
|
+
|
|
598
|
+
/* Don't try to free the keeper block, just mark it empty */
|
|
599
|
+
if (block == set->keeper)
|
|
600
|
+
{
|
|
601
|
+
GenerationBlockMarkEmpty(block);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/*
|
|
606
|
+
* If there is no freeblock set or if this is the freeblock then instead
|
|
607
|
+
* of freeing this memory, we keep it around so that new allocations have
|
|
608
|
+
* the option of recycling it.
|
|
609
|
+
*/
|
|
610
|
+
if (set->freeblock == NULL || set->freeblock == block)
|
|
611
|
+
{
|
|
612
|
+
/* XXX should we only recycle maxBlockSize sized blocks? */
|
|
613
|
+
set->freeblock = block;
|
|
614
|
+
GenerationBlockMarkEmpty(block);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/* Also make sure the block is not marked as the current block. */
|
|
619
|
+
if (set->block == block)
|
|
620
|
+
set->block = NULL;
|
|
621
|
+
|
|
622
|
+
/*
|
|
623
|
+
* The block is empty, so let's get rid of it. First remove it from the
|
|
624
|
+
* list of blocks, then return it to malloc().
|
|
625
|
+
*/
|
|
626
|
+
dlist_delete(&block->node);
|
|
627
|
+
|
|
628
|
+
set->header.mem_allocated -= block->blksize;
|
|
629
|
+
free(block);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/*
|
|
633
|
+
* GenerationRealloc
|
|
634
|
+
* When handling repalloc, we simply allocate a new chunk, copy the data
|
|
635
|
+
* and discard the old one. The only exception is when the new size fits
|
|
636
|
+
* into the old chunk - in that case we just update chunk header.
|
|
637
|
+
*/
|
|
638
|
+
void *
|
|
639
|
+
GenerationRealloc(void *pointer, Size size)
|
|
640
|
+
{
|
|
641
|
+
MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
|
|
642
|
+
GenerationContext *set;
|
|
643
|
+
GenerationBlock *block;
|
|
644
|
+
GenerationPointer newPointer;
|
|
645
|
+
Size oldsize;
|
|
646
|
+
|
|
647
|
+
/* Allow access to the chunk header. */
|
|
648
|
+
VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
649
|
+
|
|
650
|
+
if (MemoryChunkIsExternal(chunk))
|
|
651
|
+
{
|
|
652
|
+
block = ExternalChunkGetBlock(chunk);
|
|
653
|
+
|
|
654
|
+
/*
|
|
655
|
+
* Try to verify that we have a sane block pointer: the block header
|
|
656
|
+
* should reference a generation context.
|
|
657
|
+
*/
|
|
658
|
+
if (!GenerationBlockIsValid(block))
|
|
659
|
+
elog(ERROR, "could not find block containing chunk %p", chunk);
|
|
660
|
+
|
|
661
|
+
oldsize = block->endptr - (char *) pointer;
|
|
662
|
+
}
|
|
663
|
+
else
|
|
664
|
+
{
|
|
665
|
+
block = MemoryChunkGetBlock(chunk);
|
|
666
|
+
|
|
667
|
+
/*
|
|
668
|
+
* In this path, for speed reasons we just Assert that the referenced
|
|
669
|
+
* block is good. Future field experience may show that this Assert
|
|
670
|
+
* had better become a regular runtime test-and-elog check.
|
|
671
|
+
*/
|
|
672
|
+
Assert(GenerationBlockIsValid(block));
|
|
673
|
+
|
|
674
|
+
oldsize = MemoryChunkGetValue(chunk);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
set = block->context;
|
|
678
|
+
|
|
679
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
680
|
+
/* Test for someone scribbling on unused space in chunk */
|
|
681
|
+
Assert(chunk->requested_size < oldsize);
|
|
682
|
+
if (!sentinel_ok(pointer, chunk->requested_size))
|
|
683
|
+
elog(WARNING, "detected write past chunk end in %s %p",
|
|
684
|
+
((MemoryContext) set)->name, chunk);
|
|
685
|
+
#endif
|
|
686
|
+
|
|
687
|
+
/*
|
|
688
|
+
* Maybe the allocated area already is >= the new size. (In particular,
|
|
689
|
+
* we always fall out here if the requested size is a decrease.)
|
|
690
|
+
*
|
|
691
|
+
* This memory context does not use power-of-2 chunk sizing and instead
|
|
692
|
+
* carves the chunks to be as small as possible, so most repalloc() calls
|
|
693
|
+
* will end up in the palloc/memcpy/pfree branch.
|
|
694
|
+
*
|
|
695
|
+
* XXX Perhaps we should annotate this condition with unlikely()?
|
|
696
|
+
*/
|
|
697
|
+
if (oldsize >= size)
|
|
698
|
+
{
|
|
699
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
700
|
+
Size oldrequest = chunk->requested_size;
|
|
701
|
+
|
|
702
|
+
#ifdef RANDOMIZE_ALLOCATED_MEMORY
|
|
703
|
+
/* We can only fill the extra space if we know the prior request */
|
|
704
|
+
if (size > oldrequest)
|
|
705
|
+
randomize_mem((char *) pointer + oldrequest,
|
|
706
|
+
size - oldrequest);
|
|
707
|
+
#endif
|
|
708
|
+
|
|
709
|
+
chunk->requested_size = size;
|
|
710
|
+
|
|
711
|
+
/*
|
|
712
|
+
* If this is an increase, mark any newly-available part UNDEFINED.
|
|
713
|
+
* Otherwise, mark the obsolete part NOACCESS.
|
|
714
|
+
*/
|
|
715
|
+
if (size > oldrequest)
|
|
716
|
+
VALGRIND_MAKE_MEM_UNDEFINED((char *) pointer + oldrequest,
|
|
717
|
+
size - oldrequest);
|
|
718
|
+
else
|
|
719
|
+
VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size,
|
|
720
|
+
oldsize - size);
|
|
721
|
+
|
|
722
|
+
/* set mark to catch clobber of "unused" space */
|
|
723
|
+
set_sentinel(pointer, size);
|
|
724
|
+
#else /* !MEMORY_CONTEXT_CHECKING */
|
|
725
|
+
|
|
726
|
+
/*
|
|
727
|
+
* We don't have the information to determine whether we're growing
|
|
728
|
+
* the old request or shrinking it, so we conservatively mark the
|
|
729
|
+
* entire new allocation DEFINED.
|
|
730
|
+
*/
|
|
731
|
+
VALGRIND_MAKE_MEM_NOACCESS(pointer, oldsize);
|
|
732
|
+
VALGRIND_MAKE_MEM_DEFINED(pointer, size);
|
|
733
|
+
#endif
|
|
734
|
+
|
|
735
|
+
/* Disallow access to the chunk header. */
|
|
736
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
737
|
+
|
|
738
|
+
return pointer;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/* allocate new chunk */
|
|
742
|
+
newPointer = GenerationAlloc((MemoryContext) set, size);
|
|
743
|
+
|
|
744
|
+
/* leave immediately if request was not completed */
|
|
745
|
+
if (newPointer == NULL)
|
|
746
|
+
{
|
|
747
|
+
/* Disallow access to the chunk header. */
|
|
748
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
749
|
+
return NULL;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/*
|
|
753
|
+
* GenerationAlloc() may have returned a region that is still NOACCESS.
|
|
754
|
+
* Change it to UNDEFINED for the moment; memcpy() will then transfer
|
|
755
|
+
* definedness from the old allocation to the new. If we know the old
|
|
756
|
+
* allocation, copy just that much. Otherwise, make the entire old chunk
|
|
757
|
+
* defined to avoid errors as we copy the currently-NOACCESS trailing
|
|
758
|
+
* bytes.
|
|
759
|
+
*/
|
|
760
|
+
VALGRIND_MAKE_MEM_UNDEFINED(newPointer, size);
|
|
761
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
762
|
+
oldsize = chunk->requested_size;
|
|
763
|
+
#else
|
|
764
|
+
VALGRIND_MAKE_MEM_DEFINED(pointer, oldsize);
|
|
765
|
+
#endif
|
|
766
|
+
|
|
767
|
+
/* transfer existing data (certain to fit) */
|
|
768
|
+
memcpy(newPointer, pointer, oldsize);
|
|
769
|
+
|
|
770
|
+
/* free old chunk */
|
|
771
|
+
GenerationFree(pointer);
|
|
772
|
+
|
|
773
|
+
return newPointer;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/*
|
|
777
|
+
* GenerationGetChunkContext
|
|
778
|
+
* Return the MemoryContext that 'pointer' belongs to.
|
|
779
|
+
*/
|
|
780
|
+
MemoryContext
|
|
781
|
+
GenerationGetChunkContext(void *pointer)
|
|
782
|
+
{
|
|
783
|
+
MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
|
|
784
|
+
GenerationBlock *block;
|
|
785
|
+
|
|
786
|
+
/* Allow access to the chunk header. */
|
|
787
|
+
VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
788
|
+
|
|
789
|
+
if (MemoryChunkIsExternal(chunk))
|
|
790
|
+
block = ExternalChunkGetBlock(chunk);
|
|
791
|
+
else
|
|
792
|
+
block = (GenerationBlock *) MemoryChunkGetBlock(chunk);
|
|
793
|
+
|
|
794
|
+
/* Disallow access to the chunk header. */
|
|
795
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
796
|
+
|
|
797
|
+
Assert(GenerationBlockIsValid(block));
|
|
798
|
+
return &block->context->header;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/*
|
|
802
|
+
* GenerationGetChunkSpace
|
|
803
|
+
* Given a currently-allocated chunk, determine the total space
|
|
804
|
+
* it occupies (including all memory-allocation overhead).
|
|
805
|
+
*/
|
|
806
|
+
Size
|
|
807
|
+
GenerationGetChunkSpace(void *pointer)
|
|
808
|
+
{
|
|
809
|
+
MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
|
|
810
|
+
Size chunksize;
|
|
811
|
+
|
|
812
|
+
/* Allow access to the chunk header. */
|
|
813
|
+
VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
814
|
+
|
|
815
|
+
if (MemoryChunkIsExternal(chunk))
|
|
816
|
+
{
|
|
817
|
+
GenerationBlock *block = ExternalChunkGetBlock(chunk);
|
|
818
|
+
|
|
819
|
+
Assert(GenerationBlockIsValid(block));
|
|
820
|
+
chunksize = block->endptr - (char *) pointer;
|
|
821
|
+
}
|
|
822
|
+
else
|
|
823
|
+
chunksize = MemoryChunkGetValue(chunk);
|
|
824
|
+
|
|
825
|
+
/* Disallow access to the chunk header. */
|
|
826
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
827
|
+
|
|
828
|
+
return Generation_CHUNKHDRSZ + chunksize;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/*
|
|
832
|
+
* GenerationIsEmpty
|
|
833
|
+
* Is a GenerationContext empty of any allocated space?
|
|
834
|
+
*/
|
|
835
|
+
bool
|
|
836
|
+
GenerationIsEmpty(MemoryContext context)
|
|
837
|
+
{
|
|
838
|
+
GenerationContext *set = (GenerationContext *) context;
|
|
839
|
+
dlist_iter iter;
|
|
840
|
+
|
|
841
|
+
Assert(GenerationIsValid(set));
|
|
842
|
+
|
|
843
|
+
dlist_foreach(iter, &set->blocks)
|
|
844
|
+
{
|
|
845
|
+
GenerationBlock *block = dlist_container(GenerationBlock, node, iter.cur);
|
|
846
|
+
|
|
847
|
+
if (block->nchunks > 0)
|
|
848
|
+
return false;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
return true;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/*
|
|
855
|
+
* GenerationStats
|
|
856
|
+
* Compute stats about memory consumption of a Generation context.
|
|
857
|
+
*
|
|
858
|
+
* printfunc: if not NULL, pass a human-readable stats string to this.
|
|
859
|
+
* passthru: pass this pointer through to printfunc.
|
|
860
|
+
* totals: if not NULL, add stats about this context into *totals.
|
|
861
|
+
* print_to_stderr: print stats to stderr if true, elog otherwise.
|
|
862
|
+
*
|
|
863
|
+
* XXX freespace only accounts for empty space at the end of the block, not
|
|
864
|
+
* space of freed chunks (which is unknown).
|
|
865
|
+
*/
|
|
866
|
+
void
|
|
867
|
+
GenerationStats(MemoryContext context,
|
|
868
|
+
MemoryStatsPrintFunc printfunc, void *passthru,
|
|
869
|
+
MemoryContextCounters *totals, bool print_to_stderr)
|
|
870
|
+
{
|
|
871
|
+
GenerationContext *set = (GenerationContext *) context;
|
|
872
|
+
Size nblocks = 0;
|
|
873
|
+
Size nchunks = 0;
|
|
874
|
+
Size nfreechunks = 0;
|
|
875
|
+
Size totalspace;
|
|
876
|
+
Size freespace = 0;
|
|
877
|
+
dlist_iter iter;
|
|
878
|
+
|
|
879
|
+
Assert(GenerationIsValid(set));
|
|
880
|
+
|
|
881
|
+
/* Include context header in totalspace */
|
|
882
|
+
totalspace = MAXALIGN(sizeof(GenerationContext));
|
|
883
|
+
|
|
884
|
+
dlist_foreach(iter, &set->blocks)
|
|
885
|
+
{
|
|
886
|
+
GenerationBlock *block = dlist_container(GenerationBlock, node, iter.cur);
|
|
887
|
+
|
|
888
|
+
nblocks++;
|
|
889
|
+
nchunks += block->nchunks;
|
|
890
|
+
nfreechunks += block->nfree;
|
|
891
|
+
totalspace += block->blksize;
|
|
892
|
+
freespace += (block->endptr - block->freeptr);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (printfunc)
|
|
896
|
+
{
|
|
897
|
+
char stats_string[200];
|
|
898
|
+
|
|
899
|
+
snprintf(stats_string, sizeof(stats_string),
|
|
900
|
+
"%zu total in %zu blocks (%zu chunks); %zu free (%zu chunks); %zu used",
|
|
901
|
+
totalspace, nblocks, nchunks, freespace,
|
|
902
|
+
nfreechunks, totalspace - freespace);
|
|
903
|
+
printfunc(context, passthru, stats_string, print_to_stderr);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (totals)
|
|
907
|
+
{
|
|
908
|
+
totals->nblocks += nblocks;
|
|
909
|
+
totals->freechunks += nfreechunks;
|
|
910
|
+
totals->totalspace += totalspace;
|
|
911
|
+
totals->freespace += freespace;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
#ifdef MEMORY_CONTEXT_CHECKING
|
|
917
|
+
|
|
918
|
+
/*
|
|
919
|
+
* GenerationCheck
|
|
920
|
+
* Walk through chunks and check consistency of memory.
|
|
921
|
+
*
|
|
922
|
+
* NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll
|
|
923
|
+
* find yourself in an infinite loop when trouble occurs, because this
|
|
924
|
+
* routine will be entered again when elog cleanup tries to release memory!
|
|
925
|
+
*/
|
|
926
|
+
void
|
|
927
|
+
GenerationCheck(MemoryContext context)
|
|
928
|
+
{
|
|
929
|
+
GenerationContext *gen = (GenerationContext *) context;
|
|
930
|
+
const char *name = context->name;
|
|
931
|
+
dlist_iter iter;
|
|
932
|
+
Size total_allocated = 0;
|
|
933
|
+
|
|
934
|
+
/* walk all blocks in this context */
|
|
935
|
+
dlist_foreach(iter, &gen->blocks)
|
|
936
|
+
{
|
|
937
|
+
GenerationBlock *block = dlist_container(GenerationBlock, node, iter.cur);
|
|
938
|
+
int nfree,
|
|
939
|
+
nchunks;
|
|
940
|
+
char *ptr;
|
|
941
|
+
bool has_external_chunk = false;
|
|
942
|
+
|
|
943
|
+
total_allocated += block->blksize;
|
|
944
|
+
|
|
945
|
+
/*
|
|
946
|
+
* nfree > nchunks is surely wrong. Equality is allowed as the block
|
|
947
|
+
* might completely empty if it's the freeblock.
|
|
948
|
+
*/
|
|
949
|
+
if (block->nfree > block->nchunks)
|
|
950
|
+
elog(WARNING, "problem in Generation %s: number of free chunks %d in block %p exceeds %d allocated",
|
|
951
|
+
name, block->nfree, block, block->nchunks);
|
|
952
|
+
|
|
953
|
+
/* check block belongs to the correct context */
|
|
954
|
+
if (block->context != gen)
|
|
955
|
+
elog(WARNING, "problem in Generation %s: bogus context link in block %p",
|
|
956
|
+
name, block);
|
|
957
|
+
|
|
958
|
+
/* Now walk through the chunks and count them. */
|
|
959
|
+
nfree = 0;
|
|
960
|
+
nchunks = 0;
|
|
961
|
+
ptr = ((char *) block) + Generation_BLOCKHDRSZ;
|
|
962
|
+
|
|
963
|
+
while (ptr < block->freeptr)
|
|
964
|
+
{
|
|
965
|
+
MemoryChunk *chunk = (MemoryChunk *) ptr;
|
|
966
|
+
GenerationBlock *chunkblock;
|
|
967
|
+
Size chunksize;
|
|
968
|
+
|
|
969
|
+
/* Allow access to the chunk header. */
|
|
970
|
+
VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
|
|
971
|
+
|
|
972
|
+
if (MemoryChunkIsExternal(chunk))
|
|
973
|
+
{
|
|
974
|
+
chunkblock = ExternalChunkGetBlock(chunk);
|
|
975
|
+
chunksize = block->endptr - (char *) MemoryChunkGetPointer(chunk);
|
|
976
|
+
has_external_chunk = true;
|
|
977
|
+
}
|
|
978
|
+
else
|
|
979
|
+
{
|
|
980
|
+
chunkblock = MemoryChunkGetBlock(chunk);
|
|
981
|
+
chunksize = MemoryChunkGetValue(chunk);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/* move to the next chunk */
|
|
985
|
+
ptr += (chunksize + Generation_CHUNKHDRSZ);
|
|
986
|
+
|
|
987
|
+
nchunks += 1;
|
|
988
|
+
|
|
989
|
+
/* chunks have both block and context pointers, so check both */
|
|
990
|
+
if (chunkblock != block)
|
|
991
|
+
elog(WARNING, "problem in Generation %s: bogus block link in block %p, chunk %p",
|
|
992
|
+
name, block, chunk);
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
/* is chunk allocated? */
|
|
996
|
+
if (chunk->requested_size != InvalidAllocSize)
|
|
997
|
+
{
|
|
998
|
+
/* now make sure the chunk size is correct */
|
|
999
|
+
if (chunksize < chunk->requested_size ||
|
|
1000
|
+
chunksize != MAXALIGN(chunksize))
|
|
1001
|
+
elog(WARNING, "problem in Generation %s: bogus chunk size in block %p, chunk %p",
|
|
1002
|
+
name, block, chunk);
|
|
1003
|
+
|
|
1004
|
+
/* check sentinel */
|
|
1005
|
+
Assert(chunk->requested_size < chunksize);
|
|
1006
|
+
if (!sentinel_ok(chunk, Generation_CHUNKHDRSZ + chunk->requested_size))
|
|
1007
|
+
elog(WARNING, "problem in Generation %s: detected write past chunk end in block %p, chunk %p",
|
|
1008
|
+
name, block, chunk);
|
|
1009
|
+
}
|
|
1010
|
+
else
|
|
1011
|
+
nfree += 1;
|
|
1012
|
+
|
|
1013
|
+
/* if chunk is allocated, disallow access to the chunk header */
|
|
1014
|
+
if (chunk->requested_size != InvalidAllocSize)
|
|
1015
|
+
VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
/*
|
|
1019
|
+
* Make sure we got the expected number of allocated and free chunks
|
|
1020
|
+
* (as tracked in the block header).
|
|
1021
|
+
*/
|
|
1022
|
+
if (nchunks != block->nchunks)
|
|
1023
|
+
elog(WARNING, "problem in Generation %s: number of allocated chunks %d in block %p does not match header %d",
|
|
1024
|
+
name, nchunks, block, block->nchunks);
|
|
1025
|
+
|
|
1026
|
+
if (nfree != block->nfree)
|
|
1027
|
+
elog(WARNING, "problem in Generation %s: number of free chunks %d in block %p does not match header %d",
|
|
1028
|
+
name, nfree, block, block->nfree);
|
|
1029
|
+
|
|
1030
|
+
if (has_external_chunk && nchunks > 1)
|
|
1031
|
+
elog(WARNING, "problem in Generation %s: external chunk on non-dedicated block %p",
|
|
1032
|
+
name, block);
|
|
1033
|
+
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
Assert(total_allocated == context->mem_allocated);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
#endif /* MEMORY_CONTEXT_CHECKING */
|