Skip to content

Commit 3473922

Browse files
committed
Review comments, eviction and minor simplification
1 parent 17cf3d1 commit 3473922

17 files changed

Lines changed: 260 additions & 128 deletions

src/chunk.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <storage/lmgr.h>
4141
#include <storage/lockdefs.h>
4242
#include <tcop/tcopprot.h>
43+
#include <ts_stats/ts_stats_record.h>
4344
#include <utils/acl.h>
4445
#include <utils/array.h>
4546
#include <utils/builtins.h>
@@ -4074,6 +4075,9 @@ ts_chunk_drop(const Chunk *chunk, DropBehavior behavior, int32 log_level)
40744075

40754076
/* Drop the table */
40764077
performDeletion(&objaddr, behavior, 0);
4078+
4079+
/* Evict the chunk stats from the shared memory */
4080+
ts_stats_chunk_evict(chunk->table_id);
40774081
}
40784082

40794083
static void

src/guc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,8 +1489,7 @@ _guc_init(void)
14891489
"Per-database statistics cache capacity, "
14901490
"in chunks. 0 disables the feature.",
14911491
"Must be 0 or a power of 2. "
1492-
"Takes effect only for databases whose observability segment "
1493-
"has not yet been created.",
1492+
"Takes effect only after server restart.",
14941493
&ts_guc_stats_max_chunks,
14951494
TS_STATS_MAX_CHUNKS_DEFAULT, /* default */
14961495
0, /* min: 0 = disabled */

src/ts_stats/ts_stats_defs.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
*/
66
#pragma once
77

8+
#include <string.h>
89
#include <postgres.h>
910
#include "export.h"
11+
#include <c.h>
1012
#include <chunk_insert_state.h>
1113
#include <datatype/timestamp.h>
1214
#include <port/atomics.h>
@@ -54,6 +56,12 @@ StaticAssertDecl(TS_STATS_BUCKETS < 256 && TS_STATS_PROBE_WIDTH < 256,
5456
* the order of recency.
5557
*/
5658

59+
typedef struct TsStatsRelids
60+
{
61+
Oid compressed_relid;
62+
Oid uncompressed_relid;
63+
} TsStatsRelids;
64+
5765
/*
5866
* As explained above, TsStatsChunkMetadata is split off from TsStatsChunk
5967
* because these are needed more frequently than the rest of the structure,
@@ -74,10 +82,8 @@ typedef struct TsStatsChunkMetadata
7482
* bits 2-63: seqno, incremented at every update for recency tracking
7583
*/
7684
pg_atomic_uint64 state;
77-
/* Chunks are identified by the compressed_relid */
78-
Oid compressed_relid;
79-
/* The uncompressed_relid is placed here for better cache alignment */
80-
Oid uncompressed_relid;
85+
/* Chunks are identified by relids.compressed_relid */
86+
TsStatsRelids relids;
8187
} TsStatsChunkMetadata;
8288

8389
/* Bit flag values as per the above: */
@@ -328,8 +334,13 @@ mms_merge(MinMaxSumDataWA *dst, const MinMaxSumData *src)
328334
uint64 cur_sqsum = pg_atomic_read_u64(&dst->sqsum_val);
329335
for (int r = 0; r < TS_STATS_MMS_CAS_MAX_RETRIES; r++)
330336
{
331-
double new_d = *((double *) &cur_sqsum) + src->sqsum_val;
332-
uint64 desired = *((uint64 *) &new_d);
337+
double new_d;
338+
memcpy(&new_d, &cur_sqsum, sizeof(double));
339+
new_d += src->sqsum_val;
340+
341+
uint64 desired;
342+
memcpy(&desired, &new_d, sizeof(uint64));
343+
333344
if (pg_atomic_compare_exchange_u64(&dst->sqsum_val, &cur_sqsum, desired))
334345
{
335346
break;
@@ -347,7 +358,7 @@ mms_update(MinMaxSumDataWA *dst, const MinMaxSumData *src)
347358
pg_atomic_write_u32(&dst->max_val, src->max_val);
348359
pg_atomic_write_u64(&dst->sum_val, src->sum_val);
349360

350-
/* sqsum is calculated as a double and then cast to uint64 for atomic operations */
361+
/* sqsum is calculated as a double and then copied to uint64 for atomic operations */
351362
pg_atomic_write_u64(&dst->sqsum_val, *((uint64 *) &src->sqsum_val));
352363
}
353364

src/ts_stats/ts_stats_record.c

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
*/
66

77
#include "ts_stats_record.h"
8+
#include "ts_stats/ts_stats_defs.h"
89
#include "ts_stats_segment.h"
910

1011
#include <postgres.h>
1112
#include <miscadmin.h>
1213
#include <storage/lwlock.h>
14+
#include <utils/dsa.h>
1315
#include <utils/timestamp.h>
1416

1517
static inline uint64
@@ -36,10 +38,10 @@ slot_touch_timestamps(TsStatsChunk *slot, uint64 now_us)
3638
}
3739

