Which Replicated Tables Got Changes in BDR Replication

My favourite feature of BDR by 2ndQuadrant is “multi master table level selective replication”. Currently, I am preparing a plan to switch from trigger based to low level BDR replication for better performance.

But, how can I detect which replicated tables got changes (needed for memcached invalidation, for example). I can not trap it inside always-enabled-trigger any longer. An alternative is to modify BDR plugin c source code. Thanks to 2ndQuadrant team for clear source code. Following code is my modification for bdr_apply.c:

  1. Module level variable and function declaration:
  2. #define DTABLECHUNK 5
    static char** dtables;
    static int dtablessize;
    static int dtablescount;
    static void append_dtables(char* t);
  3. Variable initialization at the end of process_remote_begin:
  4. static void
    process_remote_begin(StringInfo s) {

    ...
    dtables=NULL;
    dtablessize=dtablescount=0;

    }

  5. Modify a bit declaration and definition of read_rel function to catch tablename:
  6. static BDRRelation *
    read_rel(StringInfo s, LOCKMODE mode, char** dtablename){

    int relnamelen;
    int nspnamelen;
    RangeVar* rv;
    Oid relid;
    MemoryContext oldcontext;

    rv = makeNode(RangeVar);

    nspnamelen = pq_getmsgint(s, 2);
    rv->schemaname = (char *) pq_getmsgbytes(s, nspnamelen);

    relnamelen = pq_getmsgint(s, 2);
    rv->relname = (char *) pq_getmsgbytes(s, relnamelen);

    oldcontext=MemoryContextSwitchTo(MessageContext);
    //nspnamelen and relnamelen is the length of the name including terminating zero
    *dtablename=(char*)palloc( (nspnamelen+relnamelen) * sizeof(char) );
    MemoryContextSwitchTo(oldcontext);
    sprintf(*dtablename, "%s.%s", rv->schemaname, rv->relname);

    relid = RangeVarGetRelidExtended(rv, mode, false, false, NULL, NULL);

    return bdr_heap_open(relid, NoLock);

    }

  7. Declare variable char *tablename inside process_remote_insert, process_remote_update and process_remote_delete. Add its address (&tablename) as third argument for read_real function invocation. Then, register the tablename by calling my append_dtables just after simple_heap_insert, simple_heap_update and simple_heap_delete.
  8. Call outside function to notify which tables got changes inside process_remote_commit function, somewhere after a call to CommitTransactionCommand.
  9. for(i=0;dtables!=NULL && i<dtablescount;i++) {
    //any function call to notify dtables[i] got changes
    }
  10. And finally, this is my append_dtables definition. Note that memory is allocated in MessageContext so it will be freed automatically in bdr_apply_work main loop.
  11. static void
    append_dtables(char* t) {

    int i, allocsize;
    MemoryContext oldcontext;

    for(i=0;i<dtablescount;i++) {

    if(!strcmp(dtables[i], t)) {//ensure unique table registration

    oldcontext=MemoryContextSwitchTo(MessageContext);
    pfree(t);
    MemoryContextSwitchTo(oldcontext);
    return;

    }

    }
    if(dtablessize<++dtablescount) {

    dtablessize+=DTABLECHUNK;
    allocsize=dtablessize * sizeof(char*);
    oldcontext=MemoryContextSwitchTo(MessageContext);
    if(dtables==NULL)

    dtables=(char*)palloc(allocsize);

    else

    dtables=(char**)repalloc(dtables, allocsize);

    MemoryContextSwitchTo(oldcontext);

    }
    dtables[dtablescount-1]=t;

    }

    What I love from open source project is that there is always a way to tweak to suit my development framework.

    Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: