Skip to content

Commit 6753a2c

Browse files
authored
Merge pull request #9 from CherkashinSergey/add_xact_support
Add xact support optimization
2 parents f807d8f + bf7c420 commit 6753a2c

File tree

3 files changed

+85
-32
lines changed

3 files changed

+85
-32
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,15 @@ SELECT pgv_get('pack','var_int', NULL::int);
335335
ERROR: unrecognized variable "var_int"
336336
COMMIT;
337337
```
338+
Also you cannot undo removing variable by `ROLLBACK`:
339+
```sql
340+
SELECT pgv_set('pack', 'var_int', 122, true);
341+
BEGIN;
342+
SELECT pgv_free();
343+
ROLLBACK;
344+
SELECT pgv_get('pack', 'var_int', NULL::int);
345+
ERROR: unrecognized package "pack"
346+
```
338347
If you created transactional variable once, you should use flag `is_transactional`
339348
every time when you want to change variable value by functions `pgv_set()`,
340349
`pgv_insert()` and deprecated setters (i.e. `pgv_set_int()`). If you try to

pg_variables.c

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ static HashVariableEntry *createVariableInternal(HashPackageEntry *package,
7676
text *name, Oid typid,
7777
bool is_transactional);
7878
static void createSavepoint(HashPackageEntry *package, HashVariableEntry *variable);
79-
static bool isVarChangedInTrans(HashVariableEntry *variable);
79+
static bool isVarChangedInCurrentTrans(HashVariableEntry *variable);
80+
static bool isVarChangedInUpperTrans(HashVariableEntry *variable);
8081
static void addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable);
8182

8283
#define CHECK_ARGS_FOR_NULL() \
@@ -100,12 +101,11 @@ static HashPackageEntry *LastPackage = NULL;
100101
static HashVariableEntry *LastVariable = NULL;
101102

102103
/*
103-
* List of variables, changed in top level transaction. Used to limit
104+
* Stack of lists of variables, changed in each transaction level. Used to limit
104105
* number of proceeded variables on start of transaction.
105106
*/
106-
static dlist_head *changedVars = NULL;
107-
static MemoryContext changedVarsContext = NULL;
108107
static dlist_head *changedVarsStack = NULL;
108+
static MemoryContext changedVarsContext = NULL;
109109
#define get_actual_changed_vars_list() \
110110
((dlist_head_element(ChangedVarsStackNode, node, changedVarsStack))-> \
111111
changedVarsList)
@@ -621,7 +621,7 @@ variable_insert(PG_FUNCTION_ARGS)
621621
errmsg("variable \"%s\" already created as %sTRANSACTIONAL",
622622
key, LastVariable->is_transactional ? "" : "NOT ")));
623623
}
624-
if (!isVarChangedInTrans(variable) && variable->is_transactional)
624+
if (!isVarChangedInCurrentTrans(variable) && variable->is_transactional)
625625
{
626626
createSavepoint(package, variable);
627627
addToChangedVars(package, variable);
@@ -707,7 +707,7 @@ variable_update(PG_FUNCTION_ARGS)
707707
else
708708
variable = LastVariable;
709709

710-
if (variable->is_transactional && !isVarChangedInTrans(variable))
710+
if (variable->is_transactional && !isVarChangedInCurrentTrans(variable))
711711
{
712712
createSavepoint(package, variable);
713713
addToChangedVars(package, variable);
@@ -785,7 +785,7 @@ variable_delete(PG_FUNCTION_ARGS)
785785
else
786786
variable = LastVariable;
787787

788-
if (variable->is_transactional && !isVarChangedInTrans(variable))
788+
if (variable->is_transactional && !isVarChangedInCurrentTrans(variable))
789789
{
790790
createSavepoint(package, variable);
791791
addToChangedVars(package, variable);
@@ -1220,7 +1220,7 @@ remove_packages(PG_FUNCTION_ARGS)
12201220

12211221
packagesHash = NULL;
12221222
ModuleContext = NULL;
1223-
changedVars = NULL;
1223+
changedVarsStack = NULL;
12241224

12251225
PG_RETURN_VOID();
12261226
}
@@ -1663,7 +1663,7 @@ createVariableInternal(HashPackageEntry *package, text *name, Oid typid,
16631663
* For each transaction level there should be own savepoint.
16641664
* New value should be stored in a last state.
16651665
*/
1666-
if (variable->is_transactional && !isVarChangedInTrans(variable))
1666+
if (variable->is_transactional && !isVarChangedInCurrentTrans(variable))
16671667
{
16681668
createSavepoint(package, variable);
16691669
}
@@ -1769,6 +1769,11 @@ releaseSavepoint(HashVariableEntry *variable)
17691769
dlist_delete(nodeToDelete);
17701770
pfree(historyEntryToDelete);
17711771
}
1772+
/*
1773+
* If variable was changed in subtransaction, so it is considered it
1774+
* was changed in parent transaction.
1775+
*/
1776+
(get_actual_value(variable)->level)--;
17721777
}
17731778

17741779
/*
@@ -1792,22 +1797,32 @@ rollbackSavepoint(HashPackageEntry *package, HashVariableEntry *variable)
17921797
* Check if variable was changed in current transaction level
17931798
*/
17941799
static bool
1795-
isVarChangedInTrans(HashVariableEntry *variable)
1800+
isVarChangedInCurrentTrans(HashVariableEntry *variable)
17961801
{
1797-
dlist_iter iter;
1798-
dlist_head *changedVars;
1802+
ValueHistoryEntry *var_state;
17991803

18001804
if (!changedVarsStack)
18011805
return false;
18021806

1803-
changedVars = get_actual_changed_vars_list();
1804-
dlist_foreach(iter, changedVars)
1805-
{
1806-
ChangedVarsNode *cvn;
1807+
var_state = get_actual_value(variable);
1808+
return (var_state->level == GetCurrentTransactionNestLevel());
1809+
}
18071810

1808-
cvn = dlist_container(ChangedVarsNode, node, iter.cur);
1809-
if (cvn->variable == variable)
1810-
return true;
1811+
/*
1812+
* Check if variable was changed in parent transaction level
1813+
*/
1814+
static bool
1815+
isVarChangedInUpperTrans(HashVariableEntry *variable)
1816+
{
1817+
ValueHistoryEntry *var_state,
1818+
*var_prev_state;
1819+
1820+
var_state = get_actual_value(variable);
1821+
1822+
if(dlist_has_next(&variable->data, &var_state->node))
1823+
{
1824+
var_prev_state = get_history_entry(var_state->node.next);
1825+
return (var_prev_state->level == (GetCurrentTransactionNestLevel() - 1));
18111826
}
18121827
return false;
18131828
}
@@ -1890,12 +1905,12 @@ popChangedVarsStack()
18901905
{
18911906
if (changedVarsStack)
18921907
{
1893-
ChangedVarsStackNode *cvse;
1908+
ChangedVarsStackNode *cvsn;
18941909

18951910
Assert(!dlist_is_empty(changedVarsStack));
1896-
cvse = dlist_container(ChangedVarsStackNode, node,
1911+
cvsn = dlist_container(ChangedVarsStackNode, node,
18971912
dlist_pop_head_node(changedVarsStack));
1898-
MemoryContextDelete(cvse->ctx);
1913+
MemoryContextDelete(cvsn->ctx);
18991914
if (dlist_is_empty(changedVarsStack))
19001915
{
19011916
MemoryContextDelete(changedVarsContext);
@@ -1905,6 +1920,20 @@ popChangedVarsStack()
19051920
}
19061921
}
19071922

1923+
/*
1924+
* Initialize an instance of ChangedVarsNode datatype
1925+
*/
1926+
static inline ChangedVarsNode *
1927+
initChangedVarsNode(MemoryContext ctx, HashPackageEntry *package, HashVariableEntry *variable)
1928+
{
1929+
ChangedVarsNode *cvn;
1930+
1931+
cvn = MemoryContextAllocZero(ctx, sizeof(ChangedVarsNode));
1932+
cvn->package = package;
1933+
cvn->variable = variable;
1934+
return cvn;
1935+
}
1936+
19081937
/*
19091938
* Add a variable to list of changed vars in current transaction level
19101939
*/
@@ -1925,20 +1954,19 @@ addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable)
19251954

19261955
Assert(changedVarsStack && changedVarsContext);
19271956

1928-
if (!isVarChangedInTrans(variable))
1957+
if (!isVarChangedInCurrentTrans(variable))
19291958
{
19301959
ChangedVarsNode *cvn;
19311960

19321961
cvsn = dlist_head_element(ChangedVarsStackNode, node, changedVarsStack);
1933-
cvn = MemoryContextAllocZero(cvsn->ctx, sizeof(ChangedVarsNode));
1934-
cvn->package = package;
1935-
cvn->variable = variable;
1962+
cvn = initChangedVarsNode(cvsn->ctx, package, variable);
19361963
dlist_push_head(cvsn->changedVarsList, &cvn->node);
1964+
get_actual_value(cvn->variable)->level = GetCurrentTransactionNestLevel();
19371965
}
19381966
}
19391967

19401968
/*
1941-
* If variable was chenged in some subtransaction, it is considered that it was
1969+
* If variable was changed in some subtransaction, it is considered that it was
19421970
* changed in parent transaction. So it is important to add this variable to
19431971
* list of changes of parent transaction. But if var was already changed in
19441972
* upper level, it has savepoint there, so we need to release it.
@@ -1957,13 +1985,25 @@ levelUpOrRelease()
19571985
Assert(!dlist_is_empty(changedVarsStack));
19581986
dlist_foreach(iter, bottom_list->changedVarsList)
19591987
{
1960-
ChangedVarsNode *cvn;
1988+
ChangedVarsNode *cvn_old;
19611989

1962-
cvn = dlist_container(ChangedVarsNode, node, iter.cur);
1963-
if (isVarChangedInTrans(cvn->variable))
1964-
releaseSavepoint(cvn->variable);
1990+
cvn_old = dlist_container(ChangedVarsNode, node, iter.cur);
1991+
if (isVarChangedInUpperTrans(cvn_old->variable))
1992+
releaseSavepoint(cvn_old->variable);
19651993
else
1966-
addToChangedVars(cvn->package, cvn->variable);
1994+
{
1995+
ChangedVarsNode *cvn_new;
1996+
ChangedVarsStackNode *cvsn;
1997+
1998+
/*
1999+
* Impossible to push in upper list existing node because
2000+
* it was created in another context
2001+
*/
2002+
cvsn = dlist_head_element(ChangedVarsStackNode, node, changedVarsStack);
2003+
cvn_new = initChangedVarsNode(cvsn->ctx, cvn_old->package, cvn_old->variable);
2004+
dlist_push_head(cvsn->changedVarsList, &cvn_new->node);
2005+
(get_actual_value(cvn_new->variable)->level)--;
2006+
}
19672007
}
19682008
MemoryContextDelete(bottom_list->ctx);
19692009
}

pg_variables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ typedef struct ValueHistoryEntry{
6868
ScalarVar scalar;
6969
RecordVar record;
7070
} value;
71+
/* Transaction nest level of current entry */
72+
int level;
7173
} ValueHistoryEntry;
7274

7375
typedef dlist_head ValueHistory;
@@ -139,6 +141,8 @@ extern void insert_savepoint(HashVariableEntry *variable,
139141
(&((dlist_head_element(ValueHistoryEntry, node, &variable->data))->value.scalar))
140142
#define get_actual_value_record(variable) \
141143
(&((dlist_head_element(ValueHistoryEntry, node, &variable->data))->value.record))
144+
#define get_actual_value(variable) \
145+
(dlist_head_element(ValueHistoryEntry, node, &variable->data))
142146
#define get_history_entry(node_ptr) \
143147
dlist_container(ValueHistoryEntry, node, node_ptr)
144148

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy