Skip to content

Instantly share code, notes, and snippets.

@viggy28
Created March 29, 2024 04:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viggy28/839aa381e69f9adbbd17b84704b02b0e to your computer and use it in GitHub Desktop.
Save viggy28/839aa381e69f9adbbd17b84704b02b0e to your computer and use it in GitHub Desktop.
title
Managing & Developing Extensions

Intro to omni

omni is a Postgres shared library (and also an extension) that helps managing and developing Postgres easier. Think of it like an extension for extensions !

Why?

Postgres extension eco-system is growing rapidly, however the tooling/infrastructure around that has a lot of catch up to do. For eg. an extension that allocates shared memory or spins up background workers requires restarting Postgres.

Features

  • Hooks initialization
  • Allocate/Deallocate shared memory
  • Managing background workers
  • Upgrading extensions
  • Setting custom GUC

Installing omni

To find the latest version of omni curl -s https://index.omnigres.com/16/Release/ubuntu-x86-64/index.json | jq .

To download and install omni curl -s https://raw.githubusercontent.com/omnigres/omnigres/master/download-omnigres-extension.sh | bash -s install omni 0.1.2

postgres=# create extension omni;

or use omni_manifest.install() to install it.

Integrating omni in your extensions

  • Include omni header file omni_v0.h
  • Declare OMNI_MAGIC in your extension
  • Create a function dummy
  • Define the callback function _Omni_init
  • Update postgresql.conf shared_preload_libraies config to include omni

Using omni

Hook capabilities

Declare a hook variable which is of type omni_hook and register that with the handle (of type omni_handle) in the callback function _Omni_init.

Example:

void planner_hook_fn(omni_hook_handle *handle, Query *parse, const char *query_string,
                     int cursorOptions, ParamListInfo boundParams) {
  ereport(NOTICE, errmsg("planner_hook_fn %p", handle->returns.PlannedStmt_value));
}

void _Omni_init(const omni_handle *handle) {
  omni_hook planner_hook = {.type = omni_hook_planner,
                            .name = "omni_guard planner hook",
                            .fn = {.planner = planner_hook_fn},
                            .wrap = true};
  handle->register_hook(handle, &planner_hook);
}

Shared memory allocation

Inside the callback _Omni_init, invoke allocate_shmem method of omni_handle type.

Example:

void _Omni_init(const omni_handle *handle) {
  bool found;
  int a = handle->allocate_shmem(handle, "shmem example using omni", sizeof(int), NULL, NULL, &found);
}

Shared memory deallocation

Inside the callback _Omni_deinit, call deallocate_shmem method of omni_handle type.

Example:

TODO: to tests
void _Omni_deinit(const omni_handle *handle) {
    handle->deallocate_shmem(handle, "shmem example using omni", NULL);
}

Setting GUC's for your extension

Inside the callback _Omni_init, invoke declare_guc_variable method of omni_handle type.

void _Omni_init(const omni_handle *handle) {
  omni_guc_variable guc_example_variable = {
      .name = "guc_example_variable",
      .long_desc = "Example variable to set GUC with omni",
      .type = PGC_STRING,
      .typed = {.string_val = {.boot_value = "hello"}},
      .context = PGC_SIGHUP};
}

Starting background workers

In general, starting background workers from an extension require postgres restart.

Inside the callback _Omni_init, invoke request_bgworker_start method of omni_handle type.

request_bgworker_start takes an argument of type BackgroundWorker

TODO: should the function be declared as PGDLLEXPORT or not?
PGDLLEXPORT void example_entry_point() {
  elog(INFO, "do something useful here");
}

void _Omni_init(const omni_handle *handle) {
omni_bgworker_handle example_bgworker_handle = handle->request_bgworker_start(handle, {
    .bgw_name = "example bgw worker from omni"
    .bgw_type = "omni"
    .bgw_function_name = "example_entry_point"
}, NULL);
}

Terminating background workers

Inside the callback _Omni_deinit, invoke request_bgworker_termination method of omni_handle type.

void _Omni_deinit(const omni_handle *handle) {
  if (example_bgworker_handle != NULL) {

    handle->request_bgworker_termination(
      handle,
      example_bgworker_handle
  );
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment