├── Makefile ├── readme.md └── pg_fix.c /Makefile: -------------------------------------------------------------------------------- 1 | # contrib/pg_fix/Makefile 2 | 3 | PGFILEDESC = "pg_fix - fix relation page" 4 | PGAPPICON = win32 5 | 6 | PROGRAM = pg_fix 7 | OBJS = pg_fix.o 8 | 9 | ifdef USE_PGXS 10 | PG_CONFIG = pg_config 11 | PGXS := $(shell $(PG_CONFIG) --pgxs) 12 | include $(PGXS) 13 | else 14 | subdir = contrib/pg_fix 15 | top_builddir = ../.. 16 | include $(top_builddir)/src/Makefile.global 17 | include $(top_srcdir)/contrib/contrib-global.mk 18 | endif 19 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## show tuple info in relation file 3 | 4 | ``` 5 | osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384 6 | lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid 7 | ---- ----- ----- ------ ---------- ---------- ---------- ----- ----- -------- --------- ---- ---------- 8 | 1 8152 1 33 1001 1002 0 0 3 2 4002 24 0 9 | 2 8112 1 33 1001 1002 0 0 4 2 4002 24 0 10 | 3 8072 1 33 1002 0 0 0 3 2002 8002 24 0 11 | 4 8032 1 33 1002 0 0 0 4 2002 8002 24 0 12 | ``` 13 | 14 | ## Clean hint in tuple 15 | 16 | first show tuple in replation file 16384: 17 | 18 | ``` 19 | osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384 20 | lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid 21 | ---- ----- ----- ------ ---------- ---------- ---------- ----- ----- -------- --------- ---- ---------- 22 | 1 8152 1 33 1001 1002 0 0 3 502 4002 24 0 23 | 2 8112 1 33 1001 1002 0 0 4 502 4002 24 0 24 | 3 8072 1 33 1002 0 0 0 3 2902 8002 24 0 25 | 4 8032 1 33 1002 0 0 0 4 2902 8002 24 0 26 | ``` 27 | 28 | then clean hint then show tuple info, please notice "infomask" colume: 29 | 30 | ``` 31 | osdba-mac:pg_fix osdba$ ./pg_fix clean_tuple_hint -f 16384 32 | osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384 33 | lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid 34 | ---- ----- ----- ------ ---------- ---------- ---------- ----- ----- -------- --------- ---- ---------- 35 | 1 8152 1 33 1001 1002 0 0 3 2 4002 24 0 36 | 2 8112 1 33 1001 1002 0 0 4 2 4002 24 0 37 | 3 8072 1 33 1002 0 0 0 3 2002 8002 24 0 38 | 4 8032 1 33 1002 0 0 0 4 2002 8002 24 0 39 | ``` 40 | 41 | ## Query transaction status in commit log and change 42 | 43 | 44 | query status of transaction: 45 | 46 | ``` 47 | osdba-mac:pg_fix osdba$ ./pg_fix get_xid_status -f 0000.bkk -x 11 48 | xid(11) status is 1(COMMITTED) 49 | ``` 50 | 51 | set status of transaction: 52 | 53 | ``` 54 | osdba-mac:pg_fix osdba$ ./pg_fix set_xid_status -f 0000.bkk -x 11 -s 0 55 | xid(11) status from 1(COMMITTED) change to 0(IN_PROGRESS) 56 | ``` 57 | -------------------------------------------------------------------------------- /pg_fix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * contrib/pagefix/pagefix.c 3 | * 4 | * 5 | * pagefix.c 6 | * 7 | * 8 | * Original author: osdba(TangCheng) 9 | * Current maintainer: osdba(TangCheng) 10 | */ 11 | 12 | #include "postgres.h" 13 | 14 | #include "access/htup_details.h" 15 | #include "utils/builtins.h" 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "pg_getopt.h" 26 | 27 | const char *progname; 28 | 29 | const char * report_bug_info = "Report bugs to osdba."; 30 | 31 | int 32 | clean_tuple_hint(char * heap_file, int page, int debug); 33 | 34 | int 35 | show_heap_file(char * heap_file, int page); 36 | 37 | int 38 | get_xid_status(char * commit_log_file, uint32 xid); 39 | 40 | int 41 | set_xid_status(char * commit_log_file, uint32 xid, unsigned char xid_status); 42 | 43 | int 44 | clean_tuple_hint(char * heap_file, int page, int debug) 45 | { 46 | char buf[BLCKSZ]; 47 | int fd; 48 | int ret; 49 | int cnt; 50 | int i; 51 | int blocks; 52 | ItemId id; 53 | uint16 lp_offset; 54 | uint16 lp_flags; 55 | uint16 lp_len; 56 | HeapTupleHeader tuphdr; 57 | 58 | 59 | fd = open(heap_file, O_RDWR); 60 | if (fd < 0) 61 | { 62 | fprintf(stderr, "Can not open %s", heap_file); 63 | perror(""); 64 | return 1; 65 | } 66 | 67 | blocks = 0; 68 | while(1) 69 | { 70 | if (page != -1) 71 | { 72 | ret = pread(fd, buf, BLCKSZ, BLCKSZ*page); 73 | } 74 | else 75 | { 76 | ret = pread(fd, buf, BLCKSZ, BLCKSZ*blocks); 77 | } 78 | if (ret == 0) 79 | { 80 | break; 81 | } 82 | if (ret < 0) 83 | { 84 | perror(""); 85 | break; 86 | } 87 | cnt = PageGetMaxOffsetNumber((Page)buf); 88 | for (i=0; i= sizeof(HeapTupleHeader) && 97 | lp_offset == MAXALIGN(lp_offset) && 98 | lp_offset + lp_len <= BLCKSZ)) 99 | { 100 | continue; 101 | } 102 | 103 | tuphdr = (HeapTupleHeader) PageGetItem((Page)buf, id); 104 | tuphdr->t_infomask &= (~HEAP_XMIN_COMMITTED); 105 | tuphdr->t_infomask &= (~HEAP_XMIN_INVALID); 106 | tuphdr->t_infomask &= (~HEAP_XMAX_COMMITTED); 107 | tuphdr->t_infomask &= (~HEAP_XMAX_INVALID); 108 | ret = pwrite(fd, buf, 8192, 8192*blocks); 109 | } 110 | 111 | if (page != -1) 112 | { 113 | break; 114 | } 115 | 116 | blocks++; 117 | } 118 | close(fd); 119 | return 0; 120 | } 121 | 122 | 123 | int 124 | show_heap_file(char * heap_file, int page) 125 | { 126 | char buf[BLCKSZ]; 127 | int fd; 128 | int ret; 129 | int cnt; 130 | int i; 131 | int blocks; 132 | ItemId id; 133 | uint16 lp_offset; 134 | uint16 lp_flags; 135 | uint16 lp_len; 136 | HeapTupleHeader tuphdr; 137 | 138 | 139 | fd = open(heap_file, O_RDONLY); 140 | if (fd < 0) 141 | { 142 | fprintf(stderr, "Can not open %s", heap_file); 143 | perror(""); 144 | return 1; 145 | } 146 | 147 | // "%4d %5d %5d %6d %10u %10u %10u %5u %5u %8x %9x %4u %10u\n 148 | printf(" lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid\n"); 149 | printf("---- ----- ----- ------ ---------- ---------- ---------- ----- ----- -------- --------- ---- ----------\n"); 150 | 151 | blocks = 0; 152 | while(1) 153 | { 154 | if (page != -1) 155 | { 156 | ret = pread(fd, buf, BLCKSZ, BLCKSZ*page); 157 | } 158 | else 159 | { 160 | ret = pread(fd, buf, BLCKSZ, BLCKSZ*blocks); 161 | } 162 | if (ret == 0) 163 | { 164 | break; 165 | } 166 | if (ret < 0) 167 | { 168 | perror(""); 169 | break; 170 | } 171 | cnt = PageGetMaxOffsetNumber((Page)buf); 172 | for (i=0; i= sizeof(HeapTupleHeader) && 180 | lp_offset == MAXALIGN(lp_offset) && 181 | lp_offset + lp_len <= BLCKSZ)) 182 | { 183 | continue; 184 | } 185 | tuphdr = (HeapTupleHeader) PageGetItem((Page)buf, id); 186 | 187 | /* "lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid"*/ 188 | printf("%4d %5d %5d %6d %10u %10u %10u %5u %5u %8x %9x %4u %10u\n", 189 | i+1, 190 | lp_offset, 191 | lp_flags, 192 | lp_len, 193 | tuphdr->t_choice.t_heap.t_xmin, 194 | tuphdr->t_choice.t_heap.t_xmax, 195 | tuphdr->t_choice.t_heap.t_field3.t_cid, 196 | (uint32)tuphdr->t_ctid.ip_blkid.bi_hi*65536 + tuphdr->t_ctid.ip_blkid.bi_lo, 197 | tuphdr->t_ctid.ip_posid, 198 | tuphdr->t_infomask, 199 | tuphdr->t_infomask2, 200 | tuphdr->t_hoff, 201 | HeapTupleHeaderGetOid(tuphdr) 202 | ); 203 | } 204 | 205 | if (page != -1) 206 | { 207 | break; 208 | } 209 | 210 | blocks++; 211 | } 212 | close(fd); 213 | return 0; 214 | } 215 | 216 | static const char * 217 | xid_status_to_str( unsigned char xid_status) 218 | { 219 | /* 事务有四种状态 220 | #define TRANSACTION_STATUS_IN_PROGRESS 0x00 221 | #define TRANSACTION_STATUS_COMMITTED 0x01 222 | #define TRANSACTION_STATUS_ABORTED 0x02 223 | #define TRANSACTION_STATUS_SUB_COMMITTED 0x03 224 | */ 225 | switch(xid_status) 226 | { 227 | case 0: 228 | return "IN_PROGRESS"; 229 | case 1: 230 | return "COMMITTED"; 231 | case 2: 232 | return "ABORTED"; 233 | case 3: 234 | return "SUB_COMMITTED"; 235 | default: 236 | return "INVALID"; 237 | } 238 | } 239 | 240 | int 241 | set_xid_status(char * commit_log_file, uint32 xid, unsigned char xid_status) 242 | { 243 | char buf[512]; 244 | int fd; 245 | int ret; 246 | uint32 position; 247 | uint32 blocks; 248 | uint32 offset; 249 | uint32 bit_off; 250 | unsigned char tmp_ch1, tmp_ch2; 251 | unsigned char old_status; 252 | 253 | fd = open(commit_log_file, O_RDWR); 254 | if (fd < 0) 255 | { 256 | fprintf(stderr, "Can not open %s", commit_log_file); 257 | perror(""); 258 | return 1; 259 | } 260 | 261 | position = xid / 4; 262 | blocks = position / 512; 263 | offset = position % 512; 264 | bit_off = (xid % 4)*2; 265 | 266 | memset(buf, 0, 512); 267 | ret = pread(fd, buf, 512, blocks*512); 268 | if (ret < 0) 269 | { 270 | fprintf(stderr, "Can not read file %s in offset %u", commit_log_file, blocks*512); 271 | perror(""); 272 | return 1; 273 | } 274 | 275 | /* 下面把指定位置bit_off,bit_off+1的两位设置为指定的状态值xid_status, 276 | * 方法为,先生成tmp_ch1,tmp_ch1的值为除要设置的两位为真实的状态值外,其它bit都为1的, 277 | * 再生成tmp_ch2,tmp_ch2的值为除要设置的两bit位全为1外,其它bit为原先的值 278 | * 最后,把tmp_ch1与tmp_ch2做位与计算就所bit_off位置的两个bit值设置为了指定的状态了。 279 | */ 280 | /*下面的操作之后,bit_off+1之前的位都置为了1t,bit_off-1后的位都为0,bit_off到bit_off+1的两位保存了原状态值*/ 281 | tmp_ch1 = (xid_status | 0xFC) << bit_off; 282 | /*(0xFF >>(8 - bit_off))的结果是bit_off之后的位都为1了*/ 283 | tmp_ch1 = tmp_ch1 | (0xFF >>(8 - bit_off)); 284 | 285 | /*把tmp_ch2中要设置的两位变为1外,其它不变*/ 286 | tmp_ch2= buf[offset]; 287 | tmp_ch2 |= (1 << bit_off | 1 << (bit_off + 1)); 288 | 289 | old_status = buf[offset]; 290 | old_status >>= bit_off; 291 | old_status &= 3; 292 | 293 | //printf("xid=%u, pre byte=%x, tmp_ch1=%x, tmp_ch2=%x\n", xid, buf[offset], tmp_ch1, tmp_ch2); 294 | buf[offset] = tmp_ch1 & tmp_ch2; 295 | //printf("xid=%u, byte=%x\n", xid, buf[offset]); 296 | 297 | ret = pwrite(fd, buf, 512, blocks*512); 298 | close(fd); 299 | printf("xid(%u) status from %x(%s) change to %x(%s)\n", 300 | xid, 301 | old_status, xid_status_to_str(old_status), 302 | xid_status, xid_status_to_str(xid_status)); 303 | return 0; 304 | } 305 | 306 | int 307 | get_xid_status(char * commit_log_file, uint32 xid) 308 | { 309 | char buf[512]; 310 | int fd; 311 | int ret; 312 | uint32 position; 313 | uint32 blocks; 314 | uint32 offset; 315 | uint32 bit_off; 316 | unsigned char tmp_ch; 317 | 318 | fd = open(commit_log_file, O_RDWR); 319 | if (fd < 0) 320 | { 321 | fprintf(stderr, "Can not open %s", commit_log_file); 322 | perror(""); 323 | return 1; 324 | } 325 | 326 | position = xid / 4; 327 | blocks = position / 512; 328 | offset = position % 512; 329 | bit_off = (xid % 4)*2; 330 | memset(buf, 0, 512); 331 | ret = pread(fd, buf, 512, blocks*512); 332 | if (ret < 0) 333 | { 334 | fprintf(stderr, "Can not read file %s in offset %u", commit_log_file, blocks*512); 335 | perror(""); 336 | return 1; 337 | } 338 | close(fd); 339 | 340 | tmp_ch = buf[offset]; 341 | tmp_ch = tmp_ch >> bit_off; 342 | tmp_ch = tmp_ch & 3; 343 | printf("xid(%u) status is %u(%s)\n", xid, tmp_ch, xid_status_to_str(tmp_ch)); 344 | return 0; 345 | } 346 | 347 | 348 | 349 | static void 350 | help_show_tuple(void) 351 | { 352 | printf("Usage:\n"); 353 | printf(" %s show_tuple [OPTION]\n", progname); 354 | printf("\nOptions:\n"); 355 | printf(" -f \n" 356 | " specifies relation file\n"); 357 | printf(" -p \n" 358 | " Specifies the page of relation file\n"); 359 | printf(" -h\n" 360 | " show this help, the exit\n"); 361 | printf("\n%s\n", report_bug_info); 362 | } 363 | 364 | static int 365 | cmd_show_tuple(int argc, char * argv[]) 366 | { 367 | int c; 368 | char *heap_file = NULL; 369 | int page = -1; 370 | 371 | while ((c = getopt(argc-1, &argv[1], "hf:p:")) != -1) 372 | { 373 | switch (c) 374 | { 375 | case 'h': 376 | help_show_tuple(); 377 | return 0; 378 | case 'f': 379 | heap_file = optarg; 380 | break; 381 | case 'p': 382 | page = atoi(optarg); 383 | break; 384 | default: 385 | fprintf(stderr, 386 | "Try \"%s %s --help\" for more information.\n", 387 | progname, argv[1]); 388 | return 2; 389 | break; 390 | } 391 | } 392 | if (argc == 2) 393 | { 394 | fprintf(stderr, 395 | "%s %s : not enough command-line arguments\n", 396 | progname, argv[1]); 397 | return 2; 398 | } 399 | return show_heap_file(heap_file, page); 400 | } 401 | 402 | static void 403 | help_clean_tuple_hint(void) 404 | { 405 | printf("Usage:\n"); 406 | printf(" %s clean_tuple_hint [OPTION]\n", progname); 407 | printf("\nOptions:\n"); 408 | printf(" -f \n" 409 | " specifies relation file\n"); 410 | printf(" -d\n" 411 | " Output debug information\n"); 412 | printf(" -p \n" 413 | " Specifies the page of relation file\n"); 414 | printf(" -h\n" 415 | " show this help, the exit\n"); 416 | printf("\n%s\n", report_bug_info); 417 | } 418 | 419 | static int 420 | cmd_clean_tuple_hint(int argc, char * argv[]) 421 | { 422 | int c; 423 | char *heap_file = NULL; 424 | int page = -1; 425 | int debug = 0; 426 | 427 | while ((c = getopt(argc-1, &argv[1], "dhf:p:")) != -1) 428 | { 429 | switch (c) 430 | { 431 | case 'h': 432 | help_clean_tuple_hint(); 433 | return 0; 434 | case 'd': 435 | debug = 1; 436 | break; 437 | case 'f': 438 | heap_file = optarg; 439 | break; 440 | case 'p': 441 | page = atoi(optarg); 442 | break; 443 | default: 444 | fprintf(stderr, 445 | "Try \"%s %s -h\" for more information.\n", 446 | progname, argv[1]); 447 | return 2; 448 | break; 449 | } 450 | } 451 | if (argc == 2) 452 | { 453 | fprintf(stderr, 454 | "%s %s : not enough command-line arguments\n", 455 | progname, argv[1]); 456 | return 2; 457 | } 458 | return clean_tuple_hint(heap_file, page, debug); 459 | } 460 | 461 | static void 462 | help_set_xid_status(void) 463 | { 464 | printf("Usage:\n"); 465 | printf(" %s set_xid_status [OPTION]\n", progname); 466 | printf("\nOptions:\n"); 467 | printf(" -f \n" 468 | " specify commit log file\n"); 469 | printf(" -x \n" 470 | " Specifies xid that you want to change it's status\n"); 471 | printf(" -s \n" 472 | " Specifies the status of xid you want to set\n"); 473 | printf(" -h show this help, then exit\n" 474 | " show this help, the exit\n"); 475 | printf("\n%s\n", report_bug_info); 476 | } 477 | 478 | static int 479 | cmd_set_xid_status(int argc, char * argv[]) 480 | { 481 | int c; 482 | char *commit_log_file = NULL; 483 | uint32 xid = 0; 484 | int xid_status = 0; 485 | 486 | while ((c = getopt(argc-1, &argv[1], "hf:x:s:")) != -1) 487 | { 488 | switch (c) 489 | { 490 | case 'h': 491 | help_set_xid_status(); 492 | return 0; 493 | case 'f': 494 | commit_log_file = optarg; 495 | break; 496 | case 'x': 497 | xid = atoi(optarg); 498 | break; 499 | case 's': 500 | xid_status = atoi(optarg); 501 | break; 502 | default: 503 | fprintf(stderr, 504 | "Try \"%s %s --help\" for more information.\n", 505 | progname, argv[1]); 506 | return 2; 507 | break; 508 | } 509 | } 510 | if (argc == 2) 511 | { 512 | fprintf(stderr, 513 | "%s %s : not enough command-line arguments\n", 514 | progname, argv[1]); 515 | return 2; 516 | } 517 | return set_xid_status(commit_log_file, xid, xid_status); 518 | } 519 | 520 | static void 521 | help_get_xid_status(void) 522 | { 523 | printf("Usage:\n"); 524 | printf(" %s get_xid_status [OPTION]\n", progname); 525 | printf("\nOptions:\n"); 526 | printf(" -f \n" 527 | " specify commit log file\n"); 528 | printf(" -x \n" 529 | " Specifies xid that you want to get it's status\n"); 530 | printf(" -h show this help, then exit\n" 531 | " show this help, the exit\n"); 532 | printf("\n%s\n", report_bug_info); 533 | } 534 | 535 | static int 536 | cmd_get_xid_status(int argc, char * argv[]) 537 | { 538 | int c; 539 | char *commit_log_file = NULL; 540 | uint32 xid = 0; 541 | 542 | while ((c = getopt(argc-1, &argv[1], "hf:x:")) != -1) 543 | { 544 | switch (c) 545 | { 546 | case 'h': 547 | help_get_xid_status(); 548 | return 0; 549 | case 'f': 550 | commit_log_file = optarg; 551 | break; 552 | case 'x': 553 | xid = atoi(optarg); 554 | break; 555 | default: 556 | fprintf(stderr, 557 | "Try \"%s %s --help\" for more information.\n", 558 | progname, argv[1]); 559 | return 2; 560 | break; 561 | } 562 | } 563 | if (argc == 2) 564 | { 565 | fprintf(stderr, 566 | "%s %s : not enough command-line arguments\n", 567 | progname, argv[1]); 568 | return 2; 569 | } 570 | return get_xid_status(commit_log_file, xid); 571 | } 572 | 573 | static void 574 | usage(void) 575 | { 576 | printf("Usage:\n"); 577 | printf(" %s [OPTION]\n", progname); 578 | printf("\ncmd:\n" 579 | " show_tuple: show tuples in a relation\n" 580 | " clean_tuple_hint: clean hint in tuple\n" 581 | " get_xid_status: get status of xid\n" 582 | " set_xid_status: set status of xid\n"); 583 | printf("\nOptions:\n"); 584 | printf(" -h: show this cmd help, then exit\n"); 585 | printf("\n%s\n", report_bug_info); 586 | } 587 | 588 | /*------------ MAIN ----------------------------------------*/ 589 | int 590 | main(int argc, char **argv) 591 | { 592 | progname = get_progname(argv[0]); 593 | 594 | if (argc == 1) 595 | { 596 | usage(); 597 | exit(0); 598 | } 599 | else if (argc == 2) 600 | { 601 | if (strcmp(argv[1], "--help") == 0 602 | || strcmp(argv[1], "-?") == 0 603 | || strcmp(argv[1], "-h") == 0) 604 | { 605 | usage(); 606 | exit(0); 607 | } 608 | if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) 609 | { 610 | puts("pg_fix (PostgreSQL) " PG_VERSION); 611 | exit(0); 612 | } 613 | } 614 | 615 | if (!strcmp(argv[1], "show_tuple")) 616 | { 617 | return cmd_show_tuple(argc, argv); 618 | } 619 | else if (!strcmp(argv[1], "clean_tuple_hint")) 620 | { 621 | return cmd_clean_tuple_hint(argc, argv); 622 | } 623 | else if (!strcmp(argv[1], "get_xid_status")) 624 | { 625 | return cmd_get_xid_status(argc, argv); 626 | } 627 | else if (!strcmp(argv[1], "set_xid_status")) 628 | { 629 | return cmd_set_xid_status(argc, argv); 630 | } 631 | else 632 | { 633 | fprintf(stderr, "Unknown command %s\n", argv[1]); 634 | } 635 | return 0; 636 | } 637 | --------------------------------------------------------------------------------