Patch: Write Amplification Reduction Method (WARM)

Started by Pavan Deolaseeover 9 years ago263 messageshackers
Jump to latest
#1Pavan Deolasee
pavan.deolasee@gmail.com

Hi All,

As previously discussed [1]/messages/by-id/CABOikdMop5Rb_RnS2xF dAXMZGSqcJ-P-BY2ruMd%2BbuUkJ4iDPw@mail.gmail.com, WARM is a technique to reduce write
amplification when an indexed column of a table is updated. HOT fails to
handle such updates and ends up inserting a new index entry in all indexes
of the table, irrespective of whether the index key has changed or not for
a specific index. The problem was highlighted by Uber's blog post [2]https://eng.uber.com/mysql-migration/, but
it was a well known problem and affects many workloads.

Simon brought up the idea originally within 2ndQuadrant and I developed it
further with inputs from my other colleagues and community members.

There were two important problems identified during the earlier discussion.
This patch addresses those issues in a simplified way. There are other
complex ideas to solve those issues, but as the results demonstrate, even a
simple approach will go far way in improving performance characteristics of
many workloads, yet keeping the code complexity to relatively low.

Two problems have so far been identified with the WARM design.

“*Duplicate Scan*” - Claudio Freire brought up a design flaw which may lead
an IndexScan to return same tuple twice or more, thus impacting the
correctness of the solution.

“*Root Pointer Search*” - Andres raised the point that it could be
inefficient to find the root line pointer for a tuple in the HOT or WARM
chain since it may require us to scan through the entire page.

The Duplicate Scan problem has correctness issues so could block WARM
completely. We propose the following solution:

We discussed a few ideas to address the "Duplicate Scan" problem. For
example, we can teach Index AMs to discard any duplicate (key, CTID) insert
requests. Or we could guarantee uniqueness by either only allowing updates
in one lexical order. While the former is a more complete solution to avoid
duplicate entries, searching through large number of keys for non-unique
indexes could be a drag on performance. The latter approach may not be
sufficient for many workloads. Also tracking increment/decrement for many
indexes will be non-trivial.

There is another problem with allowing many index entries pointing to the
same WARM chain. It will be non-trivial to know how many index entries are
currently pointing to the WARM chain and index/heap vacuum will throw up
more challenges.

Instead, what I would like to propose and the patch currently implements is
to restrict WARM update to once per chain. So the first non-HOT update to a
tuple or a HOT chain can be a WARM update. The chain can further be HOT
updated any number of times. But it can no further be WARM updated. This
might look too restrictive, but it can still bring down the number of
regular updates by almost 50%. Further, if we devise a strategy to convert
a WARM chain back to HOT chain, it can again be WARM updated. (This part is
currently not implemented). A good side effect of this simple strategy is
that we know there can maximum two index entries pointing to any given WARM
chain.

The other problem Andres brought up can be solved by storing the root line
pointer offset in the t_ctid field of the last tuple in the update chain.
Barring some aborted update case, usually it's the last tuple in the update
chain that will be updated, hence it seems logical and sufficient if we can
find the root line pointer while accessing that tuple. Note that the t_ctid
field in the latest tuple is usually useless and is made to point to
itself. Instead, I propose to use a bit from t_infomask2 to identify the
LATEST tuple in the chain and use OffsetNumber field in t_ctid to store
root line pointer offset. For rare aborted update case, we can scan the
heap page and find root line pointer is a hard way.

Index Recheck
--------------------

As the original proposal explains, while doing index scan we must recheck
if the heap tuple matches the index keys. This has to be done only when the
chain is marked as a WARM chain. Currently we do that by setting the last
free bit in t_infomask2 to HEAP_WARM_TUPLE. The bit is set on the tuple
that gets WARM updated and all subsequent tuples in the chain. But the
information can subsequently be copied to root line pointer when it's
converted to a LP_REDIRECT line pointer.

Since each index AM has its own view of the index tuples, each AM must
implement its "amrecheck" routine. This routine to used to confirm that a
tuple returned from a WARM chain indeed satisfies the index keys. If the
index AM does not implement "amrecheck" routine, WARM update is disabled on
a table which uses such an index. The patch currently implements
"amrecheck" routines for hash and btree indexes. Hence a table with GiST or
GIN index will not honour WARM updates.

Results
----------

We used a customised pgbench workload to test the feature. In particular,
the pgbench_accounts table was widened to include many more columns and
indexes. We also added an index on "abalance" field which gets updated in
every transaction. This replicates a workload where there are many indexes
on a table and an update changes just one index key.

CREATE TABLE pgbench_accounts (
aid bigint,
bid bigint,
abalance bigint,
filler1 text DEFAULT md5(random()::text),
filler2 text DEFAULT md5(random()::text),
filler3 text DEFAULT md5(random()::text),
filler4 text DEFAULT md5(random()::text),
filler5 text DEFAULT md5(random()::text),
filler6 text DEFAULT md5(random()::text),
filler7 text DEFAULT md5(random()::text),
filler8 text DEFAULT md5(random()::text),
filler9 text DEFAULT md5(random()::text),
filler10 text DEFAULT md5(random()::text),
filler11 text DEFAULT md5(random()::text),
filler12 text DEFAULT md5(random()::text)
);

CREATE UNIQUE INDEX pgb_a_aid ON pgbench_accounts(aid);
CREATE INDEX pgb_a_abalance ON pgbench_accounts(abalance);
CREATE INDEX pgb_a_filler1 ON pgbench_accounts(filler1);
CREATE INDEX pgb_a_filler2 ON pgbench_accounts(filler2);
CREATE INDEX pgb_a_filler3 ON pgbench_accounts(filler3);
CREATE INDEX pgb_a_filler4 ON pgbench_accounts(filler4);

These tests are run on c3.4xlarge AWS instances, with 30GB of RAM, 16 vCPU
and 2x160GB SSD. Data and WAL were mounted on a separate SSD.

The scale factor of 700 was chosen to ensure that the database does not fit
in memory and implications of additional write activity is evident.

The actual transactional tests would just update the pgbench_accounts table:

\set aid random(1, 100000 * :scale)
\set delta random(-5000, 5000)
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
END;

The tests were run for a long duration of 16 hrs each with 16 pgbench
clients to ensure that effects of the patch are captured correctly.

Headline TPS numbers:

Master:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 65552986
latency average: 14.059 ms
*tps = 1138.072117 (including connections establishing)*
tps = 1138.072156 (excluding connections establishing)

WARM:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 116168454
latency average: 7.933 ms
*tps = 2016.812924 (including connections establishing)*
tps = 2016.812997 (excluding connections establishing)

So WARM shows about *77% increase* in TPS. Note that these are fairly long
running tests with nearly 100M transactions and the tests show a steady
performance.

We also measured the amount of WAL generated by Master and WARM per
transaction. While master generated 34967 bytes of WAL per transaction,
WARM generated 18421 bytes of WAL per transaction.

We plotted a moving average of TPS against time and also against the
percentage of WARM updates. Clearly higher the number of WARM updates,
higher is the TPS. A graph showing percentage of WARM updates is also
plotted and it shows a steady convergence to 50% mark with time.

We repeated the same tests starting with 90% heap fill factor such that
there are many more WARM updates. Since with 90% fill factor and in
combination with HOT pruning, most initial updates will be WARM updates and
that impacts TPS positively. WARM shows nearly *150% increase *in TPS for
that workload.

Master:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 78134617
latency average: 11.795 ms
*tps = 1356.503629 (including connections establishing)*
tps = 1356.503679 (excluding connections establishing)

WARM:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 196782770
latency average: 4.683 ms
*tps = 3416.364822 (including connections establishing)*
tps = 3416.364949 (excluding connections establishing)

In this case, master produced ~49000 bytes of WAL per transaction where as
WARM produced ~14000 bytes of WAL per transaction.
I concede that we haven't yet done many tests to measure overhead of the
technique, especially in circumstances where WARM may not be very useful.
What I have in mind are couple of tests:

- With many indexes and a good percentage of them requiring update
- A mix of read-write workload

Any other ideas to do that are welcome.

Concerns:
--------------

