Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit bc1e209

Browse filesBrowse files
committed
Revert: Custom reloptions for table AM
This commit reverts 9bd99f4 and 4220415 per review by Andres Freund. Discussion: https://postgr.es/m/20240410165236.rwyrny7ihi4ddxw4%40awork3.anarazel.de
1 parent 87840b9 commit bc1e209
Copy full SHA for bc1e209
Expand file treeCollapse file tree

29 files changed

+161
-650
lines changed

‎src/backend/access/common/reloptions.c

Copy file name to clipboardExpand all lines: src/backend/access/common/reloptions.c
+35-114Lines changed: 35 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include "access/nbtree.h"
2525
#include "access/reloptions.h"
2626
#include "access/spgist_private.h"
27-
#include "access/tableam.h"
2827
#include "catalog/pg_type.h"
2928
#include "commands/defrem.h"
3029
#include "commands/tablespace.h"
@@ -45,7 +44,7 @@
4544
* value, upper and lower bounds (if applicable); for strings, consider a
4645
* validation routine.
4746
* (ii) add a record below (or use add_<type>_reloption).
48-
* (iii) add it to the appropriate options struct (perhaps HeapRdOptions)
47+
* (iii) add it to the appropriate options struct (perhaps StdRdOptions)
4948
* (iv) add it to the appropriate handling routine (perhaps
5049
* default_reloptions)
5150
* (v) make sure the lock level is set correctly for that operation
@@ -1375,16 +1374,10 @@ untransformRelOptions(Datum options)
13751374
* tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
13761375
* AM's options parser function in the case of a tuple corresponding to an
13771376
* index, or NULL otherwise.
1378-
*
1379-
* If common pointer is provided, then the corresponding struct will be
1380-
* filled with options that table AM exposes for external usage. That must
1381-
* be filled with defaults before passing here.
13821377
*/
1383-
13841378
bytea *
13851379
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
1386-
const TableAmRoutine *tableam, amoptions_function amoptions,
1387-
CommonRdOptions *common)
1380+
amoptions_function amoptions)
13881381
{
13891382
bytea *options;
13901383
bool isnull;
@@ -1406,8 +1399,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
14061399
case RELKIND_RELATION:
14071400
case RELKIND_TOASTVALUE:
14081401
case RELKIND_MATVIEW:
1409-
options = tableam_reloptions(tableam, classForm->relkind,
1410-
datum, common, false);
1402+
options = heap_reloptions(classForm->relkind, datum, false);
14111403
break;
14121404
case RELKIND_PARTITIONED_TABLE:
14131405
options = partitioned_table_reloptions(datum, false);
@@ -1703,7 +1695,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
17031695
* Given the result from parseRelOptions, allocate a struct that's of the
17041696
* specified base size plus any extra space that's needed for string variables.
17051697
*
1706-
* "base" should be sizeof(struct) of the reloptions struct (HeapRdOptions or
1698+
* "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
17071699
* equivalent).
17081700
*/
17091701
static void *
@@ -1840,95 +1832,59 @@ fillRelOptions(void *rdopts, Size basesize,
18401832

18411833

18421834
/*
1843-
* Option parser for anything that uses HeapRdOptions.
1835+
* Option parser for anything that uses StdRdOptions.
18441836
*/
1845-
static bytea *
1837+
bytea *
18461838
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
18471839
{
18481840
static const relopt_parse_elt tab[] = {
1849-
{"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRdOptions, fillfactor)},
1841+
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
18501842
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
1851-
offsetof(HeapRdOptions, common) +
1852-
offsetof(CommonRdOptions, autovacuum) +
1853-
offsetof(AutoVacOpts, enabled)},
1843+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
18541844
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
1855-
offsetof(HeapRdOptions, common) +
1856-
offsetof(CommonRdOptions, autovacuum) +
1857-
offsetof(AutoVacOpts, vacuum_threshold)},
1845+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
18581846
{"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
1859-
offsetof(HeapRdOptions, common) +
1860-
offsetof(CommonRdOptions, autovacuum) +
1861-
offsetof(AutoVacOpts, vacuum_ins_threshold)},
1847+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
18621848
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
1863-
offsetof(HeapRdOptions, common) +
1864-
offsetof(CommonRdOptions, autovacuum) +
1865-
offsetof(AutoVacOpts, analyze_threshold)},
1849+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
18661850
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
1867-
offsetof(HeapRdOptions, common) +
1868-
offsetof(CommonRdOptions, autovacuum) +
1869-
offsetof(AutoVacOpts, vacuum_cost_limit)},
1851+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
18701852
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
1871-
offsetof(HeapRdOptions, common) +
1872-
offsetof(CommonRdOptions, autovacuum) +
1873-
offsetof(AutoVacOpts, freeze_min_age)},
1853+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
18741854
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
1875-
offsetof(HeapRdOptions, common) +
1876-
offsetof(CommonRdOptions, autovacuum) +
1877-
offsetof(AutoVacOpts, freeze_max_age)},
1855+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
18781856
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
1879-
offsetof(HeapRdOptions, common) +
1880-
offsetof(CommonRdOptions, autovacuum) +
1881-
offsetof(AutoVacOpts, freeze_table_age)},
1857+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
18821858
{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
1883-
offsetof(HeapRdOptions, common) +
1884-
offsetof(CommonRdOptions, autovacuum) +
1885-
offsetof(AutoVacOpts, multixact_freeze_min_age)},
1859+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
18861860
{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
1887-
offsetof(HeapRdOptions, common) +
1888-
offsetof(CommonRdOptions, autovacuum) +
1889-
offsetof(AutoVacOpts, multixact_freeze_max_age)},
1861+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
18901862
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
1891-
offsetof(HeapRdOptions, common) +
1892-
offsetof(CommonRdOptions, autovacuum) +
1893-
offsetof(AutoVacOpts, multixact_freeze_table_age)},
1863+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
18941864
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
1895-
offsetof(HeapRdOptions, common) +
1896-
offsetof(CommonRdOptions, autovacuum) +
1897-
offsetof(AutoVacOpts, log_min_duration)},
1865+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
18981866
{"toast_tuple_target", RELOPT_TYPE_INT,
1899-
offsetof(HeapRdOptions, toast_tuple_target)},
1867+
offsetof(StdRdOptions, toast_tuple_target)},
19001868
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
1901-
offsetof(HeapRdOptions, common) +
1902-
offsetof(CommonRdOptions, autovacuum) +
1903-
offsetof(AutoVacOpts, vacuum_cost_delay)},
1869+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
19041870
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
1905-
offsetof(HeapRdOptions, common) +
1906-
offsetof(CommonRdOptions, autovacuum) +
1907-
offsetof(AutoVacOpts, vacuum_scale_factor)},
1871+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
19081872
{"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
1909-
offsetof(HeapRdOptions, common) +
1910-
offsetof(CommonRdOptions, autovacuum) +
1911-
offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
1873+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
19121874
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
1913-
offsetof(HeapRdOptions, common) +
1914-
offsetof(CommonRdOptions, autovacuum) +
1915-
offsetof(AutoVacOpts, analyze_scale_factor)},
1875+
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
19161876
{"user_catalog_table", RELOPT_TYPE_BOOL,
1917-
offsetof(HeapRdOptions, common) +
1918-
offsetof(CommonRdOptions, user_catalog_table)},
1877+
offsetof(StdRdOptions, user_catalog_table)},
19191878
{"parallel_workers", RELOPT_TYPE_INT,
1920-
offsetof(HeapRdOptions, common) +
1921-
offsetof(CommonRdOptions, parallel_workers)},
1879+
offsetof(StdRdOptions, parallel_workers)},
19221880
{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
1923-
offsetof(HeapRdOptions, common) +
1924-
offsetof(CommonRdOptions, vacuum_index_cleanup)},
1881+
offsetof(StdRdOptions, vacuum_index_cleanup)},
19251882
{"vacuum_truncate", RELOPT_TYPE_BOOL,
1926-
offsetof(HeapRdOptions, common) +
1927-
offsetof(CommonRdOptions, vacuum_truncate)}
1883+
offsetof(StdRdOptions, vacuum_truncate)}
19281884
};
19291885

19301886
return (bytea *) build_reloptions(reloptions, validate, kind,
1931-
sizeof(HeapRdOptions),
1887+
sizeof(StdRdOptions),
19321888
tab, lengthof(tab));
19331889
}
19341890

@@ -2056,65 +2012,30 @@ view_reloptions(Datum reloptions, bool validate)
20562012
tab, lengthof(tab));
20572013
}
20582014

2059-
/*
2060-
* Fill CommonRdOptions with the default values.
2061-
*/
2062-
void
2063-
fill_default_common_reloptions(CommonRdOptions *common)
2064-
{
2065-
common->autovacuum.enabled = true;
2066-
common->autovacuum.vacuum_threshold = -1;
2067-
common->autovacuum.vacuum_ins_threshold = -2;
2068-
common->autovacuum.analyze_threshold = -1;
2069-
common->autovacuum.vacuum_cost_limit = -1;
2070-
common->autovacuum.freeze_min_age = -1;
2071-
common->autovacuum.freeze_max_age = -1;
2072-
common->autovacuum.freeze_table_age = -1;
2073-
common->autovacuum.multixact_freeze_min_age = -1;
2074-
common->autovacuum.multixact_freeze_max_age = -1;
2075-
common->autovacuum.multixact_freeze_table_age = -1;
2076-
common->autovacuum.log_min_duration = -1;
2077-
common->autovacuum.vacuum_cost_delay = -1;
2078-
common->autovacuum.vacuum_scale_factor = -1;
2079-
common->autovacuum.vacuum_ins_scale_factor = -1;
2080-
common->autovacuum.analyze_scale_factor = -1;
2081-
common->parallel_workers = -1;
2082-
common->user_catalog_table = false;
2083-
common->vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
2084-
common->vacuum_truncate = true;
2085-
}
2086-
20872015
/*
20882016
* Parse options for heaps, views and toast tables.
20892017
*/
20902018
bytea *
2091-
heap_reloptions(char relkind, Datum reloptions,
2092-
CommonRdOptions *common, bool validate)
2019+
heap_reloptions(char relkind, Datum reloptions, bool validate)
20932020
{
2094-
HeapRdOptions *rdopts;
2021+
StdRdOptions *rdopts;
20952022

20962023
switch (relkind)
20972024
{
20982025
case RELKIND_TOASTVALUE:
2099-
rdopts = (HeapRdOptions *)
2026+
rdopts = (StdRdOptions *)
21002027
default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
21012028
if (rdopts != NULL)
21022029
{
21032030
/* adjust default-only parameters for TOAST relations */
21042031
rdopts->fillfactor = 100;
2105-
rdopts->common.autovacuum.analyze_threshold = -1;
2106-
rdopts->common.autovacuum.analyze_scale_factor = -1;
2032+
rdopts->autovacuum.analyze_threshold = -1;
2033+
rdopts->autovacuum.analyze_scale_factor = -1;
21072034
}
2108-
if (rdopts != NULL && common != NULL)
2109-
*common = rdopts->common;
21102035
return (bytea *) rdopts;
21112036
case RELKIND_RELATION:
21122037
case RELKIND_MATVIEW:
2113-
rdopts = (HeapRdOptions *)
2114-
default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
2115-
if (rdopts != NULL && common != NULL)
2116-
*common = rdopts->common;
2117-
return (bytea *) rdopts;
2038+
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
21182039
default:
21192040
/* other relkinds are not supported */
21202041
return NULL;

‎src/backend/access/heap/heapam.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/heapam.c
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,8 +2279,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22792279
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
22802280

22812281
needwal = RelationNeedsWAL(relation);
2282-
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
2283-
HEAP_DEFAULT_FILLFACTOR);
2282+
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
2283+
HEAP_DEFAULT_FILLFACTOR);
22842284

