/* * Set the state of a slot. * * This doesn't maintain the non-persistent state at all, * but since the slot isn't in use that's OK. * * There's intentionally no check to prevent slots going backwards * because they can actually go backwards if the master crashes when * it hasn't yet flushed slot state to disk then we copy the older * slot state after recovery. * * There's no checking done for xmin or catalog xmin either, since * we can't really do anything useful that accounts for xid wrap-around. * * Note that this is test harness code. You shouldn't expose slot internals * to SQL like this for any real world usage. See the README. */ Datum test_slot_timelines_advance_logical_slot(PG_FUNCTION_ARGS) { char *slotname = text_to_cstring(PG_GETARG_TEXT_P(0)); TransactionId new_xmin = (TransactionId) PG_GETARG_INT64(1); TransactionId new_catalog_xmin = (TransactionId) PG_GETARG_INT64(2); XLogRecPtr restart_lsn = PG_GETARG_LSN(3); XLogRecPtr confirmed_lsn = PG_GETARG_LSN(4); CheckSlotRequirements(); ReplicationSlotAcquire(slotname); if (MyReplicationSlot->data.database != MyDatabaseId) elog(ERROR, "Trying to update a slot on a different database"); MyReplicationSlot->data.xmin = new_xmin; MyReplicationSlot->data.catalog_xmin = new_catalog_xmin; MyReplicationSlot->data.restart_lsn = restart_lsn; MyReplicationSlot->data.confirmed_flush = confirmed_lsn; clear_slot_transient_state(); ReplicationSlotMarkDirty(); ReplicationSlotSave(); ReplicationSlotRelease(); ReplicationSlotsComputeRequiredXmin(false); ReplicationSlotsComputeRequiredLSN(); PG_RETURN_VOID(); }
/* * Create a new logical slot, with invalid LSN and xid, directly. This does not * use the snapshot builder or logical decoding machinery. It's only intended * for creating a slot on a replica that mirrors the state of a slot on an * upstream master. * * Note that this is test harness code. You shouldn't expose slot internals * to SQL like this for any real world usage. See the README. */ Datum test_slot_timelines_create_logical_slot(PG_FUNCTION_ARGS) { char *slotname = text_to_cstring(PG_GETARG_TEXT_P(0)); char *plugin = text_to_cstring(PG_GETARG_TEXT_P(1)); CheckSlotRequirements(); ReplicationSlotCreate(slotname, true, RS_PERSISTENT); /* register the plugin name with the slot */ StrNCpy(NameStr(MyReplicationSlot->data.plugin), plugin, NAMEDATALEN); /* * Initialize persistent state to placeholders to be set by * test_slot_timelines_advance_logical_slot . */ MyReplicationSlot->data.xmin = InvalidTransactionId; MyReplicationSlot->data.catalog_xmin = InvalidTransactionId; MyReplicationSlot->data.restart_lsn = InvalidXLogRecPtr; MyReplicationSlot->data.confirmed_flush = InvalidXLogRecPtr; clear_slot_transient_state(); ReplicationSlotRelease(); PG_RETURN_VOID(); }
/* * SQL function for creating a new physical (streaming replication) * replication slot. */ Datum pg_create_physical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); Datum values[2]; bool nulls[2]; TupleDesc tupdesc; HeapTuple tuple; Datum result; Assert(!MyReplicationSlot); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); check_permissions(); CheckSlotRequirements(); /* acquire replication slot, this will check for conflicting names */ ReplicationSlotCreate(NameStr(*name), false, RS_PERSISTENT); values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[0] = false; nulls[1] = true; tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); ReplicationSlotRelease(); PG_RETURN_DATUM(result); }
/* * SQL function for dropping a replication slot. */ Datum pg_drop_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); check_permissions(); CheckSlotRequirements(); ReplicationSlotDrop(NameStr(*name)); PG_RETURN_VOID(); }
/* * SQL function for creating a new physical (streaming replication) * replication slot. */ Datum pg_create_physical_replication_slot(PG_FUNCTION_ARGS) { Name name = PG_GETARG_NAME(0); bool immediately_reserve = PG_GETARG_BOOL(1); Datum values[2]; bool nulls[2]; TupleDesc tupdesc; HeapTuple tuple; Datum result; Assert(!MyReplicationSlot); if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); check_permissions(); CheckSlotRequirements(); /* acquire replication slot, this will check for conflicting names */ ReplicationSlotCreate(NameStr(*name), false, RS_PERSISTENT); values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[0] = false; if (immediately_reserve) { /* Reserve WAL as the user asked for it */ ReplicationSlotReserveWal(); /* Write this slot to disk */ ReplicationSlotMarkDirty(); ReplicationSlotSave(); values[1] = LSNGetDatum(MyReplicationSlot->data.restart_lsn); nulls[1] = false; } else { values[0] = NameGetDatum(&MyReplicationSlot->data.name); nulls[1] = true; } tuple = heap_form_tuple(tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); ReplicationSlotRelease(); PG_RETURN_DATUM(result); }