3840
void
39-
ts_stats_chunk_record_compression(Oid compressed_relid, Oid uncompressed_relid,
40-
const CompressionStatsAccumulator *a)
41+
ts_stats_chunk_record_compression(TsStatsRelids relids, const CompressionStatsAccumulator *a)
4142
{
42-
if (!OidIsValid(compressed_relid) || !OidIsValid(uncompressed_relid) || a->batch_count == 0)
43+
if (!OidIsValid(relids.compressed_relid) || !OidIsValid(relids.uncompressed_relid) ||
44+
a->batch_count == 0)
4345
{
4446
return;
4547
}
@@ -53,8 +55,7 @@ ts_stats_chunk_record_compression(Oid compressed_relid, Oid uncompressed_relid,
5355
/* get the slot_index for the upsert. this sets the in-progress flag and updates the bucket's
5456
* metadata if successful.
5557
*/
56-
int32 slot_idx =
57-
ts_stats_chunk_segment_prepare_upsert(seg, compressed_relid, uncompressed_relid);
58+
int32 slot_idx = ts_stats_chunk_segment_prepare_upsert(seg, relids);
5859
if (slot_idx == TS_STATS_INVALID_IDX)
5960
{
6061
/* if we failed to find or insert a slot for this compressed_relid, we just give up this
@@ -85,14 +86,13 @@ ts_stats_chunk_record_compression(Oid compressed_relid, Oid uncompressed_relid,
8586
slot_touch_timestamps(slot, now_us);
8687

8788
/* clear the in-progress flag */
88-
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, compressed_relid);
89+
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, relids.compressed_relid);
8990
}
9091

9192
void
92-
ts_stats_chunk_record_cmd(Oid compressed_relid, Oid uncompressed_relid, CmdType cmd,
93-
const SharedCounters *c)
93+
ts_stats_chunk_record_cmd(TsStatsRelids relids, CmdType cmd, const SharedCounters *c)
9494
{
95-
if (!OidIsValid(compressed_relid) || !OidIsValid(uncompressed_relid) || c == NULL)
95+
if (!OidIsValid(relids.compressed_relid) || !OidIsValid(relids.uncompressed_relid) || c == NULL)
9696
{
9797
return;
9898
}
@@ -110,8 +110,7 @@ ts_stats_chunk_record_cmd(Oid compressed_relid, Oid uncompressed_relid, CmdType
110110
/* get the slot_index for the upsert. this sets the in-progress flag and updates the bucket's
111111
* metadata if successful.
112112
*/
113-
int32 slot_idx =
114-
ts_stats_chunk_segment_prepare_upsert(seg, compressed_relid, uncompressed_relid);
113+
int32 slot_idx = ts_stats_chunk_segment_prepare_upsert(seg, relids);
115114
if (slot_idx == TS_STATS_INVALID_IDX)
116115
{
117116
/* if we failed to find or insert a slot for this compressed_relid, we just give up this
@@ -185,14 +184,13 @@ ts_stats_chunk_record_cmd(Oid compressed_relid, Oid uncompressed_relid, CmdType
185184
slot_touch_timestamps(slot, now_us);
186185

187186
/* clear the in-progress flag */
188-
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, compressed_relid);
187+
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, relids.compressed_relid);
189188
}
190189

