--
-- Testing memory usage of columnar tables.
--
CREATE SCHEMA columnar_memory;
SET search_path TO 'columnar_memory';
SET columnar.stripe_row_limit TO 50000;
SET columnar.compression TO 'pglz';
CREATE TABLE t (a int, tag text, memusage bigint) USING columnar;
-- measure memory before doing writes
SELECT TopMemoryContext as top_pre,
	   WriteStateContext write_pre
FROM columnar_test_helpers.columnar_store_memory_stats() \gset
BEGIN;
SET LOCAL client_min_messages TO DEBUG1;
-- measure memory just before flushing 1st stripe
INSERT INTO t
 SELECT i, 'first batch',
        -- sample memusage instead of recording everyr row for speed
        CASE WHEN i % 100 = 0 THEN columnar_test_helpers.top_memory_context_usage() ELSE 0 END
 FROM generate_series(1, 49999) i;
SELECT TopMemoryContext as top0,
       TopTransactionContext xact0,
	   WriteStateContext write0
FROM columnar_test_helpers.columnar_store_memory_stats() \gset
-- flush 1st stripe, and measure memory just before flushing 2nd stripe
INSERT INTO t
 SELECT i, 'second batch', 0 /* no need to record memusage per row */
 FROM generate_series(1, 50000) i;
DEBUG:  Flushing Stripe of size 50000
SELECT TopMemoryContext as top1,
       TopTransactionContext xact1,
	   WriteStateContext write1
FROM columnar_test_helpers.columnar_store_memory_stats() \gset
-- flush 2nd stripe, and measure memory just before flushing 3rd stripe
INSERT INTO t
 SELECT i, 'third batch', 0 /* no need to record memusage per row */
 FROM generate_series(1, 50000) i;
DEBUG:  Flushing Stripe of size 50000
SELECT TopMemoryContext as top2,
       TopTransactionContext xact2,
	   WriteStateContext write2
FROM columnar_test_helpers.columnar_store_memory_stats() \gset
-- insert a large batch
INSERT INTO t
 SELECT i, 'large batch',
        -- sample memusage instead of recording everyr row for speed
        CASE WHEN i % 100 = 0 THEN columnar_test_helpers.top_memory_context_usage() ELSE 0 END
 FROM generate_series(1, 100000) i;
DEBUG:  Flushing Stripe of size 50000
DEBUG:  Flushing Stripe of size 50000
COMMIT;
DEBUG:  Flushing Stripe of size 49999
-- measure memory after doing writes
SELECT TopMemoryContext as top_post,
	   WriteStateContext write_post
FROM columnar_test_helpers.columnar_store_memory_stats() \gset
\x
SELECT (1.0 * :top2/:top1 BETWEEN 0.99 AND 1.01) AS top_growth_ok,
	   (1.0 * :xact1/:xact0 BETWEEN 0.99 AND 1.01) AND
	   (1.0 * :xact2/:xact0 BETWEEN 0.99 AND 1.01) AS xact_growth_ok,
	   (1.0 * :write1/:write0 BETWEEN 0.99 AND 1.01) AND
	   (1.0 * :write2/:write0 BETWEEN 0.99 AND 1.01) AS write_growth_ok,
	   :write_pre = 0 AND :write_post = 0 AS write_clear_outside_xact;
-[ RECORD 1 ]------------+--
top_growth_ok            | t
xact_growth_ok           | t
write_growth_ok          | t
write_clear_outside_xact | t

-- inserting another bunch of rows should not grow top memory context
INSERT INTO t
 SELECT i, 'last batch', 0 /* no need to record memusage per row */
 FROM generate_series(1, 50000) i;
SELECT CASE WHEN 1.0 * TopMemoryContext / :top_post BETWEEN 0.98 AND 1.03 THEN 1 ELSE 1.0 * TopMemoryContext / :top_post END AS top_growth
FROM columnar_test_helpers.columnar_store_memory_stats();
-[ RECORD 1 ]-
top_growth | 1

-- before this change, max mem usage while executing inserts was 28MB and
-- with this change it's less than 9MB.
SELECT
 (SELECT max(memusage) < 9 * 1024 * 1024 FROM t WHERE tag='large batch') AS large_batch_ok,
 (SELECT max(memusage) < 9 * 1024 * 1024 FROM t WHERE tag='first batch') AS first_batch_ok;
-[ RECORD 1 ]--+--
large_batch_ok | t
first_batch_ok | t

\x
SELECT count(*) FROM t;
 count
---------------------------------------------------------------------
 299999
(1 row)

SET client_min_messages TO WARNING;
DROP SCHEMA columnar_memory CASCADE;
