Deletes the rows that have expired for the given table name and ttl entry information. * It deletes the number of items specified on the batchSize that have expired based on the index entry expiry value. * If ttlMetricsContext is not NULL, records metrics via the RecordTtlMetric hook. */
| 600 | * It deletes the number of items specified on the batchSize that have expired based on the index entry expiry value. |
| 601 | * If ttlMetricsContext is not NULL, records metrics via the RecordTtlMetric hook. */ |
| 602 | static uint64 |
| 603 | DeleteExpiredRowsForIndexCore(char *tableName, TtlIndexEntry *indexEntry, int64 |
| 604 | currentTime, int32 batchSize, instr_time startTime, int |
| 605 | budget, bool *isTaskTimeBudgetExceeded, |
| 606 | void *ttlMetricsContext) |
| 607 | { |
| 608 | /* Per-batch timer for TTL deletion */ |
| 609 | instr_time batchStart; |
| 610 | INSTR_TIME_SET_CURRENT(batchStart); |
| 611 | |
| 612 | int32 defaultBatchSize = (SkipRepeatDeleteForUnOrderedIndex && |
| 613 | !indexEntry->indexIsOrdered) ? |
| 614 | MaxTTLBatchSizeUnorderedIndex : MaxTTLDeleteBatchSize; |
| 615 | int32 ttlDeleteBatchSize = (batchSize != -1) ? batchSize : |
| 616 | defaultBatchSize; |
| 617 | pgbson *indexKeyDocument = DatumGetPgBson(indexEntry->indexKeyDatum); |
| 618 | pgbson *indexPfe = (indexEntry->indexPfeDatum != (Datum) 0) ? |
| 619 | DatumGetPgBson(indexEntry->indexPfeDatum) : NULL; |
| 620 | |
| 621 | /* TTL expireAfterSeconds is an int32 but we cast it as int64 to avoid overflow in milliseconds calculation */ |
| 622 | int64 indexExpiryMilliseconds = (int64) indexEntry->indexExpireAfterSeconds * 1000L; |
| 623 | bson_iter_t pathSpecIter; |
| 624 | PgbsonInitIterator(indexKeyDocument, &pathSpecIter); |
| 625 | bson_iter_next(&pathSpecIter); |
| 626 | const char *indexKey = bson_iter_key(&pathSpecIter); |
| 627 | |
| 628 | /* |
| 629 | * Note that the TTL condition is repeated here, once for selecting a batch of records and once more while deleting. |
| 630 | * The reason is that the SELECT subquery won't lock the records for update, so by the time we DELETE them, the records |
| 631 | * could have been concurrently updated for them to come out of expiry window. Deleting those record won't be correct. |
| 632 | * Hence we repeat the expiry condition once again in the DELETE statement. |
| 633 | * |
| 634 | * As a side comment, we use the SELECT subquery to select a batch of records, because "DELETE" does not support LIMIT |
| 635 | * (it's a Postgres limitation). |
| 636 | * |
| 637 | * An index can have a partial filter expression (pfe) specified during creation which is also applicable for TTL index. We apply |
| 638 | * the pfe predicate while selecting and deleting the expired records. |
| 639 | */ |
| 640 | |
| 641 | StringInfo cmdStrDeleteRows = makeStringInfo(); |
| 642 | |
| 643 | /* optimization for unsharded collection to avoid 2PC */ |
| 644 | appendStringInfo(cmdStrDeleteRows, |
| 645 | "DELETE FROM %s.%s" |
| 646 | " WHERE ctid IN (SELECT ctid FROM %s.%s" |
| 647 | " WHERE %s.bson_dollar_lt(document, $1::%s) ", |
| 648 | ApiDataSchemaName, tableName, |
| 649 | ApiDataSchemaName, tableName, |
| 650 | ApiCatalogSchemaName, FullBsonTypeName); |
| 651 | |
| 652 | int argCount = 1; |
| 653 | |
| 654 | /* |
| 655 | * In the SQL query above, we provide the corresponding TTL index as a hint for the TTL task query. |
| 656 | * Even though it's called a hint, by design it forces the use of the specified index. |
| 657 | * |
| 658 | * As an additional note IndexOnly scans are not allowed for retrieving ctids. |
| 659 | */ |
no test coverage detected