The additional heap recheck may have negative impact on performance. We
tried to measure this by running a SELECT only workload for 1hr after 16hr
test finished. But the TPS did not show any negative impact. The impact
could be more if the update changes many index keys, something these tests
don't test.

The patch also changes things such that index tuples are always returned
because they may be needed for recheck. It's not clear if this is something
to be worried about, but we could try to further fine tune this change.

There seems to be some modularity violations since index AM needs to access
some of the executor stuff to form index datums. If that's a real concern,
we can look at improving amrecheck signature so that it gets index datums
from the caller.

The patch uses remaining 2 free bits in t_infomask, thus closing any
further improvements which may need to use heap tuple flags. During the
patch development we tried several other approaches such as reusing
3-higher order bits in OffsetNumber since the current max BLCKSZ limits the
MaxOffsetNumber to 8192 and that can be represented in 13 bits. We finally
reverted that change to keep the patch simple. But there is clearly a way
to free up more bits if required.

Converting WARM chains back to HOT chains (VACUUM ?)
---------------------------------------------------------------------------------

The current implementation of WARM allows only one WARM update per chain.
This
simplifies the design and addresses certain issues around duplicate scans.
But
this also implies that the benefit of WARM will be no more than 50%, which
is
still significant, but if we could return WARM chains back to normal
status, we
could do far more WARM updates.

A distinct property of a WARM chain is that at least one index has more than
one live index entries pointing to the root of the chain. In other words,
if we
can remove duplicate entry from every index or conclusively prove that there
are no duplicate index entries for the root line pointer, the chain can
again
be marked as HOT.

Here is one idea, but more thoughts/suggestions are most welcome.

A WARM chain has two parts, separated by the tuple that caused WARM update.
All
tuples in each part has matching index keys, but certain index keys may not
match between these two parts. Lets say we mark heap tuples in each part
with a
special Red-Blue flag. The same flag is replicated in the index tuples. For
example, when new rows are inserted in a table, they are marked with Blue
flag
and the index entries associated with those rows are also marked with Blue
flag. When a row is WARM updated, the new version is marked with Red flag
and
the new index entry created by the update is also marked with Red flag.

Heap chain: lp [1]/messages/by-id/CABOikdMop5Rb_RnS2xF dAXMZGSqcJ-P-BY2ruMd%2BbuUkJ4iDPw@mail.gmail.com [2]https://eng.uber.com/mysql-migration/ [3] [4]
[aaaa, 1111]B -> [aaaa, 1111]B -> [bbbb, 1111]R -> [bbbb, 1111]R

Index1: (aaaa)B points to 1 (satisfies only tuples marked with B)
(bbbb)R points to 1 (satisfies only tuples marked with R)

Index2: (1111)B points to 1 (satisfies both B and R tuples)

It's clear that for indexes with Red and Blue pointers, a heap tuple with
Blue
flag will be reachable from Blue pointer and that with Red flag will be
reachable from Red pointer. But for indexes which did not create a new
entry,
both Blue and Red tuples will be reachable from Blue pointer (there is no
Red
pointer in such indexes). So, as a side note, matching Red and Blue flags is
not enough from index scan perspective.

During first heap scan of VACUUM, we look for tuples with HEAP_WARM_TUPLE
set.
If all live tuples in the chain are either marked with Blue flag or Red flag
(but no mix of Red and Blue), then the chain is a candidate for HOT
conversion.
We remember the root line pointer and Red-Blue flag of the WARM chain in a
separate array.

If we have a Red WARM chain, then our goal is to remove Blue pointers and
vice
versa. But there is a catch. For Index2 above, there is only Blue pointer
and that must not be removed. IOW we should remove Blue pointer iff a Red
pointer exists. Since index vacuum may visit Red and Blue pointers in any
order, I think we will need another index pass to remove dead
index pointers. So in the first index pass we check which WARM candidates
have
2 index pointers. In the second pass, we remove the dead pointer and reset
Red
flag is the surviving index pointer is Red.

During the second heap scan, we fix WARM chain by clearing HEAP_WARM_TUPLE
flag
and also reset Red flag to Blue.

There are some more problems around aborted vacuums. For example, if vacuum
aborts after changing Red index flag to Blue but before removing the other
Blue
pointer, we will end up with two Blue pointers to a Red WARM chain. But
since
the HEAP_WARM_TUPLE flag on the heap tuple is still set, further WARM
updates
to the chain will be blocked. I guess we will need some special handling for
case with multiple Blue pointers. We can either leave these WARM chains
alone
and let them die with a subsequent non-WARM update or must apply
heap-recheck
logic during index vacuum to find the dead pointer. Given that vacuum-aborts
are not common, I am inclined to leave this case unhandled. We must still
check
for presence of multiple Blue pointers and ensure that we don't accidently
remove any of the Blue pointers and not clear WARM chains either.

Of course, the idea requires one bit each in index and heap tuple. There is
already a free bit in index tuple and I've some ideas to free up additional
bits in heap tuple (as mentioned above).

Further Work
------------------

1.The patch currently disables WARM updates on system relations. This is
mostly to keep the patch simple, but in theory we should be able to support
WARM updates on system tables too. It's not clear if its worth the
complexity though.

2. AFAICS both CREATE INDEX and CIC should just work fine, but need
validation for that.

3. GiST and GIN indexes are currently disabled for WARM. I don't see a
fundamental reason why they won't work once we implement "amrecheck"
method, but I don't understand those indexes well enough.

4. There are some modularity invasions I am worried about (is amrecheck
signature ok?). There are also couple of hacks around to get access to
index tuples during scans and I hope to get them correct during review
process, with some feedback.

5. Patch does not implement machinery to convert WARM chains into HOT
chains. I would give it go unless someone finds a problem with the idea or
has a better idea.

Thanks,
Pavan

[1]: /messages/by-id/CABOikdMop5Rb_RnS2xF dAXMZGSqcJ-P-BY2ruMd%2BbuUkJ4iDPw@mail.gmail.com
dAXMZGSqcJ-P-BY2ruMd%2BbuUkJ4iDPw@mail.gmail.com
[2]: https://eng.uber.com/mysql-migration/

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

