Esempio n. 1
0
/*
 * Rebuild the event trigger cache.
 */
static void
BuildEventTriggerCache(void)
{
    HASHCTL         ctl;
    HTAB		   *cache;
    MemoryContext	oldcontext;
    Relation		rel;
    Relation		irel;
    SysScanDesc		scan;

    if (EventTriggerCacheContext != NULL)
    {
        /*
         * Free up any memory already allocated in EventTriggerCacheContext.
         * This can happen either because a previous rebuild failed, or
         * because an invalidation happened before the rebuild was complete.
         */
        MemoryContextResetAndDeleteChildren(EventTriggerCacheContext);
    }
    else
    {
        /*
         * This is our first time attempting to build the cache, so we need
         * to set up the memory context and register a syscache callback to
         * capture future invalidation events.
         */
        if (CacheMemoryContext == NULL)
            CreateCacheMemoryContext();
        EventTriggerCacheContext =
            AllocSetContextCreate(CacheMemoryContext,
                                  "EventTriggerCache",
                                  ALLOCSET_DEFAULT_MINSIZE,
                                  ALLOCSET_DEFAULT_INITSIZE,
                                  ALLOCSET_DEFAULT_MAXSIZE);
        CacheRegisterSyscacheCallback(EVENTTRIGGEROID,
                                      InvalidateEventCacheCallback,
                                      (Datum) 0);
    }

    /* Switch to correct memory context. */
    oldcontext = MemoryContextSwitchTo(EventTriggerCacheContext);

    /* Prevent the memory context from being nuked while we're rebuilding. */
    EventTriggerCacheState = ETCS_REBUILD_STARTED;

    /* Create new hash table. */
    MemSet(&ctl, 0, sizeof(ctl));
    ctl.keysize = sizeof(EventTriggerEvent);
    ctl.entrysize = sizeof(EventTriggerCacheEntry);
    ctl.hash = tag_hash;
    ctl.hcxt = EventTriggerCacheContext;
    cache = hash_create("Event Trigger Cache", 32, &ctl,
                        HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);

    /*
     * Prepare to scan pg_event_trigger in name order.  We use an MVCC
     * snapshot to avoid getting inconsistent results if the table is
     * being concurrently updated.
     */
    rel = relation_open(EventTriggerRelationId, AccessShareLock);
    irel = index_open(EventTriggerNameIndexId, AccessShareLock);
    scan = systable_beginscan_ordered(rel, irel, GetLatestSnapshot(), 0, NULL);

    /*
     * Build a cache item for each pg_event_trigger tuple, and append each
     * one to the appropriate cache entry.
     */
    for (;;)
    {
        HeapTuple		tup;
        Form_pg_event_trigger	form;
        char	   *evtevent;
        EventTriggerEvent	event;
        EventTriggerCacheItem *item;
        Datum		evttags;
        bool		evttags_isnull;
        EventTriggerCacheEntry *entry;
        bool		found;

        /* Get next tuple. */
        tup = systable_getnext_ordered(scan, ForwardScanDirection);
        if (!HeapTupleIsValid(tup))
            break;

        /* Skip trigger if disabled. */
        form = (Form_pg_event_trigger) GETSTRUCT(tup);
        if (form->evtenabled == TRIGGER_DISABLED)
            continue;

        /* Decode event name. */
        evtevent = NameStr(form->evtevent);
        if (strcmp(evtevent, "ddl_command_start") == 0)
            event = EVT_DDLCommandStart;
        else
            continue;

        /* Allocate new cache item. */
        item = palloc0(sizeof(EventTriggerCacheItem));
        item->fnoid = form->evtfoid;
        item->enabled = form->evtenabled;

        /* Decode and sort tags array. */
        evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
                               RelationGetDescr(rel), &evttags_isnull);
        if (!evttags_isnull)
        {
            item->ntags = DecodeTextArrayToCString(evttags, &item->tag);
            qsort(item->tag, item->ntags, sizeof(char *), pg_qsort_strcmp);
        }

        /* Add to cache entry. */
        entry = hash_search(cache, &event, HASH_ENTER, &found);
        if (found)
            entry->triggerlist = lappend(entry->triggerlist, item);
        else
            entry->triggerlist = list_make1(item);
    }

    /* Done with pg_event_trigger scan. */
    systable_endscan_ordered(scan);
    index_close(irel, AccessShareLock);
    relation_close(rel, AccessShareLock);

    /* Restore previous memory context. */
    MemoryContextSwitchTo(oldcontext);

    /* Install new cache. */
    EventTriggerCache = cache;

    /*
     * If the cache has been invalidated since we entered this routine, we
     * still use and return the cache we just finished constructing, to avoid
     * infinite loops, but we leave the cache marked stale so that we'll
     * rebuild it again on next access.  Otherwise, we mark the cache valid.
     */
    if (EventTriggerCacheState == ETCS_REBUILD_STARTED)
        EventTriggerCacheState = ETCS_VALID;
}
Esempio n. 2
0
/*
 * Rebuild the event trigger cache.
 */
static void
BuildEventTriggerCache(void)
{
	HASHCTL         ctl;
	HTAB		   *cache;
	MemoryContext	oldcontext;
	Relation		rel;
	Relation		irel;
	SysScanDesc		scan;

	if (EventTriggerCacheContext != NULL)
	{
		/*
		 * The cache has been previously built, and subsequently invalidated,
		 * and now we're trying to rebuild it.  Normally, there won't be
		 * anything in the context at this point, because the invalidation
		 * will have already reset it.  But if the previous attempt to rebuild
		 * the cache failed, then there might be some junk lying around
		 * that we want to reclaim.
		 */
		MemoryContextReset(EventTriggerCacheContext);
	}
	else
	{
		/*
		 * This is our first time attempting to build the cache, so we need
		 * to set up the memory context and register a syscache callback to
		 * capture future invalidation events.
		 */
		if (CacheMemoryContext == NULL)
			CreateCacheMemoryContext();
		EventTriggerCacheContext =
			AllocSetContextCreate(CacheMemoryContext,
								  "EventTriggerCache",
								  ALLOCSET_DEFAULT_MINSIZE,
								  ALLOCSET_DEFAULT_INITSIZE,
								  ALLOCSET_DEFAULT_MAXSIZE);
		CacheRegisterSyscacheCallback(EVENTTRIGGEROID,
									  InvalidateEventCacheCallback,
									  (Datum) 0);
	}

	/* Switch to correct memory context. */
	oldcontext = MemoryContextSwitchTo(EventTriggerCacheContext);

	/*
	 * Create a new hash table, but don't assign it to the global variable
	 * until it accurately represents the state of the catalogs, so that
	 * if we fail midway through this we won't end up with incorrect cache
	 * contents.
	 */
	MemSet(&ctl, 0, sizeof(ctl));
	ctl.keysize = sizeof(EventTriggerEvent);
	ctl.entrysize = sizeof(EventTriggerCacheEntry);
	ctl.hash = tag_hash;
	cache = hash_create("Event Trigger Cache", 32, &ctl,
						HASH_ELEM | HASH_FUNCTION);

	/*
	 * Prepare to scan pg_event_trigger in name order.  We use an MVCC
	 * snapshot to avoid getting inconsistent results if the table is
	 * being concurrently updated.
	 */
	rel = relation_open(EventTriggerRelationId, AccessShareLock);
	irel = index_open(EventTriggerNameIndexId, AccessShareLock);
	scan = systable_beginscan_ordered(rel, irel, GetLatestSnapshot(), 0, NULL);

	/*
	 * Build a cache item for each pg_event_trigger tuple, and append each
	 * one to the appropriate cache entry.
	 */
	for (;;)
	{
		HeapTuple		tup;
		Form_pg_event_trigger	form;
		char	   *evtevent;
		EventTriggerEvent	event;
		EventTriggerCacheItem *item;
		Datum		evttags;
		bool		evttags_isnull;
		EventTriggerCacheEntry *entry;
		bool		found;

		/* Get next tuple. */
		tup = systable_getnext_ordered(scan, ForwardScanDirection);
		if (!HeapTupleIsValid(tup))
			break;

		/* Skip trigger if disabled. */
		form = (Form_pg_event_trigger) GETSTRUCT(tup);
		if (form->evtenabled == TRIGGER_DISABLED)
			continue;

		/* Decode event name. */
		evtevent = NameStr(form->evtevent);
		if (strcmp(evtevent, "ddl_command_start") == 0)
			event = EVT_DDLCommandStart;
		else
			continue;

		/* Allocate new cache item. */
		item = palloc0(sizeof(EventTriggerCacheItem));
		item->fnoid = form->evtfoid;
		item->enabled = form->evtenabled;

		/* Decode and sort tags array. */
		evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
							   RelationGetDescr(rel), &evttags_isnull);
		if (!evttags_isnull)
		{
			item->ntags = DecodeTextArrayToCString(evttags, &item->tag);
			qsort(item->tag, item->ntags, sizeof(char *), pg_qsort_strcmp);
		}

		/* Add to cache entry. */
		entry = hash_search(cache, &event, HASH_ENTER, &found);
		if (found)
			entry->triggerlist = lappend(entry->triggerlist, item);
		else
			entry->triggerlist = list_make1(item);
	}

	/* Done with pg_event_trigger scan. */
	systable_endscan_ordered(scan);
	index_close(irel, AccessShareLock);
	relation_close(rel, AccessShareLock);

	/* Restore previous memory context. */
	MemoryContextSwitchTo(oldcontext);

	/* Cache is now valid. */
	EventTriggerCache = cache;
}