|
7 | 7 | importtime |
8 | 8 |
|
9 | 9 | fromshutilimportrmtree |
10 | | -fromsiximportraise_from,iteritems |
| 10 | +fromsiximportraise_from,iteritems,text_type |
11 | 11 | fromtempfileimportmkstemp,mkdtemp |
12 | 12 |
|
13 | 13 | from .enumsimport \ |
|
38 | 38 | PG_PID_FILE |
39 | 39 |
|
40 | 40 | from .constsimport \ |
41 | | -MAX_WAL_SENDERS, \ |
| 41 | +MAX_LOGICAL_REPLICATION_WORKERS, \ |
42 | 42 | MAX_REPLICATION_SLOTS, \ |
| 43 | +MAX_WORKER_PROCESSES, \ |
| 44 | +MAX_WAL_SENDERS, \ |
43 | 45 | WAL_KEEP_SEGMENTS |
44 | 46 |
|
45 | 47 | from .decoratorsimport \ |
@@ -329,25 +331,27 @@ def _create_recovery_conf(self, username, slot=None): |
329 | 331 | # Connect to master for some additional actions |
330 | 332 | withmaster.connect(username=username)ascon: |
331 | 333 | # check if slot already exists |
332 | | -res=con.execute(""" |
| 334 | +res=con.execute( |
| 335 | +""" |
333 | 336 | select exists ( |
334 | 337 | select from pg_catalog.pg_replication_slots |
335 | 338 | where slot_name = %s |
336 | 339 | ) |
337 | | - """,slot) |
| 340 | +""",slot) |
338 | 341 |
|
339 | 342 | ifres[0][0]: |
340 | 343 | raiseTestgresException( |
341 | 344 | "Slot '{}' already exists".format(slot)) |
342 | 345 |
|
343 | 346 | # TODO: we should drop this slot after replica's cleanup() |
344 | | -con.execute(""" |
| 347 | +con.execute( |
| 348 | +""" |
345 | 349 | select pg_catalog.pg_create_physical_replication_slot(%s) |
346 | | - """,slot) |
| 350 | +""",slot) |
347 | 351 |
|
348 | 352 | line+="primary_slot_name={}\n".format(slot) |
349 | 353 |
|
350 | | -self.append_conf(RECOVERY_CONF_FILE,line) |
| 354 | +self.append_conf(filename=RECOVERY_CONF_FILE,line=line) |
351 | 355 |
|
352 | 356 | def_maybe_start_logger(self): |
353 | 357 | iftestgres_config.use_python_logging: |
@@ -475,65 +479,79 @@ def get_auth_method(t): |
475 | 479 |
|
476 | 480 | # overwrite config file |
477 | 481 | withio.open(postgres_conf,"w")asconf: |
478 | | -# remove old lines |
479 | 482 | conf.truncate() |
480 | 483 |
|
481 | | -ifnotfsync: |
482 | | -conf.write(u"fsync = off\n") |
| 484 | +self.append_conf(fsync=fsync, |
| 485 | +max_worker_processes=MAX_WORKER_PROCESSES, |
| 486 | +log_statement=log_statement, |
| 487 | +listen_addresses=self.host, |
| 488 | +port=self.port)# yapf:disable |
483 | 489 |
|
484 | | -conf.write(u"log_statement = {}\n" |
485 | | -u"listen_addresses = '{}'\n" |
486 | | -u"port = {}\n".format(log_statement, |
487 | | -self.host, |
488 | | -self.port))# yapf: disable |
| 490 | +# common replication settings |
| 491 | +ifallow_streamingorallow_logical: |
| 492 | +self.append_conf(max_replication_slots=MAX_REPLICATION_SLOTS, |
| 493 | +max_wal_senders=MAX_WAL_SENDERS)# yapf: disable |
489 | 494 |
|
490 | | -# replication-related settings |
491 | | -ifallow_streaming: |
| 495 | +# binary replication |
| 496 | +ifallow_streaming: |
| 497 | +# select a proper wal_level for PostgreSQL |
| 498 | +wal_level='replica'ifself._pg_version>='9.6'else'hot_standby' |
492 | 499 |
|
493 | | -# select a proper wal_level for PostgreSQL |
494 | | -ifself._pg_version>='9.6': |
495 | | -wal_level="replica" |
496 | | -else: |
497 | | -wal_level="hot_standby" |
498 | | - |
499 | | -conf.write(u"hot_standby = on\n" |
500 | | -u"max_wal_senders = {}\n" |
501 | | -u"max_replication_slots = {}\n" |
502 | | -u"wal_keep_segments = {}\n" |
503 | | -u"wal_level = {}\n".format(MAX_WAL_SENDERS, |
504 | | -MAX_REPLICATION_SLOTS, |
505 | | -WAL_KEEP_SEGMENTS, |
506 | | -wal_level))# yapf: disable |
507 | | - |
508 | | -ifallow_logical: |
509 | | -ifself._pg_version<'10': |
510 | | -raiseInitNodeException( |
511 | | -"Logical replication is only available for Postgres 10 " |
512 | | -"and newer") |
513 | | -conf.write(u"wal_level = logical\n") |
514 | | - |
515 | | -# disable UNIX sockets if asked to |
516 | | -ifnotunix_sockets: |
517 | | -conf.write(u"unix_socket_directories = ''\n") |
| 500 | +self.append_conf(hot_standby=True, |
| 501 | +wal_keep_segments=WAL_KEEP_SEGMENTS, |
| 502 | +wal_level=wal_level)# yapf: disable |
| 503 | + |
| 504 | +# logical replication |
| 505 | +ifallow_logical: |
| 506 | +ifself._pg_version<'10': |
| 507 | +raiseInitNodeException("Logical replication is only " |
| 508 | +"available on PostgreSQL 10 and newer") |
| 509 | + |
| 510 | +self.append_conf( |
| 511 | +max_logical_replication_workers=MAX_LOGICAL_REPLICATION_WORKERS, |
| 512 | +wal_level='logical') |
| 513 | + |
| 514 | +# disable UNIX sockets if asked to |
| 515 | +ifnotunix_sockets: |
| 516 | +self.append_conf(unix_socket_directories='') |
518 | 517 |
|
519 | 518 | returnself |
520 | 519 |
|
521 | 520 | @method_decorator(positional_args_hack(['filename','line'])) |
522 | | -defappend_conf(self,line,filename=PG_CONF_FILE): |
| 521 | +defappend_conf(self,line='',filename=PG_CONF_FILE,**kwargs): |
523 | 522 | """ |
524 | 523 | Append line to a config file. |
525 | 524 |
|
526 | 525 | Args: |
527 | 526 | line: string to be appended to config. |
528 | 527 | filename: config file (postgresql.conf by default). |
| 528 | + **kwargs: named config options. |
529 | 529 |
|
530 | 530 | Returns: |
531 | 531 | This instance of :class:`.PostgresNode`. |
| 532 | +
|
| 533 | + Examples: |
| 534 | + append_conf(fsync=False) |
| 535 | + append_conf('log_connections = yes') |
| 536 | + append_conf('postgresql.conf', 'synchronous_commit = off') |
532 | 537 | """ |
533 | 538 |
|
| 539 | +lines= [line] |
| 540 | + |
| 541 | +foroption,valueiniteritems(kwargs): |
| 542 | +ifisinstance(value,bool): |
| 543 | +value='on'ifvalueelse'off' |
| 544 | +elifnotstr(value).replace('.','',1).isdigit(): |
| 545 | +value="'{}'".format(value) |
| 546 | + |
| 547 | +# format a new config line |
| 548 | +lines.append('{} = {}'.format(option,value)) |
| 549 | + |
534 | 550 | config_name=os.path.join(self.data_dir,filename) |
535 | 551 | withio.open(config_name,'a')asconf: |
536 | | -conf.write(u''.join([line,'\n'])) |
| 552 | +forlineinlines: |
| 553 | +conf.write(text_type(line)) |
| 554 | +conf.write(text_type('\n')) |
537 | 555 |
|
538 | 556 | returnself |
539 | 557 |
|
|