22852285
/* Toast and set header data in all the slots */
22862286
heaptuples = palloc(ntuples * sizeof(HeapTuple));

‎src/backend/access/heap/heapam_handler.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/heapam_handler.c
-13Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "access/heapam.h"
2424
#include "access/heaptoast.h"
2525
#include "access/multixact.h"
26-
#include "access/reloptions.h"
2726
#include "access/rewriteheap.h"
2827
#include "access/syncscan.h"
2928
#include "access/tableam.h"
@@ -2162,17 +2161,6 @@ heapam_relation_toast_am(Relation rel)
21622161
return rel->rd_rel->relam;
21632162
}
21642163

2165-
static bytea *
2166-
heapam_reloptions(char relkind, Datum reloptions,
2167-
CommonRdOptions *common, bool validate)
2168-
{
2169-
Assert(relkind == RELKIND_RELATION ||
2170-
relkind == RELKIND_TOASTVALUE ||
2171-
relkind == RELKIND_MATVIEW);
2172-
2173-
return heap_reloptions(relkind, reloptions, common, validate);
2174-
}
2175-
21762164

21772165
/* ------------------------------------------------------------------------
21782166
* Planner related callbacks for the heap AM
@@ -2734,7 +2722,6 @@ static const TableAmRoutine heapam_methods = {
27342722
.relation_needs_toast_table = heapam_relation_needs_toast_table,
27352723
.relation_toast_am = heapam_relation_toast_am,
27362724
.relation_fetch_toast_slice = heap_fetch_toast_slice,
2737-
.reloptions = heapam_reloptions,
27382725

27392726
.relation_estimate_size = heapam_estimate_rel_size,
27402727

‎src/backend/access/heap/heaptoast.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/heaptoast.c
+1-8Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,6 @@
3232
#include "access/toast_internals.h"
3333
#include "utils/fmgroids.h"
3434

35-
/*
36-
* HeapGetToastTupleTarget
37-
* Returns the heap relation's toast_tuple_target. Note multiple eval of argument!
38-
*/
39-
#define HeapGetToastTupleTarget(relation, defaulttarg) \
40-
((HeapRdOptions *) (relation)->rd_options ? \
41-
((HeapRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
4235

4336
/* ----------
4437
* heap_toast_delete -
@@ -181,7 +174,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
181174
hoff += BITMAPLEN(numAttrs);
182175
hoff = MAXALIGN(hoff);
183176
/* now convert to a limit on the tuple data size */
184-
maxDataLen = HeapGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
177+
maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
185178

186179
/*
187180
* Look for attributes with attstorage EXTENDED to compress. Also find

‎src/backend/access/heap/hio.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/hio.c
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
536536
len, MaxHeapTupleSize)));
537537

538538
/* Compute desired extra freespace due to fillfactor option */
539-
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
540-
HEAP_DEFAULT_FILLFACTOR);
539+
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
540+
HEAP_DEFAULT_FILLFACTOR);
541541

542542
/*
543543
* Since pages without tuples can still have line pointers, we consider

‎src/backend/access/heap/pruneheap.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/pruneheap.c
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
235235
* important than sometimes getting a wrong answer in what is after all
236236
* just a heuristic estimate.
237237
*/
238-
minfree = HeapGetTargetPageFreeSpace(relation,
239-
HEAP_DEFAULT_FILLFACTOR);
238+
minfree = RelationGetTargetPageFreeSpace(relation,
239+
HEAP_DEFAULT_FILLFACTOR);
240240
minfree = Max(minfree, BLCKSZ / 10);
241241

242242
if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)

