Hacking PostgreSQL. Локальная память процессов. Контексты...

36
www.postgrespro.ru ЛОКАЛЬНАЯ ПАМЯТЬ ПРОЦЕССОВ Hacking PostgreSQL 28.04.2016

Transcript of Hacking PostgreSQL. Локальная память процессов. Контексты...

Page 1: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

www.postgrespro.ru

ЛОКАЛЬНАЯ ПАМЯТЬ ПРОЦЕССОВ

Hacking PostgreSQL

28.04.2016

Page 2: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

2

Содержание

1.Создание процесса

2.SysCache

3.PlanCache

4.MemoryContexts

5.work_mem

6.maintenance_work_mem

Page 3: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

3

Память в PostgreSQL

Page 4: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

4

Page 5: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

5

Локальная память

src/include/utils/

src/include/storage/proc.h

src/backend/utils/cache

attoptcache.c catcache.c evtcache.c inval.c lsyscache.c

plancache.c relcache.c relfilenodemap.c relmapper.c

spccache.c syscache.c ts_cache.c typcache.c

src/backend/utils/mmgr

src/backend/storage/lmgr/proc.c

src/backend/utils/init/postinit.c

Page 6: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

6

EXEC_BACKEND

src/backend/main/main.c

main()startup_hacks(); //Platform-specific startup hacks

#ifdef EXEC_BACKENDif (argc > 1 && strncmp(argv[1], "--fork", 6) == 0)SubPostmasterMain(argc, argv);

#endif

if (argc > 1 && strcmp(argv[1], "--boot") == 0)AuxiliaryProcessMain(argc, argv);

else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0)GucInfoMain();

else if (argc > 1 && strcmp(argv[1], "--single") == 0)PostgresMain(argc, argv,

NULL, /* no dbname */ Strdup(get_user_name_or_exit(progname)));else

PostmasterMain(argc, argv);

Page 7: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

7

Создание процесса

PostgresMain()InitProcess() //инициализировать структуру PGPROC для процесса

InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);

InitProcessPhase2(); //добавить запись PGPROC в ProcArrayProcSignalInit(MyBackendId); //добавить запись в ProcSignalRegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeoutHandler);

RelationCacheInitialize(); //хэш-таблица RelationIdCacheInitCatalogCache(); //массив CatCache *SysCache[SysCacheSize]InitPlanCache(); //регистрация callback-функций

RelationCacheInitializePhase2(); //кэшировать записи основных глобальных //таблиц каталога

...

Page 8: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

8

Чтение данных каталога в кэш

RelationCacheInitializePhase2()RelationMapInitializePhase2() //загрузить данные из pg_filenode.map

if (!load_relcache_init_file(true)) //пытаемся прочитать pg_internal.init {formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true, true, Natts_pg_database, Desc_pg_database);formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true, true, Natts_pg_authid, Desc_pg_authid);formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true, false, Natts_pg_auth_members, Desc_pg_auth_members);formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true, false, Natts_pg_shseclabel, Desc_pg_shseclabel);}

Page 9: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

9

Чтение данных каталога в кэш

load_relcache_init_file() //пытаемся прочитать pg_internal.init

for (relno = 0; relno < num_rels; relno++){

//вставить запись в хэш-таблицу RelationIdCacheRelationCacheInsert(rels[relno], false);

}

formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true, true, Natts_pg_database, Desc_pg_database);

//Создать новый дескриптор relation//инициализировать без обращения к каталогу//вставить запись в хэш-таблицу RelationIdCache RelationCacheInsert(relation, false);

Page 10: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

10

Page 11: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

11

Создание процесса (продолжение)

PostgresMain()InitProcess() //инициализировать структуру PGPROC для процесса

InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);

...

RelationCacheInitializePhase2(); //кэшировать основные глобальные //таблицы каталога

PerformAuthentication(); //выполнить аутентификацию клиента

MyProc->databaseId = MyDatabaseId; //Подключиться к базеSetDatabasePath(fullpath);

