-
Notifications
You must be signed in to change notification settings - Fork 849
/
log.c
135 lines (114 loc) · 3.29 KB
/
log.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* This file and its contents are licensed under the Apache License 2.0.
* Please see the included NOTICE for copyright information and
* LICENSE-APACHE for a copy of the license.
*/
#include <postgres.h>
#include <access/xact.h>
#include <catalog/namespace.h>
#include <postmaster/bgworker.h>
#include <storage/proc.h>
#include <utils/builtins.h>
#include <utils/lsyscache.h>
#include "log.h"
#include "params.h"
#include "scanner.h"
#include "ts_catalog/catalog.h"
#include "utils.h"
#include "compat/compat.h"
static char *bgw_application_name = "unset";
void
ts_bgw_log_set_application_name(char *name)
{
bgw_application_name = name;
}
static bool
bgw_log_insert_relation(Relation rel, char *msg)
{
TupleDesc desc = RelationGetDescr(rel);
static int32 msg_no = 0;
Datum values[4];
bool nulls[4] = { false, false, false };
values[0] = Int32GetDatum(msg_no++);
values[1] = Int64GetDatum((int64) ts_params_get()->current_time);
values[2] = CStringGetTextDatum(bgw_application_name);
values[3] = CStringGetTextDatum(msg);
ts_catalog_insert_values(rel, desc, values, nulls);
return true;
}
/* Insert a new entry into public.bgw_log
* This table is used for testing as a way for mock background jobs
* to insert messages into a log that could then be output into the golden file
*/
static void
bgw_log_insert(char *msg)
{
Relation rel;
Oid log_oid = ts_get_relation_relid("public", "bgw_log", false);
rel = table_open(log_oid, RowExclusiveLock);
bgw_log_insert_relation(rel, msg);
table_close(rel, RowExclusiveLock);
}
static emit_log_hook_type prev_emit_log_hook = NULL;
/*
* NOTE: using transactions in emit_log_hook functions is not recommended.
* However we rely on this current functionality for our test verifications,
* so have to live with it for now.
*/
static void
emit_log_hook_callback(ErrorData *edata)
{
/*
* once proc_exit has started we may no longer be able to start transactions
*/
if (MyProc == NULL)
return;
/*
* Block signals so we don't lose messages generated during signal
* processing if they occur while we are saving this log message (since
* emit_log_hook is modified and restored below)
*/
BackgroundWorkerBlockSignals();
PG_TRY();
{
/*
* If we do encounter some error writing to our log hook, remove the
* hook to prevent potentially infinite recursion where this callback
* keeps encountering an error, and it is its own logging callback. We
* reinstall the hook when we're successfully done with this function.
*/
emit_log_hook = NULL;
bool started_txn = false;
if (!IsTransactionState())
{
StartTransactionCommand();
started_txn = true;
}
bgw_log_insert(edata->message);
if (started_txn)
CommitTransactionCommand();
if (prev_emit_log_hook != NULL)
prev_emit_log_hook(edata);
/* Reinstall the hook if log was successful. */
emit_log_hook = emit_log_hook_callback;
}
PG_CATCH();
{
/* If there was an error, rollback what was done before the error */
if (IsTransactionState())
AbortCurrentTransaction();
/*
* Reinstall the hook because we are out of the main body of the
* function.
*/
emit_log_hook = emit_log_hook_callback;
}
PG_END_TRY();
BackgroundWorkerUnblockSignals();
}
void
ts_register_emit_log_hook()
{
prev_emit_log_hook = emit_log_hook;
emit_log_hook = emit_log_hook_callback;
}