Master-vs-WARM-TPS.pngimage/png; name=Master-vs-WARM-TPS.pngDownload
Percentage-WARM-with-time.pngimage/png; name=Percentage-WARM-with-time.pngDownload
WARM-vs-TPS.pngimage/png; name=WARM-vs-TPS.pngDownload
0001_track_root_lp_v2.patchapplication/octet-stream; name=0001_track_root_lp_v2.patchDownload+224-45
0002_warm_updates_v2.patchapplication/octet-stream; name=0002_warm_updates_v2.patchDownload+1257-157
#2Claudio Freire
klaussfreire@gmail.com
In reply to: Pavan Deolasee (#1)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Aug 31, 2016 at 1:45 PM, Pavan Deolasee <pavan.deolasee@gmail.com>
wrote:

We discussed a few ideas to address the "Duplicate Scan" problem. For
example, we can teach Index AMs to discard any duplicate (key, CTID) insert
requests. Or we could guarantee uniqueness by either only allowing updates
in one lexical order. While the former is a more complete solution to avoid
duplicate entries, searching through large number of keys for non-unique
indexes could be a drag on performance. The latter approach may not be
sufficient for many workloads. Also tracking increment/decrement for many
indexes will be non-trivial.

There is another problem with allowing many index entries pointing to the
same WARM chain. It will be non-trivial to know how many index entries are
currently pointing to the WARM chain and index/heap vacuum will throw up
more challenges.

Instead, what I would like to propose and the patch currently implements
is to restrict WARM update to once per chain. So the first non-HOT update
to a tuple or a HOT chain can be a WARM update. The chain can further be
HOT updated any number of times. But it can no further be WARM updated.
This might look too restrictive, but it can still bring down the number of
regular updates by almost 50%. Further, if we devise a strategy to convert
a WARM chain back to HOT chain, it can again be WARM updated. (This part is
currently not implemented). A good side effect of this simple strategy is
that we know there can maximum two index entries pointing to any given WARM
chain.

We should probably think about coordinating with my btree patch.

From the description above, the strategy is quite readily "upgradable" to
one in which the indexam discards duplicate (key,ctid) pairs and that would
remove the limitation of only one WARM update... right?

#3Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Claudio Freire (#2)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Aug 31, 2016 at 10:38 PM, Claudio Freire <klaussfreire@gmail.com>
wrote:

On Wed, Aug 31, 2016 at 1:45 PM, Pavan Deolasee <pavan.deolasee@gmail.com>
wrote:

We discussed a few ideas to address the "Duplicate Scan" problem. For
example, we can teach Index AMs to discard any duplicate (key, CTID) insert
requests. Or we could guarantee uniqueness by either only allowing updates
in one lexical order. While the former is a more complete solution to avoid
duplicate entries, searching through large number of keys for non-unique
indexes could be a drag on performance. The latter approach may not be
sufficient for many workloads. Also tracking increment/decrement for many
indexes will be non-trivial.

There is another problem with allowing many index entries pointing to the
same WARM chain. It will be non-trivial to know how many index entries are
currently pointing to the WARM chain and index/heap vacuum will throw up
more challenges.

Instead, what I would like to propose and the patch currently implements
is to restrict WARM update to once per chain. So the first non-HOT update
to a tuple or a HOT chain can be a WARM update. The chain can further be
HOT updated any number of times. But it can no further be WARM updated.
This might look too restrictive, but it can still bring down the number of
regular updates by almost 50%. Further, if we devise a strategy to convert
a WARM chain back to HOT chain, it can again be WARM updated. (This part is
currently not implemented). A good side effect of this simple strategy is
that we know there can maximum two index entries pointing to any given WARM
chain.

We should probably think about coordinating with my btree patch.

From the description above, the strategy is quite readily "upgradable" to
one in which the indexam discards duplicate (key,ctid) pairs and that would
remove the limitation of only one WARM update... right?

Yes, we should be able to add further optimisations on lines you're working
on, but what I like about the current approach is that a) it reduces
complexity of the patch and b) having thought about cleaning up WARM
chains, limiting number of index entries per root chain to a small number
will simplify that aspect too.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#4Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#1)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Aug 31, 2016 at 10:15 PM, Pavan Deolasee <pavan.deolasee@gmail.com>
wrote:

Hi All,

As previously discussed [1], WARM is a technique to reduce write
amplification when an indexed column of a table is updated. HOT fails to
handle such updates and ends up inserting a new index entry in all indexes
of the table, irrespective of whether the index key has changed or not for
a specific index. The problem was highlighted by Uber's blog post [2], but
it was a well known problem and affects many workloads.

I realised that the patches were bit-rotten because of 8e1e3f958fb. Rebased
patches on the current master are attached. I also took this opportunity to
correct some white space errors and improve formatting of the README.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

0001_track_root_lp_v3.patchapplication/octet-stream; name=0001_track_root_lp_v3.patchDownload+223-45
0002_warm_updates_v3.patchapplication/octet-stream; name=0002_warm_updates_v3.patchDownload+1258-154
#5Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#1)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Aug 31, 2016 at 10:15:33PM +0530, Pavan Deolasee wrote:

Instead, what I would like to propose and the patch currently implements is to
restrict WARM update to once per chain. So the first non-HOT update to a tuple
or a HOT chain can be a WARM update. The chain can further be HOT updated any
number of times. But it can no further be WARM updated. This might look too
restrictive, but it can still bring down the number of regular updates by
almost 50%. Further, if we devise a strategy to convert a WARM chain back to
HOT chain, it can again be WARM updated. (This part is currently not
implemented). A good side effect of this simple strategy is that we know there
can maximum two index entries pointing to any given WARM chain.

I like the simplified approach, as long as it doesn't block further
improvements.

Headline TPS numbers:

Master:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 65552986
latency average: 14.059 ms
tps = 1138.072117 (including connections establishing)
tps = 1138.072156 (excluding connections establishing)

WARM:

transaction type: update.sql
scaling factor: 700
query mode: simple
number of clients: 16
number of threads: 8
duration: 57600 s
number of transactions actually processed: 116168454
latency average: 7.933 ms
tps = 2016.812924 (including connections establishing)
tps = 2016.812997 (excluding connections establishing)

These are very impressive results.

Converting WARM chains back to HOT chains (VACUUM ?)
---------------------------------------------------------------------------------

The current implementation of WARM allows only one WARM update per chain. This
simplifies the design and addresses certain issues around duplicate scans. But
this also implies that the benefit of WARM will be no more than 50%, which is
still significant, but if we could return WARM chains back to normal status, we
could do far more WARM updates.

A distinct property of a WARM chain is that at least one index has more than
one live index entries pointing to the root of the chain. In other words, if we
can remove duplicate entry from every index or conclusively prove that there
are no duplicate index entries for the root line pointer, the chain can again
be marked as HOT.

I had not thought of how to convert from WARM to HOT yet.

Here is one idea, but more thoughts/suggestions are most welcome.�

A WARM chain has two parts, separated by the tuple that caused WARM update. All
tuples in each part has matching index keys, but certain index keys may not
match between these two parts. Lets say we mark heap tuples in each part with a
special Red-Blue flag. The same flag is replicated in the index tuples. For
example, when new rows are inserted in a table, they are marked with Blue flag
and the index entries associated with those rows are also marked with Blue
flag. When a row is WARM updated, the new version is marked with Red flag and
the new index entry created by the update is also marked with Red flag.

Heap chain: lp �[1] [2] [3] [4]
� [aaaa, 1111]B -> [aaaa, 1111]B -> [bbbb, 1111]R -> [bbbb, 1111]R

Index1: (aaaa)B points to 1 (satisfies only tuples marked with B)
(bbbb)R points to 1 (satisfies only tuples marked with R)

Index2: (1111)B points to 1 (satisfies both B and R tuples)

It's clear that for indexes with Red and Blue pointers, a heap tuple with Blue
flag will be reachable from Blue pointer and that with Red flag will be
reachable from Red pointer. But for indexes which did not create a new entry,
both Blue and Red tuples will be reachable from Blue pointer (there is no Red
pointer in such indexes). So, as a side note, matching Red and Blue flags is
not enough from index scan perspective.

During first heap scan of VACUUM, we look for tuples with HEAP_WARM_TUPLE set.
If all live tuples in the chain are either marked with Blue flag or Red flag
(but no mix of Red and Blue), then the chain is a candidate for HOT conversion.

Uh, if the chain is all blue, then there is are WARM entries so it
already a HOT chain, so there is nothing to do, right?

We remember the root line pointer and Red-Blue flag of the WARM chain in a
separate array.

If we have a Red WARM chain, then our goal is to remove Blue pointers and vice
versa. But there is a catch. For Index2 above, there is only Blue pointer
and that must not be removed. IOW we should remove Blue pointer iff a Red
pointer exists. Since index vacuum may visit Red and Blue pointers in any
order, I think we will need another index pass to remove dead
index pointers. So in the first index pass we check which WARM candidates have
2 index pointers. In the second pass, we remove the dead pointer and reset Red
flag is the surviving index pointer is Red.