191190
void
192-
ts_stats_chunk_record_decompression(Oid compressed_relid, Oid uncompressed_relid,
193-
const CompressionStatsAccumulator *a)
191+
ts_stats_chunk_record_decompression(TsStatsRelids relids, const CompressionStatsAccumulator *a)
194192
{
195-
if (!OidIsValid(compressed_relid) || !OidIsValid(uncompressed_relid))
193+
if (!OidIsValid(relids.compressed_relid) || !OidIsValid(relids.uncompressed_relid))
196194
{
197195
return;
198196
}
@@ -210,8 +208,7 @@ ts_stats_chunk_record_decompression(Oid compressed_relid, Oid uncompressed_relid
210208
/* get the slot_index for the upsert. this sets the in-progress flag and updates the bucket's
211209
* metadata if successful.
212210
*/
213-
int32 slot_idx =
214-
ts_stats_chunk_segment_prepare_upsert(seg, compressed_relid, uncompressed_relid);
211+
int32 slot_idx = ts_stats_chunk_segment_prepare_upsert(seg, relids);
215212
if (slot_idx == TS_STATS_INVALID_IDX)
216213
{
217214
/* if we failed to find or insert a slot for this compressed_relid, we just give up this
@@ -257,7 +254,7 @@ ts_stats_chunk_record_decompression(Oid compressed_relid, Oid uncompressed_relid
257254
slot_touch_timestamps(slot, now_us);
258255

259256
/* clear the in-progress flag */
260-
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, compressed_relid);
257+
ts_stats_chunk_segment_finish_upsert(seg, slot_idx, relids.compressed_relid);
261258
}
262259

263260
bool
@@ -290,3 +287,52 @@ ts_stats_chunk_lookup(Oid compressed_relid, TsStatsChunk *out)
290287
memcpy(out, slot, sizeof(TsStatsChunk));
291288
return true;
292289
}
290+
291+
void
292+
ts_stats_chunk_evict(Oid compressed_relid)
293+
{
294+
if (!OidIsValid(compressed_relid))
295+
{
296+
return;
297+
}
298+
TsStatsChunkSegment *seg = ts_get_stats_chunk_segment();
299+
if (seg == NULL)
300+
{
301+
return;
302+
}
303+
304+
int32 slot_idx = ts_stats_chunk_segment_lookup(seg, compressed_relid);
305+
306+
if (slot_idx == TS_STATS_INVALID_IDX)
307+
{
308+
return;
309+
}
310+
Assert(slot_idx >= 0 && slot_idx < (int32) seg->num_slots);
311+
312+
TsStatsChunkMetadata *meta_base = ts_stats_chunk_metadata(seg);
313+
TsStatsChunkMetadata *meta = &meta_base[slot_idx];
314+
315+
/* limited CAS loop to ensure we don't evict a chunk that is currently being updated, the danger
316+
* is that the one that we are evicting is already being overwritten by a newer/other chunk.
317+
*/
318+
uint64 state = pg_atomic_read_u64(&meta->state);
319+
uint64 new_seqno = pg_atomic_add_fetch_u64(&seg->update_seqno, 1);
320+
uint64 new_state = (new_seqno << TS_STATS_CHUNK_METADATA_SEQNO_SHIFT);
321+
for (int i = 0;
322+
i < 5 &&
323+
/* the slot still matches the compressed_relid */
324+
meta->relids.compressed_relid == compressed_relid &&
325+
/* the slot is still valid and not in progress */
326+
TS_STATS_CHUNK_METADATA_IS_VALID(state) &&
327+
!(TS_STATS_CHUNK_METADATA_IS_IN_PROGRESS(state)) &&
328+
/* the slot being updated is older than the sequence number of the current update */
329+
TS_STATS_CHUNK_METADATA_GET_SEQNO(state) < new_seqno;
330+
++i)
331+
{
332+
if (pg_atomic_compare_exchange_u64(&meta->state, &state, new_state))
333+
{
334+
meta->relids.compressed_relid = InvalidOid;
335+
break;
336+
}
337+
}
338+
}

src/ts_stats/ts_stats_record.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,26 @@ ts_stats_compression_acc_batch(CompressionStatsAccumulator *a, uint32 batch_rows
5353
/* Update shared memory with new statistics information. */
5454

5555
/* Compression — commits the accumulator into the chunk's slot. */
56-
extern TSDLLEXPORT void ts_stats_chunk_record_compression(Oid compressed_relid,
57-
Oid uncompressed_relid,
56+
extern TSDLLEXPORT void ts_stats_chunk_record_compression(TsStatsRelids relids,
5857
const CompressionStatsAccumulator *a);
5958

6059
/* Cmd stats on compressed data. cmd is one of CMD_INSERT / CMD_UPDATE / CMD_DELETE / CMD_SELECT */
61-
extern TSDLLEXPORT void ts_stats_chunk_record_cmd(Oid compressed_relid, Oid uncompressed_relid,
62-
CmdType cmd, const SharedCounters *c);
60+
extern TSDLLEXPORT void ts_stats_chunk_record_cmd(TsStatsRelids relids, CmdType cmd,
61+
const SharedCounters *c);
6362

6463
/* For backfilling compressed data during decompression.
6564
* This function will update the compression stats for the chunk when it finds more complete
6665
* information about the compressed data than the one we have in memory. The reason we
6766
* need this is because the in-memory entries may miss the compression event, either because
6867
* of a restart or because the chunk information has been evicted from memory due to lack of use.
6968
*/
70-
extern TSDLLEXPORT void ts_stats_chunk_record_decompression(Oid compressed_relid,
71-
Oid uncompressed_relid,
69+
extern TSDLLEXPORT void ts_stats_chunk_record_decompression(TsStatsRelids relids,
7270
const CompressionStatsAccumulator *a);
7371

7472
/* Lookup TsStatsChunk based on the compressed relid. It returns true if the chunk is found, false
7573
* otherwise. */
7674
extern TSDLLEXPORT bool ts_stats_chunk_lookup(Oid compressed_relid, TsStatsChunk *out);
75+
76+
/* Evict the chunk information for a given compressed relid. This function is called when we
77+
* drop a compressed chunk. */
78+
extern TSDLLEXPORT void ts_stats_chunk_evict(Oid compressed_relid);

0 commit comments

Comments
 (0)