aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/parser/pg_wrapper/arena_ctx.cpp
blob: e91cd6ad7a2a7dd43aa7b099fd952135d1f01b50 (plain) (blame)
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
136
137
138
139
140
#include "arena_ctx.h"
#include <util/generic/yexception.h>

#define TypeName PG_TypeName
#define SortBy PG_SortBy
#undef SIZEOF_SIZE_T
extern "C" {
#include "postgres.h"
#include "nodes/memnodes.h"
#include "utils/memutils.h"
#include "utils/memutils_internal.h"
}

namespace NYql {

struct TArenaPAllocHeader {
    size_t Size;
    ui64 Self; // should be placed right before pointer to allocated area, see GetMemoryChunkContext
};

static_assert(sizeof(TArenaPAllocHeader) == sizeof(size_t) + sizeof(MemoryContext), "Padding is not allowed");

extern "C" {
extern void *ArenaAlloc(MemoryContext context, Size size);
extern void ArenaFree(void *pointer);
extern void *ArenaRealloc(void *pointer, Size size);
extern void ArenaReset(MemoryContext context);
extern void ArenaDelete(MemoryContext context);
extern MemoryContext ArenaGetChunkContext(void *pointer);
extern Size ArenaGetChunkSpace(void *pointer);
extern bool ArenaIsEmpty(MemoryContext context);
extern void ArenaStats(MemoryContext context,
						  MemoryStatsPrintFunc printfunc, void *passthru,
						  MemoryContextCounters *totals,
						  bool print_to_stderr);
#ifdef MEMORY_CONTEXT_CHECKING
extern void ArenaCheck(MemoryContext context);
#endif
}

extern "C" void *ArenaAlloc(MemoryContext context, Size size) {
    Y_UNUSED(context);
    auto fullSize = size + MAXIMUM_ALIGNOF - 1 + sizeof(TArenaPAllocHeader);
    auto ptr = TArenaMemoryContext::GetCurrentPool().Allocate(fullSize);
    auto aligned = (TArenaPAllocHeader*)MAXALIGN(ptr + sizeof(TArenaPAllocHeader));
    Y_ENSURE((ui64(context) & MEMORY_CONTEXT_METHODID_MASK) == 0);
    aligned[-1].Self = ui64(context) | MCTX_UNUSED2_ID;
    aligned[-1].Size = size;
    return aligned;
}

extern "C" void ArenaFree(void* pointer) {
    Y_UNUSED(pointer);
}

extern "C" void* ArenaRealloc(void* pointer, Size size) {
    if (!size) {
        return nullptr;
    }

    void* ret = ArenaAlloc(nullptr, size);
    if (pointer) {
        auto prevSize = ((const TArenaPAllocHeader*)pointer)[-1].Size;
        memmove(ret, pointer, prevSize);
    }

    return ret;
}

extern "C" void ArenaReset(MemoryContext context) {
    Y_UNUSED(context);
}

extern "C" void ArenaDelete(MemoryContext context) {
    Y_UNUSED(context);
}

extern "C" MemoryContext ArenaGetChunkContext(void *pointer) {
    return (MemoryContext)(((ui64*)pointer)[-1] & ~MEMORY_CONTEXT_METHODID_MASK);
}

extern "C" Size ArenaGetChunkSpace(void* pointer) {
    Y_UNUSED(pointer);
    return 0;
}

extern "C" bool ArenaIsEmpty(MemoryContext context) {
    Y_UNUSED(context);
    return false;
}

extern "C" void ArenaStats(MemoryContext context,
    MemoryStatsPrintFunc printfunc, void *passthru,
    MemoryContextCounters *totals,
    bool print_to_stderr) {
    Y_UNUSED(context);
    Y_UNUSED(printfunc);
    Y_UNUSED(passthru);
    Y_UNUSED(totals);
    Y_UNUSED(print_to_stderr);
}

extern "C" void ArenaCheck(MemoryContext context) {
    Y_UNUSED(context);
}

__thread TArenaMemoryContext* TArenaMemoryContext::Current = nullptr;

TArenaMemoryContext::TArenaMemoryContext() {
    MyContext = (MemoryContext)malloc(sizeof(MemoryContextData));
    static_assert(MEMORY_CONTEXT_METHODID_MASK < sizeof(void*));
    MemoryContextCreate(MyContext,
        T_AllocSetContext,
        MCTX_UNUSED2_ID,
        nullptr,
        "arena");
    Acquire();
}

TArenaMemoryContext::~TArenaMemoryContext() {
    MemoryContextDeleteChildren(MyContext);
    Release();
    free(MyContext);
}

void TArenaMemoryContext::Acquire() {
    PrevContext = CurrentMemoryContext;
    CurrentMemoryContext = MyContext;
    Prev = Current;
    Current = this;
}

void TArenaMemoryContext::Release() {
    CurrentMemoryContext = PrevContext;
    PrevContext = nullptr;
    Current = Prev;
    Prev = nullptr;
}

}