RelationCacheInitializePhase3(); //кэшировать таблицы и индексы каталога

Page 12: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

12

Чтение данных каталога в кэш

RelationCacheInitializePhase3()

if(!load_relcache_init_file(false)) //пытаемся прочитать pg_internal.init{formrdesc("pg_class", RelationRelation_Rowtype_Id, false, true, Natts_pg_class, Desc_pg_class);formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false, false, Natts_pg_attribute, Desc_pg_attribute);formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false, true, Natts_pg_proc, Desc_pg_proc);formrdesc("pg_type", TypeRelation_Rowtype_Id, false, true, Natts_pg_type, Desc_pg_type);}

load_critical_index() //загружаем критические индексы

//обновляем и дополняем все записи RelationIdCache

InitCatalogCachePhase2(); //завершаем инициализацию массива SysCacheCatalogCacheInitializeCache()

Page 13: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

13

SysCache

src/backend/utils/cache/lsyscache.c

char *get_attname(Oid relid, AttrNumber attnum);Oid get_atttype(Oid relid, AttrNumber attnum);

Oid get_commutator(Oid opno);Oid get_negator(Oid opno);

char *get_func_name(Oid funcid);Oid get_func_rettype(Oid funcid);bool func_strict(Oid funcid);char func_volatile(Oid funcid);

Page 14: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

14

Инвалидация кэша

src/include/storage/sinval.hsrc/backend/utils/cache/inval.c

CacheInvalidateCatalog(Oid catalogId) //после CLUSTER TABLE pg_*CacheInvalidateRelcache(Relation relation) //например, DROP INDEX

src/backend/utils/cache/catcache.c

CatalogCacheIdInvalidate(int cacheId, uint32 hashValue) //удалить записи из кэша

src/backend/commands/cluster.cswap_relation_files() //Пример инвалидации кэша

Page 15: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

15

Page 16: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

16

Prepared statements

PREPARE usrrptplan (int) AS SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid AND l.date = $2;

EXECUTE usrrptplan(1, current_date);

select * from pg_prepared_statements;

name | usrrptplanstatement | PREPARE usrrptplan (int) AS + | SELECT * FROM users u, logs l WHERE u.usrid=$1 AND u.usrid=l.usrid+ | AND l.date = $2;prepare_time | 2016-04-28 13:42:57.3563+03parameter_types | {integer,"time without time zone"}from_sql | t

Page 17: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

17

Plan cache

src/include/utils/plancache.hsrc/backend/utils/cache/plancache.c

CreateCachedPlan()CompleteCachedPlan()

SaveCachedPlan() //перенести план в долгоживущий контекст памяти

DropCachedPlan() //удалить сохранённый план

choose_custom_plan() //выбор между обобщенным и конкретным планом

BuildCachedPlan() //построить обобщённый или конкретный план //из сохраненной информации

Page 18: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

18

Page 19: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

19

Memory Context API

src/include/nodes/memnodes.h

typedef struct MemoryContextData{

NodeTag type; // всегда T_AllocSetContexbool isReset;bool allowInCritSection;MemoryContextMethods *methods;MemoryContext parent;MemoryContext firstchild;MemoryContext prevchild;MemoryContext nextchild;char *name; // Имя контекста. Для отладкиMemoryContextCallback *reset_cbs;

} MemoryContextData;

Page 20: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

20

Дерево контекстов

Context

firstchild

parent

nextchild. . .

. . .

. . .

Page 21: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

21

Memory Context Methods

src/include/nodes/memnodes.h