‎src/backend/access/heap/rewriteheap.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/rewriteheap.c
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
641641
len, MaxHeapTupleSize)));
642642

643643
/* Compute desired extra freespace due to fillfactor option */
644-
saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel,
645-
HEAP_DEFAULT_FILLFACTOR);
644+
saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel,
645+
HEAP_DEFAULT_FILLFACTOR);
646646

647647
/* Now we can check to see if there's enough free space already. */
648648
page = (Page) state->rs_buffer;

‎src/backend/access/table/tableam.c

Copy file name to clipboardExpand all lines: src/backend/access/table/tableam.c
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ table_block_relation_estimate_size(Relation rel, int32 *attr_widths,
750750
* The other branch considers it implicitly by calculating density
751751
* from actual relpages/reltuples statistics.
752752
*/
753-
fillfactor = HeapGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
753+
fillfactor = RelationGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
754754

755755
tuple_width = get_rel_data_width(rel, attr_widths);
756756
tuple_width += overhead_bytes_per_tuple;

‎src/backend/access/table/tableamapi.c

Copy file name to clipboardExpand all lines: src/backend/access/table/tableamapi.c
-25Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,9 @@
1313

1414
#include "access/tableam.h"
1515
#include "access/xact.h"
16-
#include "catalog/pg_am.h"
1716
#include "commands/defrem.h"
1817
#include "miscadmin.h"
1918
#include "utils/guc_hooks.h"
20-
#include "utils/syscache.h"
2119

2220

2321
/*
@@ -100,29 +98,6 @@ GetTableAmRoutine(Oid amhandler)
10098
return routine;
10199
}
102100

103-
/*
104-
* GetTableAmRoutineByAmOid
105-
* Given the table access method oid get its TableAmRoutine struct, which
106-
* will be palloc'd in the caller's memory context.
107-
*/
108-
const TableAmRoutine *
109-
GetTableAmRoutineByAmOid(Oid amoid)
110-
{
111-
HeapTuple ht_am;
112-
Form_pg_am amrec;
113-
const TableAmRoutine *tableam = NULL;
114-
115-
ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
116-
if (!HeapTupleIsValid(ht_am))
117-
elog(ERROR, "cache lookup failed for access method %u",
118-
amoid);
119-
amrec = (Form_pg_am) GETSTRUCT(ht_am);
120-
121-
tableam = GetTableAmRoutine(amrec->amhandler);
122-
ReleaseSysCache(ht_am);
123-
return tableam;
124-
}
125-
126101
/* check_hook: validate new default_table_access_method */
127102
bool
128103
check_default_table_access_method(char **newval, void **extra, GucSource source)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.