Skip to content

Commit 3157940

Browse files
committed
Add pg_gtm extension
1 parent 56c8ce8 commit 3157940

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+7684
-6
lines changed

contrib/pg_gtm/Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
MODULE_big = pg_dtm
2+
OBJS = pg_dtm.o libdtm.o
3+
4+
EXTENSION = pg_dtm
5+
DATA = pg_dtm--1.0.sql
6+
7+
ifdef USE_PGXS
8+
PG_CONFIG = pg_config
9+
PGXS := $(shell $(PG_CONFIG) --pgxs)
10+
include $(PGXS)
11+
else
12+
subdir = contrib/pg_dtm
13+
top_builddir = ../..
14+
include $(top_builddir)/src/Makefile.global
15+
include $(top_srcdir)/contrib/contrib-global.mk
16+
endif

contrib/pg_gtm/README

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
===
2+
dtm
3+
===
4+
5+
Distributed transaction management tools for PostgreSQL.
6+
7+
--------------------
8+
Communication scheme
9+
--------------------
10+
11+
.- Backend -.
12+
/ \
13+
/ \
14+
DTM ---- Backend ---- Coordinator
15+
\ /
16+
\ /
17+
`- Backend -´
18+
19+
-----------------------
20+
Coordinator-Backend API
21+
-----------------------
22+
23+
This API includes a set of postgres procedures that
24+
the coordinator can call with "select" statement.
25+
26+
extend_transaction (n integer) -> (higcid gcid)
27+
join_transaction (higcid gcid) -> ()
28+
FIXME: add procedures that would start and finish 2pc
29+
30+
----------
31+
libdtm api
32+
----------
33+
34+
typedef unsigned long long cid_t;
35+
36+
// Connects to the specified DTM.
37+
DTMConn DtmConnect(char *host, int port);
38+
39+
// Disconnects from the DTM. Do not use the 'dtm' pointer after this call, or
40+
// bad things will happen.
41+
void DtmDisconnect(DTMConn dtm);
42+
43+
// Asks DTM for the first 'gcid' with unknown status. This 'gcid' is used as a
44+
// kind of snapshot. Returns the 'gcid' on success, or INVALID_GCID otherwise.
45+
cid_t DtmGlobalGetNextCid(DTMConn dtm);
46+
47+
// Prepares a commit. Returns the 'gcid' on success, or INVALID_GCID otherwise.
48+
cid_t DtmGlobalPrepare(DTMConn dtm);
49+
50+
// Finishes a given commit with 'committed' status. Returns 'true' on success,
51+
// 'false' otherwise.
52+
bool DtmGlobalCommit(DTMConn dtm, cid_t gcid);
53+
54+
// Finishes a given commit with 'aborted' status.
55+
void DtmGlobalRollback(DTMConn dtm, cid_t gcid);
56+
57+
// Gets the status of the commit identified by 'gcid'. Returns the status on
58+
// success, or -1 otherwise.
59+
int DtmGlobalGetTransStatus(DTMConn dtm, cid_t gcid);
60+
61+
--------------------
62+
Backend-DTM Protocol
63+
--------------------
64+
65+
DTM <--> Backend:
66+
67+
<- 'p'<hex16 self> - "prepare"
68+
-> '+'<hex16 gcid> - "commit prepared"
69+
-> '-' - "something went wrong"
70+
71+
<- 'c'<hex16 gcid> - "commit"
72+
-> '+' - "commit saved"
73+
-> '-' - "something went wrong"
74+
75+
<- 'a'<hex16 gcid> - "abort"
76+
-> '+' - "abort saved"
77+
-> '-' - "something went wrong"
78+
79+
<- 'h' - "horizon"
80+
-> '+'<hex16 gcid> - "here is a gcid you can use as a snapshot"
81+
-> '-' - "something went wrong"
82+
83+
<- 's'<hex16 gcid> - "status"
84+
-> '+''c|a|?' - "here is the transaction status"
85+
(c)ommitted, (a)borted or (?)unknown
86+
-> '-' - "something went wrong"
87+
88+
Backend disconnection is considered as an abort of all incomplete commits
89+
prepared by that backend.

contrib/pg_gtm/dtmd/Makefile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
CC=gcc
2+
CFLAGS=-g -pedantic -Wall -Iinclude -D_LARGEFILE64_SOURCE
3+
LIBUV_PREFIX=$(HOME)/libuv-build
4+
LIBUV_CFLAGS=-I"$(LIBUV_PREFIX)/include" -L"$(LIBUV_PREFIX)/lib"
5+
LIBUV_LDFLAGS=-luv -pthread
6+
7+
SYSTEM=$(shell uname -s)
8+
ifeq ($(SYSTEM),Darwin)
9+
CFLAGS += -D_DARWIN_C_SOURCE
10+
endif
11+
12+
.PHONY: all clean check bindir objdir
13+
14+
all: bin/dtmd
15+
@echo Done.
16+
@echo Feel free to run the tests with \'make check\'.
17+
18+
bin/dtmd: obj/eventwrap.o obj/main.o obj/parser.o obj/clog.o obj/clogfile.o obj/util.o | bindir objdir
19+
$(CC) -o bin/dtmd $(CFLAGS) $(LIBUV_CFLAGS) \
20+
obj/eventwrap.o obj/main.o obj/parser.o \
21+
obj/clog.o obj/clogfile.o obj/util.o \
22+
$(LIBUV_LDFLAGS)
23+
24+
obj/eventwrap.o: src/eventwrap.c | objdir
25+
$(CC) -c -o obj/eventwrap.o $(CFLAGS) $(LIBUV_CFLAGS) src/eventwrap.c
26+
27+
check: bin/util-test bin/clog-test bin/parser-test
28+
./check.sh util parser clog
29+
30+
obj/%.o: src/%.c | objdir
31+
$(CC) $(CFLAGS) -c -o $@ $<
32+
33+
bin/util-test: obj/util-test.o obj/util.o | bindir
34+
$(CC) -o bin/util-test $(CFLAGS) obj/util-test.o obj/util.o
35+
36+
bin/clog-test: obj/clog-test.o obj/clog.o obj/clogfile.o obj/util.o | bindir
37+
$(CC) -o bin/clog-test $(CFLAGS) obj/clog-test.o obj/clog.o obj/clogfile.o obj/util.o
38+
39+
bin/parser-test: obj/parser-test.o obj/parser.o | bindir
40+
$(CC) -o bin/parser-test $(CFLAGS) obj/parser-test.o obj/parser.o
41+
42+
bindir:
43+
mkdir -p bin
44+
45+
objdir:
46+
mkdir -p obj
47+
48+
clean:
49+
rm -rfv bin obj test.log

contrib/pg_gtm/dtmd/bin/dtmd

51.2 KB
Binary file not shown.

contrib/pg_gtm/dtmd/check.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/sh
2+
rm -rf test.log
3+
failed=0
4+
passed=0
5+
for testname in $@; do
6+
if bin/${testname}-test >> test.log 2>&1; then
7+
echo "${testname} ok"
8+
passed=$((passed + 1))
9+
else
10+
echo "${testname} FAILED"
11+
failed=$((failed + 1))
12+
fi
13+
done
14+
15+
echo "tests passed: $passed"
16+
echo "tests failed: $failed"
17+
if [ $failed -eq 0 ]; then
18+
rm -rf test.log
19+
else
20+
echo "see test.log for details"
21+
exit 1
22+
fi

contrib/pg_gtm/dtmd/include/clog.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* This module provides a high-level API to access clog files.
3+
*/
4+
5+
#ifndef CLOG_H
6+
#define CLOG_H
7+
8+
#include <stdbool.h>
9+
#include "int.h"
10+
11+
#define INVALID_GCID 0
12+
#define MIN_GCID 42
13+
#define MAX_GCID 0xdeadbeefcafebabe
14+
15+
#define COMMIT_UNKNOWN 0
16+
#define COMMIT_YES 1
17+
#define COMMIT_NO 2
18+
19+
typedef struct clog_data_t *clog_t;
20+
21+
// Open the clog at the specified path. Try not to open the same datadir twice
22+
// or in two different processes. Return a clog object on success, NULL
23+
// otherwise.
24+
clog_t clog_open(char *datadir);
25+
26+
// Get the status of the specified global commit.
27+
int clog_read(clog_t clog, cid_t gcid);
28+
29+
// Set the status of the specified global commit. Return 'true' on success,
30+
// 'false' otherwise.
31+
bool clog_write(clog_t clog, cid_t gcid, int status);
32+
33+
// Allocate a fresh unused gcid. Return INVALID_GCID on error.
34+
cid_t clog_advance(clog_t clog);
35+
36+
// Get the first unknown commit id (used as a snapshot). Return INVALID_GCID on
37+
// error.
38+
cid_t clog_horizon(clog_t clog);
39+
40+
// Forget about the commits before the given one ('until'), and free the
41+
// occupied space if possible. Return 'true' on success, 'false' otherwise.
42+
bool clog_forget(clog_t clog, cid_t until);
43+
44+
// Close the specified clog. Do not use the clog object after closing. Return
45+
// 'true' on success, 'false' otherwise.
46+
bool clog_close(clog_t clog);
47+
48+
#endif
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* This module provides a low-level API to access clog files.
3+
*/
4+
5+
#include <stdbool.h>
6+
#include "int.h"
7+
8+
#ifndef CLOGFILE_H
9+
#define CLOGFILE_H
10+
11+
#define BITS_PER_COMMIT 2
12+
#define COMMIT_MASK ((1 << BITS_PER_COMMIT) - 1)
13+
#define COMMITS_PER_BYTE 4
14+
#define COMMITS_PER_FILE 1024 // 0x100000000
15+
#define BYTES_PER_FILE ((COMMITS_PER_FILE) / (COMMITS_PER_BYTE))
16+
#define GCID_TO_FILEID(GCID) ((GCID) / (COMMITS_PER_FILE))
17+
#define GCID_TO_OFFSET(GCID) (((GCID) % (COMMITS_PER_FILE)) / (COMMITS_PER_BYTE))
18+
#define GCID_TO_SUBOFFSET(GCID) (((GCID) % (COMMITS_PER_FILE)) % (COMMITS_PER_BYTE))
19+
20+
typedef struct clogfile_t {
21+
char *path;
22+
cid_t min;
23+
cid_t max;
24+
void *data; // ptr for mmap
25+
} clogfile_t;
26+
27+
// Open a clog file with the gived id. Create before opening if 'create' is
28+
// true. Return 'true' on success, 'false' otherwise.
29+
bool clogfile_open_by_id(clogfile_t *clogfile, char *datadir, int fileid, bool create);
30+
31+
// Close and remove the given clog file. Return 'true' on success, 'false'
32+
// otherwise.
33+
bool clogfile_remove(clogfile_t *clogfile);
34+
35+
// Close the specified clogfile. Return 'true' on success, 'false' otherwise.
36+
bool clogfile_close(clogfile_t *clogfile);
37+
38+
// Get the status of the specified global commit from the clog file.
39+
int clogfile_get_status(clogfile_t *clogfile, cid_t gcid);
40+
41+
// Set the status of the specified global commit in the clog file. Return
42+
// 'true' on success, 'false' otherwise.
43+
bool clogfile_set_status(clogfile_t *clogfile, cid_t gcid, int status);
44+
45+
#endif
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* This module is used as a layer of abstraction between the main logic and the
3+
* event library. This should, theoretically, allow us to switch to another
4+
* library with less effort.
5+
*/
6+
7+
#ifndef EVENTWRAP_H
8+
#define EVENTWRAP_H
9+
10+
int eventwrap(
11+
const char *host,
12+
int port,
13+
char *(*ondata)(void *client, size_t len, char *data),
14+
void (*onconnect)(void **client),
15+
void (*ondisconnect)(void *client)
16+
);
17+
18+
#endif

contrib/pg_gtm/dtmd/include/int.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef INT_H
2+
#define INT_H
3+
4+
typedef unsigned long long cid_t;
5+
6+
#endif

contrib/pg_gtm/dtmd/include/parser.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef PARSER_H
2+
#define PARSER_H
3+
4+
#include <stdbool.h>
5+
6+
#include "int.h"
7+
8+
#define CMD_PREPARE 'p'
9+
#define CMD_COMMIT 'c'
10+
#define CMD_ABORT 'a'
11+
#define CMD_HORIZON 'h'
12+
#define CMD_STATUS 's'
13+
14+
typedef struct cmd_t {
15+
char cmd;
16+
cid_t arg;
17+
} cmd_t;
18+
19+
// Do not rely on the inner structure, it may change tomorrow.
20+
typedef struct parser_data_t *parser_t;
21+
22+
// Allocate and initialize a parser.
23+
parser_t parser_create();
24+
25+
// Destroy the parser. The 'p' handle becomes invalid, so do not refer to it
26+
// after destroying the parser.
27+
void parser_destroy(parser_t p);
28+
29+
// Initialize the parser.
30+
void parser_init(parser_t p);
31+
32+
// Check if parser has failed.
33+
bool parser_failed(parser_t p);
34+
35+
// Get the error message for the parser.
36+
char *parser_errormsg(parser_t p);
37+
38+
// Feeds a character to the parser, and returns a parsed command if it is
39+
// complete. Returns NULL if command is not complete. The caller should check
40+
// for errors, please use parser_failed() method for that. Also the caller
41+
// should free the cmd after use.
42+
cmd_t *parser_feed(parser_t p, char c);
43+
44+
#endif

contrib/pg_gtm/dtmd/include/util.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef UTIL_H
2+
#define UTIL_H
3+
4+
#if defined(__APPLE__)
5+
#define off64_t off_t
6+
#endif
7+
8+
#include <stdbool.h>
9+
#include <sys/stat.h>
10+
#include <fcntl.h>
11+
12+
#include "int.h"
13+
14+
char *join_path(const char *dir, const char *file);
15+
bool inrange(cid_t min, cid_t x, cid_t max);
16+
int falloc(int fd, off64_t size);
17+
18+
#define shout(...) \
19+
do { \
20+
fprintf(stderr, __VA_ARGS__); \
21+
fflush(stderr); \
22+
} while (0)
23+
24+
#endif

0 commit comments

Comments
 (0)