-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
\c :TEST_DBNAME :ROLE_SUPERUSER;
CREATE TABLE ht_metrics_compressed(time timestamptz, device int, value float, tag text);
ALTER TABLE ht_metrics_compressed SET (autovacuum_enabled = false);
SELECT create_hypertable('ht_metrics_compressed','time',create_default_indexes:=false);
         create_hypertable          
------------------------------------
 (1,public,ht_metrics_compressed,t)

ALTER TABLE ht_metrics_compressed SET (timescaledb.compress, timescaledb.compress_segmentby='device', timescaledb.compress_orderby='time');
-- helper function: float -> pseudorandom float [0..1].
CREATE OR REPLACE FUNCTION mix(x float4) RETURNS float4 AS $$ SELECT ((hashfloat4(x) / (pow(2., 31) - 1) + 1) / 2)::float4 $$ LANGUAGE SQL;
INSERT INTO ht_metrics_compressed
SELECT
    '2020-01-08'::timestamptz + interval '1 second' * (x + 0.1 * mix(device + x * 10)),
    device,
    100 * mix(device) * sin(x / 3600)
        + 100 * mix(device + 1) * sin(x / (3600 * 24))
        + 100 * mix(device + 2) * sin(x / (3600 * 24 * 7))
        + mix(device + x * 10 + 1),
     format('this-is-a-long-tag-#%s', x % 29)
FROM generate_series(1, 3600 * 24 * 356, 100) x, generate_series(1,2) device;
-- compress it all
SELECT count(compress_chunk(c, true)) FROM show_chunks('ht_metrics_compressed') c;
 count 
-------
    52

select count(*) from ht_metrics_compressed;
 count  
--------
 615168

-- Helper function that returns the amount of memory currently allocated in a
-- given memory context.
create or replace function ts_debug_allocated_bytes(text = 'PortalContext') returns bigint
    as :MODULE_PATHNAME, 'ts_debug_allocated_bytes'
    language c strict volatile;
-- Check that decompression doesn't leak memory. Record memory usage after each
-- compressed chunk, and use linear regression to tell if memory usage grows.
with log as materialized (
        select rank() over (order by c) n, ts_debug_allocated_bytes() b, decompress_chunk(c, true)
        from show_chunks('ht_metrics_compressed') c order by c)
    , regression as (select regr_slope(b, n) slope, regr_intercept(b, n) intercept from log)
select * from log
    where (select slope / intercept::float > 0.01 from regression)
;
 n | b | decompress_chunk 
---+---+------------------

-- Same as above but for compression.
with log as materialized (
        select rank() over (order by c) n, ts_debug_allocated_bytes() b, compress_chunk(c, true)
        from show_chunks('ht_metrics_compressed') c order by c)
    , regression as (select regr_slope(b, n) slope, regr_intercept(b, n) intercept from log)
select * from log
    where (select slope / intercept::float > 0.01 from regression)
;
 n | b | compress_chunk 
---+---+----------------

-- Test recompression with small batches.
select count(decompress_chunk(c, true)) from show_chunks('ht_metrics_compressed') c;
 count 
-------
    52

alter table ht_metrics_compressed set (timescaledb.compress,
    timescaledb.compress_segmentby='time', timescaledb.compress_orderby='value');
select count(compress_chunk(c, true)) from show_chunks('ht_metrics_compressed') c;
 count 
-------
    52

update ht_metrics_compressed set value = 0 where value < 1 and value > -1;
with
to_recompress as (
  select tableoid::oid::regclass c, count(*) r
  from ht_metrics_compressed
  where value = 0
  group by 1
),
log as materialized (
        select rank() over (order by r) n,
            ts_debug_allocated_bytes(case
                when _timescaledb_functions.recompress_chunk_segmentwise(c)::text != ''
                then 'PortalContext' else '' end) b
        from show_chunks('ht_metrics_compressed') c
        join to_recompress using (c)
        order by r),
regression as (select regr_slope(b, n) slope, regr_intercept(b, n) intercept from log)
select * from log
    where (select slope / intercept::float > 0.01 from regression)
;
 n | b 
---+---