Why not just remember the tid of chains converted from WARM to HOT, then
use "amrecheck" on an index entry matching that tid to see if the index
matches one of the entries in the chain. (It will match all of them or
none of them, because they are all red.) I don't see a point in
coloring the index entries as reds as later you would have to convert to
blue in the WARM-to-HOT conversion, and a vacuum crash could lead to
inconsistencies. Consider that you can just call "amrecheck" on the few
chains that have converted from WARM to HOT. I believe this is more
crash-safe too. However, if you have converted WARM to HOT in the heap,
but crash durin the index entry removal, you could potentially have
duplicates in the index later, which is bad.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ As you are, so once was I. As I am, so you will be. +
+                     Ancient Roman grave inscription +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Bruce Momjian
bruce@momjian.us
In reply to: Bruce Momjian (#5)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Aug 31, 2016 at 04:03:29PM -0400, Bruce Momjian wrote:

Why not just remember the tid of chains converted from WARM to HOT, then
use "amrecheck" on an index entry matching that tid to see if the index
matches one of the entries in the chain. (It will match all of them or
none of them, because they are all red.) I don't see a point in
coloring the index entries as reds as later you would have to convert to
blue in the WARM-to-HOT conversion, and a vacuum crash could lead to
inconsistencies. Consider that you can just call "amrecheck" on the few
chains that have converted from WARM to HOT. I believe this is more
crash-safe too. However, if you have converted WARM to HOT in the heap,
but crash during the index entry removal, you could potentially have
duplicates in the index later, which is bad.

I think Pavan had the "crash durin the index entry removal" fixed via:

During the second heap scan, we fix WARM chain by clearing HEAP_WARM_TUPLE flag
and also reset Red flag to Blue.

so the marking from WARM to HOT only happens after the index has been cleaned.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ As you are, so once was I. As I am, so you will be. +
+                     Ancient Roman grave inscription +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#5)
Re: Patch: Write Amplification Reduction Method (WARM)

On Thu, Sep 1, 2016 at 1:33 AM, Bruce Momjian <bruce@momjian.us> wrote:

On Wed, Aug 31, 2016 at 10:15:33PM +0530, Pavan Deolasee wrote:

Instead, what I would like to propose and the patch currently implements

is to

restrict WARM update to once per chain. So the first non-HOT update to a

tuple

or a HOT chain can be a WARM update. The chain can further be HOT

updated any

number of times. But it can no further be WARM updated. This might look

too

restrictive, but it can still bring down the number of regular updates by
almost 50%. Further, if we devise a strategy to convert a WARM chain

back to

HOT chain, it can again be WARM updated. (This part is currently not
implemented). A good side effect of this simple strategy is that we know

there

can maximum two index entries pointing to any given WARM chain.

I like the simplified approach, as long as it doesn't block further
improvements.

Yes, the proposed approach is simple yet does not stop us from improving
things further. Moreover it has shown good performance characteristics and
I believe it's a good first step.

Master:
tps = 1138.072117 (including connections establishing)

WARM:
tps = 2016.812924 (including connections establishing)

These are very impressive results.

Thanks. What's also interesting and something that headline numbers don't
show is that WARM TPS is as much as 3 times of master TPS when the
percentage of WARM updates is very high. Notice the spike in TPS in the
comparison graph.

Results with non-default heap fill factor are even better. In both cases,
the improvement in TPS stays constant over long periods.

During first heap scan of VACUUM, we look for tuples with

HEAP_WARM_TUPLE set.

If all live tuples in the chain are either marked with Blue flag or Red

flag

(but no mix of Red and Blue), then the chain is a candidate for HOT

conversion.

Uh, if the chain is all blue, then there is are WARM entries so it
already a HOT chain, so there is nothing to do, right?

For aborted WARM updates, the heap chain may be all blue, but there may
still be a red index pointer which must be cleared before we allow further
WARM updates to the chain.

We remember the root line pointer and Red-Blue flag of the WARM chain in

a

separate array.

If we have a Red WARM chain, then our goal is to remove Blue pointers

and vice

versa. But there is a catch. For Index2 above, there is only Blue pointer
and that must not be removed. IOW we should remove Blue pointer iff a Red
pointer exists. Since index vacuum may visit Red and Blue pointers in any
order, I think we will need another index pass to remove dead
index pointers. So in the first index pass we check which WARM

candidates have

2 index pointers. In the second pass, we remove the dead pointer and

reset Red

flag is the surviving index pointer is Red.

Why not just remember the tid of chains converted from WARM to HOT, then
use "amrecheck" on an index entry matching that tid to see if the index
matches one of the entries in the chain.

That will require random access to heap during index vacuum phase,
something I would like to avoid. But we can have that as a fall back
solution for handling aborted vacuums.

(It will match all of them or
none of them, because they are all red.) I don't see a point in
coloring the index entries as reds as later you would have to convert to
blue in the WARM-to-HOT conversion, and a vacuum crash could lead to
inconsistencies.

Yes, that's a concern since the conversion of red to blue will also need to
WAL logged to ensure that a crash doesn't leave us in inconsistent state. I
still think that this will be an overall improvement as compared to
allowing one WARM update per chain.

Consider that you can just call "amrecheck" on the few
chains that have converted from WARM to HOT. I believe this is more
crash-safe too. However, if you have converted WARM to HOT in the heap,
but crash durin the index entry removal, you could potentially have
duplicates in the index later, which is bad.

As you probably already noted, we clear heap flags only after all indexes
are cleared of duplicate entries and hence a crash in between should not
cause any correctness issue. As long as heap tuples are marked as warm,
amrecheck will ensure that only valid tuples are returned to the caller.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#8Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#7)
Re: Patch: Write Amplification Reduction Method (WARM)

On Thu, Sep 1, 2016 at 02:37:40PM +0530, Pavan Deolasee wrote:

I like the simplified approach, as long as it doesn't block further
improvements.

Yes, the proposed approach is simple yet does not stop us from improving things
further. Moreover it has shown good performance characteristics and I believe
it's a good first step.

Agreed. This is BIG. Do you think it can be done for PG 10?

Thanks. What's also interesting and something that headline numbers don't show
is that WARM TPS is as much as 3 times of master TPS when the percentage of
WARM updates is very high. Notice the spike in TPS in the comparison graph.

Results with non-default heap fill factor are even better. In both cases, the
improvement in TPS stays constant over long periods.�

Yes, I expect the benefits of this to show up in better long-term
performance.

During first heap scan of VACUUM, we look for tuples with HEAP_WARM_TUPLE

set.

If all live tuples in the chain are either marked with Blue flag or Red

flag

(but no mix of Red and Blue), then the chain is a candidate for HOT

conversion.

Uh, if the chain is all blue, then there is are WARM entries so it
already a HOT chain, so there is nothing to do, right?

For aborted WARM updates, the heap chain may be all blue, but there may still
be a red index pointer which must be cleared before we allow further WARM
updates to the chain.

Ah, understood now. Thanks.

Why not just remember the tid of chains converted from WARM to HOT, then
use "amrecheck" on an index entry matching that tid to see if the index
matches one of the entries in the chain.�

That will require random access to heap during index vacuum phase, something I
would like to avoid. But we can have that as a fall back solution for handling
aborted vacuums.�

Yes, that is true. So the challenge is figuring how which of the index
entries pointing to the same tid is valid, and coloring helps with that?

(It will match all of them or
none of them, because they are all red.)� I don't see a point in
coloring the index entries as reds as later you would have to convert to
blue in the WARM-to-HOT conversion, and a vacuum crash could lead to
inconsistencies.�

Yes, that's a concern since the conversion of red to blue will also need to WAL
logged to ensure that a crash doesn't leave us in inconsistent state. I still
think that this will be an overall improvement as compared to allowing one WARM
update per chain.

OK. I will think some more on this to see if I can come with another
approach.

�

Consider that you can just call "amrecheck" on the few
chains that have converted from WARM to HOT.� I believe this is more
crash-safe too.� However, if you have converted WARM to HOT in the heap,
but crash durin the index entry removal, you could potentially have
duplicates in the index later, which is bad.

As you probably already noted, we clear heap flags only after all indexes are
cleared of duplicate entries and hence a crash in between should not cause any
correctness issue. As long as heap tuples are marked as warm, amrecheck will
ensure that only valid tuples are returned to the caller.

OK, got it.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ As you are, so once was I. As I am, so you will be. +
+                     Ancient Roman grave inscription +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#8)
Re: Patch: Write Amplification Reduction Method (WARM)

On Thu, Sep 1, 2016 at 9:44 PM, Bruce Momjian <bruce@momjian.us> wrote:

On Thu, Sep 1, 2016 at 02:37:40PM +0530, Pavan Deolasee wrote:

I like the simplified approach, as long as it doesn't block further
improvements.

Yes, the proposed approach is simple yet does not stop us from improving

things

further. Moreover it has shown good performance characteristics and I

believe

it's a good first step.

Agreed. This is BIG. Do you think it can be done for PG 10?

I definitely think so. The patches as submitted are fully functional and
sufficient. Of course, there are XXX and TODOs that I hope to sort out
during the review process. There are also further tests needed to ensure
that the feature does not cause significant regression in the worst cases.
Again something I'm willing to do once I get some feedback on the broader
design and test cases. What I am looking at this stage is to know if I've
missed something important in terms of design or if there is some show
stopper that I overlooked.

Latest patches rebased with current master are attached. I also added a few
more comments to the code. I forgot to give a brief about the patches, so
including that as well.

0001_track_root_lp_v4.patch: This patch uses a free t_infomask2 bit to
track latest tuple in an update chain. The t_ctid.ip_posid is used to track
the root line pointer of the update chain. We do this only in the latest
tuple in the chain because most often that tuple will be updated and we
need to quickly find the root only during update.

0002_warm_updates_v4.patch: This patch implements the core of WARM logic.
During WARM update, we only insert new entries in the indexes whose key has
changed. But instead of indexing the real TID of the new tuple, we index
the root line pointer and then use additional recheck logic to ensure only
correct tuples are returned from such potentially broken HOT chains. Each
index AM must implement a amrecheck method to support WARM. The patch
currently implements this for hash and btree indexes.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

0001_track_root_lp_v4.patchapplication/octet-stream; name=0001_track_root_lp_v4.patchDownload+243-46
0002_warm_updates_v4.patchapplication/octet-stream; name=0002_warm_updates_v4.patchDownload+1298-155
#10Michael Paquier
michael@paquier.xyz
In reply to: Pavan Deolasee (#9)
Re: Patch: Write Amplification Reduction Method (WARM)

On Mon, Sep 5, 2016 at 1:53 PM, Pavan Deolasee <pavan.deolasee@gmail.com> wrote:

0001_track_root_lp_v4.patch: This patch uses a free t_infomask2 bit to track
latest tuple in an update chain. The t_ctid.ip_posid is used to track the
root line pointer of the update chain. We do this only in the latest tuple
in the chain because most often that tuple will be updated and we need to
quickly find the root only during update.

0002_warm_updates_v4.patch: This patch implements the core of WARM logic.
During WARM update, we only insert new entries in the indexes whose key has
changed. But instead of indexing the real TID of the new tuple, we index the
root line pointer and then use additional recheck logic to ensure only
correct tuples are returned from such potentially broken HOT chains. Each
index AM must implement a amrecheck method to support WARM. The patch
currently implements this for hash and btree indexes.

Moved to next CF, I was surprised to see that it is not *that* large:
43 files changed, 1539 insertions(+), 199 deletions(-)
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Pavan Deolasee (#9)
Re: Patch: Write Amplification Reduction Method (WARM)

On 09/05/2016 06:53 AM, Pavan Deolasee wrote:

On Thu, Sep 1, 2016 at 9:44 PM, Bruce Momjian <bruce@momjian.us
<mailto:bruce@momjian.us>> wrote:

On Thu, Sep 1, 2016 at 02:37:40PM +0530, Pavan Deolasee wrote:

I like the simplified approach, as long as it doesn't block further
improvements.

Yes, the proposed approach is simple yet does not stop us from improving things
further. Moreover it has shown good performance characteristics and I believe
it's a good first step.

Agreed. This is BIG. Do you think it can be done for PG 10?

I definitely think so. The patches as submitted are fully functional and
sufficient. Of course, there are XXX and TODOs that I hope to sort out
during the review process. There are also further tests needed to ensure
that the feature does not cause significant regression in the worst
cases. Again something I'm willing to do once I get some feedback on the
broader design and test cases. What I am looking at this stage is to
know if I've missed something important in terms of design or if there
is some show stopper that I overlooked.

Latest patches rebased with current master are attached. I also added a
few more comments to the code. I forgot to give a brief about the
patches, so including that as well.

0001_track_root_lp_v4.patch: This patch uses a free t_infomask2 bit to
track latest tuple in an update chain. The t_ctid.ip_posid is used to
track the root line pointer of the update chain. We do this only in the
latest tuple in the chain because most often that tuple will be updated
and we need to quickly find the root only during update.

0002_warm_updates_v4.patch: This patch implements the core of WARM
logic. During WARM update, we only insert new entries in the indexes
whose key has changed. But instead of indexing the real TID of the new
tuple, we index the root line pointer and then use additional recheck
logic to ensure only correct tuples are returned from such potentially
broken HOT chains. Each index AM must implement a amrecheck method to
support WARM. The patch currently implements this for hash and btree
indexes.

Hi,

I've been looking at the patch over the past few days, running a bunch
of benchmarks etc. I can confirm the significant speedup, often by more
than 75% (depending on number of indexes, whether the data set fits into
RAM, etc.). Similarly for the amount of WAL generated, although that's a
bit more difficult to evaluate due to full_page_writes.

I'm not going to send detailed results, as that probably does not make
much sense at this stage of the development - I can repeat the tests
once the open questions get resolved.

There's a lot of useful and important feedback in the thread(s) so far,
particularly the descriptions of various failure cases. I think it'd be
very useful to collect those examples and turn them into regression
tests - that's something the patch should include anyway.

I don't really have much comments regarding the code, but during the
testing I noticed a bit strange behavior when updating statistics.
Consider a table like this:

create table t (a int, b int, c int) with (fillfactor = 10);
insert into t select i, i from generate_series(1,1000) s(i);
create index on t(a);
create index on t(b);

and update:

update t set a = a+1, b=b+1;

which has to update all indexes on the table, but:

select n_tup_upd, n_tup_hot_upd from pg_stat_user_tables

n_tup_upd | n_tup_hot_upd
-----------+---------------
1000 | 1000

So it's still counted as "WARM" - does it make sense? I mean, we're
creating a WARM chain on the page, yet we have to add pointers into all
indexes (so not really saving anything). Doesn't this waste the one WARM
update per HOT chain without actually getting anything in return?

The way this is piggy-backed on the current HOT statistics seems a bit
strange for another reason, although WARM is a relaxed version of HOT.
Until now, HOT was "all or nothing" - we've either added index entries
to all indexes or none of them. So the n_tup_hot_upd was fine.

But WARM changes that - it allows adding index entries only to a subset
of indexes, which means the "per row" n_tup_hot_upd counter is not
sufficient. When you have a table with 10 indexes, and the counter
increases by 1, does that mean the update added index tuple to 1 index
or 9 of them?

So I think we'll need two counters to track WARM - number of index
tuples we've added, and number of index tuples we've skipped. So
something like blks_hit and blks_read. I'm not sure whether we should
replace the n_tup_hot_upd entirely, or keep it for backwards
compatibility (and to track perfectly HOT updates).

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Tomas Vondra (#11)
Re: Patch: Write Amplification Reduction Method (WARM)

On Wed, Oct 5, 2016 at 1:43 PM, Tomas Vondra <tomas.vondra@2ndquadrant.com>
wrote:

I've been looking at the patch over the past few days, running a bunch of
benchmarks etc.

Thanks for doing that.

I can confirm the significant speedup, often by more than 75% (depending
on number of indexes, whether the data set fits into RAM, etc.). Similarly
for the amount of WAL generated, although that's a bit more difficult to
evaluate due to full_page_writes.

I'm not going to send detailed results, as that probably does not make
much sense at this stage of the development - I can repeat the tests once
the open questions get resolved.

Sure. Anything that stands out? Any regression that you see? I'm not sure
if your benchmarks exercise the paths which might show overheads without
any tangible benefits. For example, I wonder if a test with many indexes
where most of them get updated and then querying the table via those
updated indexes could be one such test case.

There's a lot of useful and important feedback in the thread(s) so far,
particularly the descriptions of various failure cases. I think it'd be
very useful to collect those examples and turn them into regression tests -
that's something the patch should include anyway.

Sure. I added only a handful test cases which I knew regression isn't
covering. But I'll write more of them. One good thing is that the code gets
heavily exercised even during regression. I caught and fixed multiple bugs
running regression. I'm not saying that's enough, but it certainly gives
some confidence.

and update:

update t set a = a+1, b=b+1;

which has to update all indexes on the table, but:

select n_tup_upd, n_tup_hot_upd from pg_stat_user_tables

n_tup_upd | n_tup_hot_upd
-----------+---------------
1000 | 1000

So it's still counted as "WARM" - does it make sense?

No, it does not. The code currently just marks any update as a WARM update
if the table supports it and there is enough free space in the page. And
yes, you're right. It's worth fixing that because of one-WARM update per
chain limitation. Will fix.

The way this is piggy-backed on the current HOT statistics seems a bit
strange for another reason,

Agree. We could add a similar n_tup_warm_upd counter.

But WARM changes that - it allows adding index entries only to a subset of
indexes, which means the "per row" n_tup_hot_upd counter is not sufficient.
When you have a table with 10 indexes, and the counter increases by 1, does
that mean the update added index tuple to 1 index or 9 of them?

How about having counters similar to n_tup_ins/n_tup_del for indexes as
well? Today it does not make sense because every index gets the same number
of inserts, but WARM will change that.

For example, we could have idx_tup_insert and idx_tup_delete that shows up
in pg_stat_user_indexes. I don't know if idx_tup_delete adds any value, but
one can then look at idx_tup_insert for various indexes to get a sense
which indexes receives more inserts than others. The indexes which receive
more inserts are the ones being frequently updated as compared to other
indexes.

This also relates to vacuuming strategies. Today HOT updates do not count
for triggering vacuum (or to be more precise, HOT pruned tuples are
discounted while counting dead tuples). WARM tuples get the same treatment
as far as pruning is concerned, but since they cause fresh index inserts, I
wonder if we need some mechanism to cleanup the dead line pointers and dead
index entries. This will become more important if we do something to
convert WARM chains into HOT chains, something that only VACUUM can do in
the design I've proposed so far.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#13Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Pavan Deolasee (#12)
Re: Patch: Write Amplification Reduction Method (WARM)

On 10/06/2016 07:36 AM, Pavan Deolasee wrote:

On Wed, Oct 5, 2016 at 1:43 PM, Tomas Vondra
<tomas.vondra@2ndquadrant.com <mailto:tomas.vondra@2ndquadrant.com>> wrote:

...

I can confirm the significant speedup, often by more than 75%
(depending on number of indexes, whether the data set fits into RAM,
etc.). Similarly for the amount of WAL generated, although that's a
bit more difficult to evaluate due to full_page_writes.

I'm not going to send detailed results, as that probably does not
make much sense at this stage of the development - I can repeat the
tests once the open questions get resolved.

Sure. Anything that stands out? Any regression that you see? I'm not
sure if your benchmarks exercise the paths which might show overheads
without any tangible benefits. For example, I wonder if a test with many
indexes where most of them get updated and then querying the table via
those updated indexes could be one such test case.

No, nothing that would stand out. Let me explain what benchmark(s) I've
done. I've made some minor mistakes when running the benchmarks, so I
plan to rerun them and post the results after that. So let's take the
data with a grain of salt.

My goal was to compare current non-HOT behavior (updating all indexes)
with the WARM (updating only indexes on modified columns), and I've
taken two approaches:

1) fixed number of indexes, update variable number of columns

Create a table with 8 secondary indexes and then run a bunch of
benchmarks updating increasing number of columns. So the first run did

UPDATE t SET c1 = c1+1 WHERE id = :id;

while the second did

UPDATE t SET c1 = c1+1, c2 = c2+1 WHERE id = :id;

and so on, up to updating all the columns in the last run. I've used
multiple scripts to update all the columns / indexes uniformly
(essentially using multiple "-f" flags with pgbench). The runs were
fairly long (2h, enough to get stable behavior).

For a small data set (fits into RAM), the results look like this:

master patched diff
1 5994 8490 +42%
2 4347 7903 +81%
3 4340 7400 +70%
4 4324 6929 +60%
5 4256 6495 +52%
6 4253 5059 +19%
7 4235 4534 +7%
8 4194 4237 +1%

and the amount of WAL generated (after correction for tps difference)
looks like this (numbers are MBs)

master patched diff
1 27257 18508 -32%
2 21753 14599 -33%
3 21912 15864 -28%
4 22021 17135 -22%
5 21819 18258 -16%
6 21929 20659 -6%
7 21994 22234 +1%
8 21851 23267 +6%

So this is quite significant difference. I'm pretty sure the minor WAL
increase for the last two runs is due to full page writes (which also
affects the preceding runs, making the WAL reduction smaller than the
tps increase).

I do have results for larger data sets (>RAM), the results are very
similar although the speedup seems a bit smaller. But I need to rerun those.

2) single-row update, adding indexes between runs

This is kinda the opposite of the previous approach, i.e. transactions
always update a single column (multiple scripts to update the columns
uniformly), but there are new indexes added between runs. The results
(for a large data set, exceeding RAM) look like this:

master patched diff
0 954 1404 +47%
1 701 1045 +49%
2 484 816 +70%
3 346 683 +97%
4 248 608 +145%
5 190 525 +176%
6 152 397 +161%
7 123 315 +156%
8 123 270 +119%

So this looks really interesting.

There's a lot of useful and important feedback in the thread(s) so
far, particularly the descriptions of various failure cases. I think
it'd be very useful to collect those examples and turn them into
regression tests - that's something the patch should include anyway.

Sure. I added only a handful test cases which I knew regression isn't
covering. But I'll write more of them. One good thing is that the code
gets heavily exercised even during regression. I caught and fixed
multiple bugs running regression. I'm not saying that's enough, but it
certainly gives some confidence.

I don't see any changes to src/test in the patch, so I'm not sure what
you mean when you say you added a handful of test cases?

and update:

update t set a = a+1, b=b+1;

which has to update all indexes on the table, but:

select n_tup_upd, n_tup_hot_upd from pg_stat_user_tables

n_tup_upd | n_tup_hot_upd
-----------+---------------
1000 | 1000

So it's still counted as "WARM" - does it make sense?

No, it does not. The code currently just marks any update as a WARM
update if the table supports it and there is enough free space in the
page. And yes, you're right. It's worth fixing that because of one-WARM
update per chain limitation. Will fix.

Hmmm, so this makes monitoring of %WARM during benchmarks less reliable
than I hoped for :-(

The way this is piggy-backed on the current HOT statistics seems a
bit strange for another reason,

Agree. We could add a similar n_tup_warm_upd counter.

Yes, although HOT is a special case of WARM. But it probably makes sense
to differentiate them, I guess.

But WARM changes that - it allows adding index entries only to a
subset of indexes, which means the "per row" n_tup_hot_upd counter
is not sufficient. When you have a table with 10 indexes, and the
counter increases by 1, does that mean the update added index tuple
to 1 index or 9 of them?

How about having counters similar to n_tup_ins/n_tup_del for indexes
as well? Today it does not make sense because every index gets the
same number of inserts, but WARM will change that.

For example, we could have idx_tup_insert and idx_tup_delete that shows
up in pg_stat_user_indexes. I don't know if idx_tup_delete adds any
value, but one can then look at idx_tup_insert for various indexes to
get a sense which indexes receives more inserts than others. The indexes
which receive more inserts are the ones being frequently updated as
compared to other indexes.

Hmmm, I'm not sure that'll work. I mean, those metrics would be useful
(although I can't think of a use case for idx_tup_delete), but I'm not
sure it's a enough to measure WARM. We need to compute

index_tuples_inserted / index_tuples_total

where (index_tuples_total - index_tuples_inserted) is the number of
index tuples we've been able to skip thanks to WARM. So we'd also need
to track the number of index tuples that we skipped for the index, and
I'm not sure that's a good idea.

Also, we really don't care about inserted tuples - what matters for WARM
are updates, so idx_tup_insert is either useless (because it also
includes non-UPDATE entries) or the naming is misleading.

This also relates to vacuuming strategies. Today HOT updates do not
count for triggering vacuum (or to be more precise, HOT pruned tuples
are discounted while counting dead tuples). WARM tuples get the same
treatment as far as pruning is concerned, but since they cause fresh
index inserts, I wonder if we need some mechanism to cleanup the dead
line pointers and dead index entries. This will become more important if
we do something to convert WARM chains into HOT chains, something that
only VACUUM can do in the design I've proposed so far.

True.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Tomas Vondra (#13)
Re: Patch: Write Amplification Reduction Method (WARM)

Thanks for the patch. This shows a very good performance improvement.

I started reviewing the patch, during this process and I ran the regression
test on the WARM patch. I observed a failure in create_index test.
This may be a bug in code or expected that needs to be corrected.

Regards,
Hari Babu
Fujitsu Australia

#15Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Haribabu Kommi (#14)
Re: Patch: Write Amplification Reduction Method (WARM)

On Tue, Nov 8, 2016 at 9:13 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Thanks for the patch. This shows a very good performance improvement.

Thank you. Can you please share the benchmark you ran, results and
observations?

I started reviewing the patch, during this process and I ran the regression
test on the WARM patch. I observed a failure in create_index test.
This may be a bug in code or expected that needs to be corrected.

Can you please share the diff? I ran regression after applying patch on the
current master and did not find any change? Does it happen consistently?

I'm also attaching fresh set of patches. The first patch hasn't changed at
all (though I changed the name to v5 to keep it consistent with the other
patch). The second patch has the following changes:

1. WARM updates are now tracked separately. We still don't count number of
index inserts separately as suggested by Tomas.
2. We don't do a WARM update if all columns referenced by all indexes have
changed. Ideally, we should check if all indexes will require an update and
avoid WARM. So there is still some room for improvement here
3. I added a very minimal regression test case. But really, it just
contains one test case which I specifically wanted to test.

So not a whole lot of changes since the last version. I'm still waiting for
some serious review of the design/code before I spend a lot more time on
the patch. I hope the patch receives some attention in this CF.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

0001_track_root_lp_v5.patchapplication/octet-stream; name=0001_track_root_lp_v5.patchDownload+243-46
0002_warm_updates_v5.patchapplication/octet-stream; name=0002_warm_updates_v5.patchDownload+1419-158
#16Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Pavan Deolasee (#15)
Re: Patch: Write Amplification Reduction Method (WARM)

On Sat, Nov 12, 2016 at 10:12 PM, Pavan Deolasee <pavan.deolasee@gmail.com>
wrote:

On Tue, Nov 8, 2016 at 9:13 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Thanks for the patch. This shows a very good performance improvement.

Thank you. Can you please share the benchmark you ran, results and
observations?

I just ran a performance test on my laptop with minimal configuration, it
didn't show much
improvement, currently I don't have access to a big machine to test the
performance.

I started reviewing the patch, during this process and I ran the regression

test on the WARM patch. I observed a failure in create_index test.
This may be a bug in code or expected that needs to be corrected.

Can you please share the diff? I ran regression after applying patch on
the current master and did not find any change? Does it happen consistently?

Yes, it is happening consistently. I ran the make installcheck. Attached
the regression.diffs file with the failed test.
I applied the previous warm patch on this commit -
e3e66d8a9813d22c2aa027d8f373a96d4d4c1b15

Regards,
Hari Babu
Fujitsu Australia

Attachments:

regression.diffsapplication/octet-stream; name=regression.diffsDownload+5-5
#17Haribabu Kommi
kommi.haribabu@gmail.com
In reply to: Haribabu Kommi (#16)
Re: Patch: Write Amplification Reduction Method (WARM)

On Tue, Nov 15, 2016 at 5:58 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

On Sat, Nov 12, 2016 at 10:12 PM, Pavan Deolasee <pavan.deolasee@gmail.com

wrote:

On Tue, Nov 8, 2016 at 9:13 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Thanks for the patch. This shows a very good performance improvement.

Thank you. Can you please share the benchmark you ran, results and
observations?

I just ran a performance test on my laptop with minimal configuration, it
didn't show much
improvement, currently I don't have access to a big machine to test the
performance.

I started reviewing the patch, during this process and I ran the

regression
test on the WARM patch. I observed a failure in create_index test.
This may be a bug in code or expected that needs to be corrected.

Can you please share the diff? I ran regression after applying patch on
the current master and did not find any change? Does it happen consistently?

Yes, it is happening consistently. I ran the make installcheck. Attached
the regression.diffs file with the failed test.
I applied the previous warm patch on this commit
- e3e66d8a9813d22c2aa027d8f373a96d4d4c1b15

Are you able to reproduce the issue?

Currently the patch is moved to next CF with "needs review" state.

Regards,
Hari Babu
Fujitsu Australia

#18Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Haribabu Kommi (#17)
Re: Patch: Write Amplification Reduction Method (WARM)

On Fri, Dec 2, 2016 at 8:34 AM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

On Tue, Nov 15, 2016 at 5:58 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:

Yes, it is happening consistently. I ran the make installcheck. Attached
the regression.diffs file with the failed test.
I applied the previous warm patch on this commit
- e3e66d8a9813d22c2aa027d8f373a96d4d4c1b15

Are you able to reproduce the issue?

Apologies for the delay. I could reproduce this on a different environment.
It was a case of uninitialised variable and hence the inconsistent results.

I've updated the patches after fixing the issue. Multiple rounds of
regression passes for me without any issue. Please let me know if it works
for you.

Currently the patch is moved to next CF with "needs review" state.

Thanks,
Pavan

--
Pavan Deolasee http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

0001_track_root_lp_v6.patchapplication/octet-stream; name=0001_track_root_lp_v6.patchDownload+243-46
0002_warm_updates_v6.patchapplication/octet-stream; name=0002_warm_updates_v6.patchDownload+1430-161
#19Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#18)
Re: Patch: Write Amplification Reduction Method (WARM)

I noticed that this patch changes HeapSatisfiesHOTAndKeyUpdate() by
adding one more set of attributes to check, and one more output boolean
flag. My patch to add indirect indexes also modifies that routine to
add the same set of things. I think after committing both these
patches, the API is going to be fairly ridiculous. I propose to use a
different approach.

With your WARM and my indirect indexes, plus the additions for for-key
locks, plus identity columns, there is no longer a real expectation that
we can exit early from the function. In your patch, as well as mine,
there is a semblance of optimization that tries to avoid computing the
updated_attrs output bitmapset if the pointer is not passed in, but it's
effectively pointless because the only interesting use case is from
ExecUpdate() which always activates the feature. Can we just agree to
drop that?

If we do drop that, then the function can become much simpler: compare
all columns in new vs. old, return output bitmapset of changed columns.
Then "satisfies_hot" and all the other boolean output flags can be
computed simply in the caller by doing bms_overlap().

Thoughts?

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#19)
Re: Patch: Write Amplification Reduction Method (WARM)

Alvaro Herrera wrote:

With your WARM and my indirect indexes, plus the additions for for-key
locks, plus identity columns, there is no longer a real expectation that
we can exit early from the function. In your patch, as well as mine,
there is a semblance of optimization that tries to avoid computing the
updated_attrs output bitmapset if the pointer is not passed in, but it's
effectively pointless because the only interesting use case is from
ExecUpdate() which always activates the feature. Can we just agree to
drop that?

I think the only case that gets worse is the path that does
simple_heap_update, which is used for DDL. I would be very surprised if
a change there is noticeable, when compared to the rest of the stuff
that goes on for DDL commands.

Now, after saying that, I think that a table with a very large number of
columns is going to be affected by this. But we don't really need to
compute the output bits for every single column -- we only care about
those that are covered by some index. So we should pass an input
bitmapset comprising all such columns, and the output bitmapset only
considers those columns, and ignores columns not indexed. My patch for
indirect indexes already does something similar (though it passes a
bitmapset of columns indexed by indirect indexes only, so it needs a
tweak there.)

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Jaime Casanova
jcasanov@systemguards.com.ec
In reply to: Pavan Deolasee (#18)
#22Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Jaime Casanova (#21)
#23Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#22)
#24Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#20)
#25Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Jaime Casanova (#21)
#26Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#25)
#27Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#26)
#28Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#27)
#29Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#28)
#30Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#29)
#31Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#30)
#32Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#30)
#33Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#32)
#34Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#32)
#35Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#34)
#36Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#31)
#37Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#32)
#38Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#36)
#39Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#32)
#40Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#39)
#41Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#40)
#42Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#41)
#43Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#42)
#44Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#43)
#45Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#44)
#46Andres Freund
andres@anarazel.de
In reply to: Alvaro Herrera (#44)
#47Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Andres Freund (#46)
#48Andres Freund
andres@anarazel.de
In reply to: Alvaro Herrera (#47)
#49Tom Lane
tgl@sss.pgh.pa.us
In reply to: Andres Freund (#46)
#50Stephen Frost
sfrost@snowman.net
In reply to: Tom Lane (#49)
#51Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#50)
#52Andres Freund
andres@anarazel.de
In reply to: Tom Lane (#49)
#53Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#51)
#54Michael Paquier
michael@paquier.xyz
In reply to: Alvaro Herrera (#53)
#55Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#40)
#56Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#53)
#57Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#56)
#58Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#57)
#59Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Tom Lane (#58)
#60Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#45)
#61Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#60)
#62Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#60)
#63Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Tom Lane (#49)
#64Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#39)
#65Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#55)
#66Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#64)
#67Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#66)
#68Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#67)
#69Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#68)
#70Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#69)
#71Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#70)
#72Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#71)
#73Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#72)
#74Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#65)
#75Robert Haas
robertmhaas@gmail.com
In reply to: Bruce Momjian (#64)
#76Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#67)
#77Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#75)
#78Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#72)
#79Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#78)
#80Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#79)
#81Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#80)
#82Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#81)
#83Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#82)
#84Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#76)
#85Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#83)
#86Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#85)
#87Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#85)
#88Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#87)
#89Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#88)
#90Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#89)
#91Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#89)
#92Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#91)
#93Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#92)
#94Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#93)
#95Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#94)
#96Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#91)
#97Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#91)
#98Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#96)
#99Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#98)
#100Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#98)
#101Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#99)
#102Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#101)
In reply to: Alvaro Herrera (#101)
#104Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#100)
#105Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#104)
#106Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#105)
#107Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Peter Geoghegan (#103)
#108Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#106)
#109Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#108)
#110Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#100)
#111Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#96)
#112Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#111)
In reply to: Pavan Deolasee (#107)
#114Amit Kapila
amit.kapila16@gmail.com
In reply to: Alvaro Herrera (#95)
#115Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#94)
#116Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#115)
#117Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#116)
#118Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#97)
#119Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#117)
#120Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Amit Kapila (#115)
#121Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#119)
#122Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#121)
#123Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#119)
#124Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#122)
#125Robert Haas
robertmhaas@gmail.com
In reply to: Alvaro Herrera (#124)
#126Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#116)
#127Andres Freund
andres@anarazel.de
In reply to: Pavan Deolasee (#123)
#128Bruce Momjian
bruce@momjian.us
In reply to: Robert Haas (#119)
#129Robert Haas
robertmhaas@gmail.com
In reply to: Bruce Momjian (#128)
In reply to: Robert Haas (#129)
#131Robert Haas
robertmhaas@gmail.com
In reply to: Peter Geoghegan (#130)
#132Bruce Momjian
bruce@momjian.us
In reply to: Robert Haas (#129)
#133Bruce Momjian
bruce@momjian.us
In reply to: Robert Haas (#131)
#134Petr Jelinek
petr@2ndquadrant.com
In reply to: Robert Haas (#131)
#135Petr Jelinek
petr@2ndquadrant.com
In reply to: Bruce Momjian (#133)
#136Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#132)
#137Robert Haas
robertmhaas@gmail.com
In reply to: Petr Jelinek (#134)
#138Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#129)
#139Bruce Momjian
bruce@momjian.us
In reply to: Petr Jelinek (#135)
#140Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#136)
#141Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#138)
#142Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#141)
#143Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#142)
#144Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Bruce Momjian (#143)
#145Bruce Momjian
bruce@momjian.us
In reply to: Alvaro Herrera (#144)
#146Mithun Cy
mithun.cy@enterprisedb.com
In reply to: Robert Haas (#125)
#147Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Mithun Cy (#146)
#148Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#147)
#149Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Mithun Cy (#146)
#150Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#118)
#151Mithun Cy
mithun.cy@enterprisedb.com
In reply to: Pavan Deolasee (#149)
#152Bruce Momjian
bruce@momjian.us
In reply to: Bruce Momjian (#145)
#153Mithun Cy
mithun.cy@enterprisedb.com
In reply to: Pavan Deolasee (#147)
#154Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Mithun Cy (#151)
#155Mithun Cy
mithun.cy@enterprisedb.com
In reply to: Pavan Deolasee (#154)
#156Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#150)
#157Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#154)
#158Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#150)
#159Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#156)
#160Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#157)
#161Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#160)
#162Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#158)
#163Mithun Cy
mithun.cy@enterprisedb.com
In reply to: Pavan Deolasee (#154)
#164Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Mithun Cy (#163)
#165Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#140)
#166Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#162)
#167Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#166)
#168Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#167)
#169Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#159)
#170Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#169)
#171Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#170)
In reply to: Amit Kapila (#171)
#173Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Peter Geoghegan (#172)
#174Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#173)
#175Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#170)
#176Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Pavan Deolasee (#175)
#177Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#171)
#178Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#176)
#179Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#165)
#180Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#178)
#181Bruce Momjian
bruce@momjian.us
In reply to: Robert Haas (#179)
#182Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#179)
#183Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#181)
#184Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#183)
#185Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#177)
#186Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#178)
#187Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#175)
#188Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#175)
#189Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#187)
#190Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#182)
#191David Steele
david@pgmasters.net
In reply to: Robert Haas (#190)
#192Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#187)
#193Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#188)
#194Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#189)
#195Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#190)
#196Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#175)
#197Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Alvaro Herrera (#196)
#198Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#194)
#199Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#198)
#200Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#192)
#201Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#199)
#202Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#201)
#203Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#202)
#204Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Pavan Deolasee (#197)
#205Dilip Kumar
dilipbalaut@gmail.com
In reply to: Pavan Deolasee (#197)
#206Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#202)
#207Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Dilip Kumar (#205)
#208Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#206)
#209Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#208)
#210Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#206)
#211Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#210)
#212Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#209)
#213Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#212)
#214Petr Jelinek
petr@2ndquadrant.com
In reply to: Pavan Deolasee (#211)
#215Andres Freund
andres@anarazel.de
In reply to: Pavan Deolasee (#207)
#216Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#215)
#217Bruce Momjian
bruce@momjian.us
In reply to: Bruce Momjian (#145)
#218Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#208)
#219Simon Riggs
simon@2ndQuadrant.com
In reply to: Robert Haas (#216)
#220Robert Haas
robertmhaas@gmail.com
In reply to: Simon Riggs (#219)
#221Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#220)
#222Robert Haas
robertmhaas@gmail.com
In reply to: Petr Jelinek (#214)
#223Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#221)
#224Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#223)
#225Jeff Janes
jeff.janes@gmail.com
In reply to: Pavan Deolasee (#207)
#226Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Jeff Janes (#225)
#227Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#224)
#228Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Dilip Kumar (#218)
#229Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Bruce Momjian (#217)
#230Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#222)
#231Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#213)
#232Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#231)
#233Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#232)
#234Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#233)
#235Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#234)
#236Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#234)
In reply to: Andres Freund (#235)
#238Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#236)
#239Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#238)
#240Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Peter Geoghegan (#237)
#241Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Andres Freund (#235)
#242Bruce Momjian
bruce@momjian.us
In reply to: Pavan Deolasee (#241)
#243Andres Freund
andres@anarazel.de
In reply to: Pavan Deolasee (#241)
#244Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#241)
#245Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#244)
#246Bruce Momjian
bruce@momjian.us
In reply to: Andres Freund (#243)
#247Amit Kapila
amit.kapila16@gmail.com
In reply to: Pavan Deolasee (#245)
#248Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Amit Kapila (#247)
#249Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#245)
In reply to: Robert Haas (#249)
#251Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Peter Geoghegan (#250)
#252Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#249)
#253Jaime Casanova
jcasanov@systemguards.com.ec
In reply to: Pavan Deolasee (#236)
#254Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Jaime Casanova (#253)
#255Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#254)
#256Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Robert Haas (#255)
In reply to: Pavan Deolasee (#256)
#258Pavan Deolasee
pavan.deolasee@gmail.com
In reply to: Peter Geoghegan (#257)
#259Robert Haas
robertmhaas@gmail.com
In reply to: Pavan Deolasee (#258)
In reply to: Pavan Deolasee (#258)
#261Claudio Freire
klaussfreire@gmail.com
In reply to: Peter Geoghegan (#260)
In reply to: Claudio Freire (#261)
#263Daniel Gustafsson
daniel@yesql.se
In reply to: Robert Haas (#259)