typedef struct MemoryContextMethods{

void *(*alloc) (MemoryContext context, Size size);/* call this free_p in case someone #define's free() */void (*free_p) (MemoryContext context, void *pointer);void *(*realloc) (MemoryContext context, void *pointer, Size size);void (*init) (MemoryContext context);void (*reset) (MemoryContext context);void (*delete_context) (MemoryContext context);Size (*get_chunk_space) (MemoryContext context, void *pointer);bool (*is_empty) (MemoryContext context);void (*stats) (MemoryContext context, int level, bool print, MemoryContextCounters *totals);

#ifdef MEMORY_CONTEXT_CHECKINGvoid (*check) (MemoryContext context);

#endif} MemoryContextMethods;

Page 22: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

22

AllocSetMethods

src/backend/utils/mmgr/aset.c

static MemoryContextMethods AllocSetMethods = {AllocSetAlloc,AllocSetFree,AllocSetRealloc,AllocSetInit,AllocSetReset,AllocSetDelete,AllocSetGetChunkSpace,AllocSetIsEmpty,AllocSetStats

#ifdef MEMORY_CONTEXT_CHECKING,AllocSetCheck

#endif};

Page 23: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

23

Контексты

src/include/utils/memutils.hsrc/backend/utils/mmgr/README

TopMemoryContext; //Корень дерева контекстовErrorContext;PostmasterContext;CacheMemoryContext;MessageContext;TopTransactionContext;CurTransactionContext;

CurrentMemoryContext;

Page 24: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

24

Переключение контекстов

src/backend/utils/mmgr/mcxt.c

MemoryContext tempContext = AllocSetContextCreate(….);MemoryContext saveContext = MemoryContextSwitchTo(tempContext);

/* делаем что-то в новом контексте */char * x = palloc(128);char * y = palloc(256);. . . . . . . . . . . . . . . . . .

MemoryContextSwitchTo(saveContext);MemoryContextDelete(tempContext);

Page 25: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

25

AllocSetContext

src/backend/utils/mmgr/aset.c

typedef struct AllocSetContext{

MemoryContextData header; /* Standard memory-context fields */

AllocBlock blocks; /* head of list of blocks in this set */AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */

Size initBlockSize;Size maxBlockSize;Size nextBlockSize; /* next block size to allocate */Size allocChunkLimit;AllocBlock keeper;

} AllocSetContext;

Page 26: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

26

AllocBlock

src/backend/utils/mmgr/aset.c

typedef struct AllocBlockData{

AllocSet aset; /* aset that owns this block */AllocBlock next; /* next block in aset's blocks list */char *freeptr; /* start of free space in this block */char *endptr; /* end of space in this block */

} AllocBlockData;

MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize);

Page 27: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

27

blocks

header

header

bloc

ks

data free

header data

header data

header data

Page 28: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

28

AllocChunk

src/backend/utils/mmgr/aset.c

typedef struct AllocChunkData{

/* aset is the owning aset if allocated, or the freelist link if free */void *aset;/* size is always the size of the usable space in the chunk */Size size;

#ifdef MEMORY_CONTEXT_CHECKING/* when debugging memory usage, also store actual requested size */

Size requested_size;#endif} AllocChunkData;

Page 29: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

29

chunks

header data free

1 2 3 4 5

Page 30: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

30

palloc

header data free

1 2 3 4 5

6

Page 31: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

31

palloc

header data free

1 2 3 4 5 6

Page 32: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

32

pfree

1 2 3 4 5 6

freelist[]

Page 33: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

33

Источники потерь

● Выделение множества мелких кусочков памяти

– сопоставимых с заголовком чанка (16 байт)

● Выделение кусочков размера 2N + o

● Создание множества контекстов под мелкие запросы

● Увеличение размера выделенной памяти (repalloc)

Page 34: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

34

Настройки памяти

● work_mem● maintenance_work_mem● autovacuum_work_mem● replacement_sort_tuples

Page 35: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

35

Источники

● Introduction to MemoryContexts by Tomas Vondra

● Examples of palloc overhead by Tomas Vondra

● Sorting Through The Ages

Page 36: Hacking PostgreSQL. Локальная память процессов. Контексты памяти.

www.postgrespro.ru

СПАСИБО ЗА ВНИМАНИЕ! ВОПРОСЫ?

Hacking PostgreSQL

28.04.2016

[email protected]