<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="generator" content="Asciidoctor 2.0.16"> <meta name="author" content="Perforce Professional Services"> <title>Perforce Helix Server Deployment Package (for Windows)</title> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"> <style> /*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */ /* Uncomment the following line when using as a custom stylesheet */ /* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */ html{font-family:sans-serif;-webkit-text-size-adjust:100%} a{background:none} a:focus{outline:thin dotted} a:active,a:hover{outline:0} h1{font-size:2em;margin:.67em 0} b,strong{font-weight:bold} abbr{font-size:.9em} abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none} dfn{font-style:italic} hr{height:0} mark{background:#ff0;color:#000} code,kbd,pre,samp{font-family:monospace;font-size:1em} pre{white-space:pre-wrap} q{quotes:"\201C" "\201D" "\2018" "\2019"} small{font-size:80%} sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} audio,video{display:inline-block} audio:not([controls]){display:none;height:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} button,input{line-height:normal} button,select{text-transform:none} button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} input[type=checkbox],input[type=radio]{padding:0} button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} textarea{overflow:auto;vertical-align:top} table{border-collapse:collapse;border-spacing:0} *,::before,::after{box-sizing:border-box} html,body{font-size:100%} body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased} a:hover{cursor:pointer} img,object,embed{max-width:100%;height:auto} object,embed{height:100%} img{-ms-interpolation-mode:bicubic} .left{float:left!important} .right{float:right!important} .text-left{text-align:left!important} .text-right{text-align:right!important} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} img,object,svg{display:inline-block;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0} a{color:#2156a5;text-decoration:underline;line-height:inherit} a:hover,a:focus{color:#1d4b8f} a img{border:0} p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} p aside{font-size:.875em;line-height:1.35;font-style:italic} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} h1{font-size:2.125em} h2{font-size:1.6875em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} h4,h5{font-size:1.125em} h6{font-size:1em} hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em} em,i{font-style:italic;line-height:inherit} strong,b{font-weight:bold;line-height:inherit} small{font-size:60%;line-height:inherit} code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} ul,ol{margin-left:1.5em} ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0} ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} ul.square{list-style-type:square} ul.circle{list-style-type:circle} ul.disc{list-style-type:disc} ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} dl dt{margin-bottom:.3125em;font-weight:bold} dl dd{margin-bottom:1.25em} blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} @media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} h1{font-size:2.75em} h2{font-size:2.3125em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} h4{font-size:1.4375em}} table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal} table thead,table tfoot{background:#f7f8f7} table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} table tr.even,table tr.alt{background:#f8f8f7} table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} .center{margin-left:auto;margin-right:auto} .stretch{width:100%} .clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table} .clearfix::after,.float-group::after{clear:both} :not(pre).nobreak{word-wrap:normal} :not(pre).nowrap{white-space:nowrap} :not(pre).pre-wrap{white-space:pre-wrap} :not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed} pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit} pre>code{display:block} pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal} em em{font-style:normal} strong strong{font-weight:400} .keyseq{color:rgba(51,51,51,.8)} kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menuref{color:#000} .menuseq b:not(.caret),.menuref{font-weight:inherit} .menuseq{word-spacing:-.02em} .menuseq b.caret{font-size:1.25em;line-height:.8} .menuseq i.caret{font-weight:bold;text-align:center;width:.45em} b.button::before,b.button::after{position:relative;top:-1px;font-weight:400} b.button::before{content:"[";padding:0 3px 0 2px} b.button::after{content:"]";padding:0 2px 0 3px} p a>code:hover{color:rgba(0,0,0,.9)} #header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} #header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table} #header::after,#content::after,#footnotes::after,#footer::after{clear:both} #content{margin-top:1.25em} #content::before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf} #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px} #header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} #header .details br{display:none} #header .details br+span::before{content:"\00a0\2013\00a0"} #header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} #header .details br+span#revremark::before{content:"\00a0|\00a0"} #header #revnumber{text-transform:capitalize} #header #revnumber::after{content:"\00a0"} #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} #toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em} #toc>ul{margin-left:.125em} #toc ul.sectlevel0>li>a{font-style:italic} #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} #toc li{line-height:1.3334;margin-top:.3334em} #toc a{text-decoration:none} #toc a:active{text-decoration:underline} #toctitle{color:#7a2518;font-size:1.2em} @media screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} #toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} #toc.toc2 ul ul{margin-left:0;padding-left:1em} #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} body.toc2.toc-right{padding-left:0;padding-right:15em} body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}} @media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} #toc.toc2{width:20em} #toc.toc2 #toctitle{font-size:1.375em} #toc.toc2>ul{font-size:.95em} #toc.toc2 ul ul{padding-left:1.25em} body.toc2.toc-right{padding-left:0;padding-right:20em}} #content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px} #content #toc>:first-child{margin-top:0} #content #toc>:last-child{margin-bottom:0} #footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em} #footer-text{color:hsla(0,0%,100%,.8);line-height:1.44} #content{margin-bottom:.625em} .sect1{padding-bottom:.625em} @media screen and (min-width:768px){#content{margin-bottom:1.25em} .sect1{padding-bottom:1.25em}} .sect1:last-child{padding-bottom:0} .sect1+.sect1{border-top:1px solid #e7e7e9} #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400} #content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} details{margin-left:1.25rem} details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;-webkit-tap-highlight-color:transparent} details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)} details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)} details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem} .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} table.tableblock.fit-content>caption.title{white-space:nowrap;width:0} .paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)} .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} .admonitionblock>table td.icon{text-align:center;width:80px} .admonitionblock>table td.icon img{max-width:none} .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere} .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} .exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px} .exampleblock>.content>:first-child{margin-top:0} .exampleblock>.content>:last-child{margin-bottom:0} .sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px} .sidebarblock>:first-child{margin-top:0} .sidebarblock>:last-child{margin-bottom:0} .sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center} .exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} .literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em} @media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}} @media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}} .literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8} .literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)} .listingblock>.content{position:relative} .listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5} .listingblock:hover code[data-lang]::before{display:block} .listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5} .listingblock.terminal pre .command:not([data-prompt])::before{content:"$"} .listingblock pre.highlightjs{padding:0} .listingblock pre.highlightjs>code{padding:1em;border-radius:4px} .listingblock pre.prettyprint{border-width:0} .prettyprint{background:#f7f7f8} pre.prettyprint .linenums{line-height:1.45;margin-left:2em} pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0} pre.prettyprint li code[data-lang]::before{opacity:1} pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none} table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none} table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal} table.linenotable td.code{padding-left:.75em} table.linenotable td.linenos{border-right:1px solid;opacity:.35;padding-right:.5em} pre.pygments .lineno{border-right:1px solid;opacity:.35;display:inline-block;margin-right:.75em} pre.pygments .lineno::before{content:"";margin-right:-.125em} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em} .quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} .quoteblock blockquote{margin:0;padding:0;border:0} .quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} .quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right} .verseblock{margin:0 1em 1.25em} .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} .verseblock pre strong{font-weight:400} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none} .quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0} .quoteblock.abstract{margin:0 1em 1.25em;display:block} .quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center} .quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf} .quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0} .quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem} .quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0} p.tableblock:last-child{margin-bottom:0} td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere} td.tableblock>.content>:last-child{margin-bottom:-1.25em} table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} table.grid-all>*>tr>*{border-width:1px} table.grid-cols>*>tr>*{border-width:0 1px} table.grid-rows>*>tr>*{border-width:1px 0} table.frame-all{border-width:1px} table.frame-ends{border-width:1px 0} table.frame-sides{border-width:0 1px} table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0} table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0} table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0} table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0} table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7} th.halign-left,td.halign-left{text-align:left} th.halign-right,td.halign-right{text-align:right} th.halign-center,td.halign-center{text-align:center} th.valign-top,td.valign-top{vertical-align:top} th.valign-bottom,td.valign-bottom{vertical-align:bottom} th.valign-middle,td.valign-middle{vertical-align:middle} table thead th,table tfoot th{font-weight:bold} tbody tr th{background:#f7f8f7} tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold} p.tableblock>code:only-child{background:none;padding:0} p.tableblock{font-size:1em} ol{margin-left:1.75em} ul li ol{margin-left:1.5em} dl dd{margin-left:1.125em} dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none} ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em} ul.unstyled,ol.unstyled{margin-left:0} ul.checklist>li>p:first-child{margin-left:-1em} ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em} ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em} ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em} ul.inline>li{margin-left:1.25em} .unstyled dl dt{font-weight:400;font-style:normal} ol.arabic{list-style-type:decimal} ol.decimal{list-style-type:decimal-leading-zero} ol.loweralpha{list-style-type:lower-alpha} ol.upperalpha{list-style-type:upper-alpha} ol.lowerroman{list-style-type:lower-roman} ol.upperroman{list-style-type:upper-roman} ol.lowergreek{list-style-type:lower-greek} .hdlist>table,.colist>table{border:0;background:none} .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} td.hdlist1{font-weight:bold;padding-bottom:1.25em} td.hdlist2{word-wrap:anywhere} .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} .colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top} .colist td:not([class]):first-child img{max-width:none} .colist td:not([class]):last-child{padding:.25em 0} .thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd} .imageblock.left{margin:.25em .625em 1.25em 0} .imageblock.right{margin:.25em 0 1.25em .625em} .imageblock>.title{margin-bottom:0} .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em} #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em} #footnotes .footnote:last-of-type{margin-bottom:0} #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} .gist .file-data>table td.line-data{width:99%} div.unbreakable{page-break-inside:avoid} .big{font-size:larger} .small{font-size:smaller} .underline{text-decoration:underline} .overline{text-decoration:overline} .line-through{text-decoration:line-through} .aqua{color:#00bfbf} .aqua-background{background:#00fafa} .black{color:#000} .black-background{background:#000} .blue{color:#0000bf} .blue-background{background:#0000fa} .fuchsia{color:#bf00bf} .fuchsia-background{background:#fa00fa} .gray{color:#606060} .gray-background{background:#7d7d7d} .green{color:#006000} .green-background{background:#007d00} .lime{color:#00bf00} .lime-background{background:#00fa00} .maroon{color:#600000} .maroon-background{background:#7d0000} .navy{color:#000060} .navy-background{background:#00007d} .olive{color:#606000} .olive-background{background:#7d7d00} .purple{color:#600060} .purple-background{background:#7d007d} .red{color:#bf0000} .red-background{background:#fa0000} .silver{color:#909090} .silver-background{background:#bcbcbc} .teal{color:#006060} .teal-background{background:#007d7d} .white{color:#bfbfbf} .white-background{background:#fafafa} .yellow{color:#bfbf00} .yellow-background{background:#fafa00} span.icon>.fa{cursor:default} a span.icon>.fa{cursor:inherit} .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} .admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c} .admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} .admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000} .conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]::after{content:attr(data-value)} pre .conum[data-value]{position:relative;top:-.125em} b.conum *{color:inherit!important} .conum:not([data-value]):empty{display:none} dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em} p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} p,blockquote,dt,td.content,span.alt,summary{font-size:1.0625rem} p{margin-bottom:1.25rem} .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} .exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc} .print-only{display:none!important} @page{margin:1.25cm .75cm} @media print{*{box-shadow:none!important;text-shadow:none!important} html{font-size:80%} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} abbr[title]{border-bottom:1px dotted} abbr[title]::after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} thead{display:table-header-group} svg{max-width:100%} p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #header,#content,#footnotes,#footer{max-width:none} #toc,.sidebarblock,.exampleblock>.content{background:none!important} #toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em} body.book #header .details{border:0!important;display:block;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} body.book #header .details br{display:block} body.book #header .details br+span::before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} .listingblock code[data-lang]::before{display:block} #footer{padding:0 .9375em} .hide-on-print{display:none!important} .print-only{display:block!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} @media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem} .sect1{padding:0!important} .sect1+.sect1{border:0} #footer{background:none} #footer-text{color:rgba(0,0,0,.6);font-size:.9em}} @media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}} </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> </head> <body class="book"> <div id="header"> <h1>Perforce Helix Server Deployment Package (for Windows)</h1> <div class="details"> <span id="author" class="author">Perforce Professional Services</span><br> <span id="email" class="email"><a href="mailto:consulting@perforce.com">consulting@perforce.com</a></span><br> <span id="revnumber">version v2021.1,</span> <span id="revdate">2021-11-09</span> </div> <div id="toc" class="toc"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> <li><a href="#_preface">Preface</a></li> <li><a href="#_overview">1. Overview</a> <ul class="sectlevel2"> <li><a href="#_windows_sdp_vs_unix_sdp">1.1. Windows SDP vs Unix SDP</a></li> <li><a href="#_downloading_sdp">1.2. Downloading SDP</a></li> <li><a href="#_checking_the_sdp_version">1.3. Checking the SDP Version</a></li> </ul> </li> <li><a href="#_configuring_the_perforce_server">2. Configuring the Perforce Server</a> <ul class="sectlevel2"> <li><a href="#_volume_layout_and_hardware">2.1. Volume Layout and Hardware</a></li> <li><a href="#_instance_names">2.2. Instance Names</a></li> </ul> </li> <li><a href="#_installing_the_perforce_server_and_the_sdp">3. Installing the Perforce Server and the SDP</a> <ul class="sectlevel2"> <li><a href="#_clean_installation">3.1. Clean Installation</a> <ul class="sectlevel3"> <li><a href="#_pre_requisites">3.1.1. Pre-requisites</a></li> <li><a href="#_configuring_powershell">3.1.2. Configuring Powershell</a></li> <li><a href="#_initial_setup">3.1.3. Initial setup</a></li> <li><a href="#_running_configuration_script">3.1.4. Running Configuration script</a></li> <li><a href="#_sdp_config_ini">3.1.5. sdp_config.ini</a></li> <li><a href="#_installing_services">3.1.6. Installing service(s)</a></li> <li><a href="#_start_the_server_to_test">3.1.7. Start the server to test</a></li> <li><a href="#_create_p4admin_shortcuts">3.1.8. Create P4Admin Shortcuts</a> <ul class="sectlevel4"> <li><a href="#_create_the_promptsetup_bat_file">3.1.8.1. Create the <code>PromptSetup.bat</code> File</a></li> <li><a href="#_create_the_shortcut">3.1.8.2. Create the Shortcut</a></li> </ul> </li> <li><a href="#_applying_configurables_to_the_server_instance">3.1.9. Applying configurables to the server instance</a></li> <li><a href="#_configuring_the_server">3.1.10. Configuring the server</a></li> <li><a href="#_verifying_your_server_installation">3.1.11. Verifying your server installation</a></li> <li><a href="#_scheduling_maintenance_scripts">3.1.12. Scheduling maintenance scripts</a> <ul class="sectlevel4"> <li><a href="#_daily_backup_bat">3.1.12.1. Daily-backup.bat</a> <ul class="sectlevel5"> <li><a href="#_task_basics">Task Basics</a></li> <li><a href="#_trigger_screen">Trigger screen</a></li> <li><a href="#_action">Action</a></li> </ul> </li> </ul> </li> <li><a href="#_saving_your_configuration_files_in_perforce">3.1.13. Saving your configuration files in Perforce</a></li> <li><a href="#_archiving_configuration_files">3.1.14. Archiving configuration files</a></li> <li><a href="#_configuring_a_new_instance_on_an_existing_machine">3.1.15. Configuring a New Instance on an existing machine</a></li> <li><a href="#_upgrading_an_existing_non_sdp_windows_installation">3.1.16. Upgrading an existing (non SDP) Windows installation</a></li> <li><a href="#_upgrading_an_older_windows_sdp_installation">3.1.17. Upgrading an older Windows SDP installation</a></li> <li><a href="#_configuring_protections_file_types_monitoring_and_security">3.1.18. Configuring protections, file types, monitoring and security</a></li> </ul> </li> <li><a href="#_general_sdp_usage">3.2. General SDP Usage</a></li> </ul> </li> <li><a href="#_backup_replication_and_recovery">4. Backup, Replication, and Recovery</a> <ul class="sectlevel2"> <li><a href="#_typical_backup_procedure">4.1. Typical Backup Procedure</a></li> <li><a href="#_planning_for_ha_and_dr">4.2. Planning for HA and DR</a> <ul class="sectlevel3"> <li><a href="#_further_resources">4.2.1. Further Resources</a></li> <li><a href="#_creating_a_failover_replica_for_commit_or_edge_server">4.2.2. Creating a Failover Replica for Commit or Edge Server</a></li> <li><a href="#_what_is_a_failover_replica">4.2.3. What is a Failover Replica?</a></li> <li><a href="#_mandatory_vs_non_mandatory_standbys">4.2.4. Mandatory vs Non-mandatory Standbys</a></li> <li><a href="#_server_host_naming_conventions">4.2.5. Server host naming conventions</a></li> <li><a href="#_pre_requisites_for_failover">4.2.6. Pre-requisites for Failover</a></li> </ul> </li> <li><a href="#_full_one_way_replication">4.3. Full One-Way Replication</a> <ul class="sectlevel3"> <li><a href="#_replication_setup">4.3.1. Replication Setup</a></li> </ul> </li> <li><a href="#_replication_setup_details">4.4. Replication Setup Details</a></li> <li><a href="#_recovery_procedures">4.5. Recovery Procedures</a> <ul class="sectlevel3"> <li><a href="#_recovering_from_a_checkpoint_and_journals">4.5.1. Recovering from a checkpoint and journal(s)</a></li> <li><a href="#_recovering_from_a_tape_backup">4.5.2. Recovering from a tape backup</a></li> <li><a href="#_failover_to_a_replicated_standby_machine">4.5.3. Failover to a replicated standby machine</a></li> </ul> </li> </ul> </li> <li><a href="#_server_maintenance">5. Server Maintenance</a> <ul class="sectlevel2"> <li><a href="#_server_upgrades">5.1. Server upgrades</a> <ul class="sectlevel3"> <li><a href="#_database_modifications">5.1.1. Database Modifications</a></li> <li><a href="#_unloading_and_reloading_labels">5.1.2. Unloading and Reloading labels</a></li> <li><a href="#_workspace_management">5.1.3. Workspace management</a></li> <li><a href="#_removing_empty_changelists">5.1.4. Removing empty changelists</a></li> </ul> </li> </ul> </li> <li><a href="#_maximizing_server_performance">6. Maximizing Server Performance</a> <ul class="sectlevel2"> <li><a href="#_optimizing_the_database_files">6.1. Optimizing the database files</a></li> <li><a href="#_managing_server_load">6.2. Managing server load</a> <ul class="sectlevel3"> <li><a href="#_limiting_large_requests">6.2.1. Limiting large requests</a></li> <li><a href="#_offloading_remote_syncs">6.2.2. Offloading remote syncs</a></li> </ul> </li> <li><a href="#_p4v_performance_settings">6.3. P4V performance settings</a></li> </ul> </li> <li><a href="#_tools_and_scripts">7. Tools and Scripts</a> <ul class="sectlevel2"> <li><a href="#_standard_scripts">7.1. Standard scripts</a></li> <li><a href="#_core_scripts">7.2. Core scripts</a> <ul class="sectlevel3"> <li><a href="#_daily_backup_ps1">7.2.1. daily-backup.ps1</a></li> <li><a href="#_p4verify_ps1">7.2.2. p4verify.ps1</a></li> </ul> </li> <li><a href="#_other_scripts_and_tools">7.3. Other scripts and tools</a> <ul class="sectlevel3"> <li><a href="#_create_filtered_edge_checkpoint_ps1">7.3.1. create-filtered-edge-checkpoint.ps1</a></li> <li><a href="#_create_offline_db_from_checkpoint_ps1">7.3.2. create-offline-db-from-checkpoint.ps1</a></li> <li><a href="#_grep_exe">7.3.3. grep.exe</a></li> <li><a href="#_gzip_exe">7.3.4. gzip.exe</a></li> <li><a href="#_live_checkpoint_ps1">7.3.5. live-checkpoint.ps1</a></li> <li><a href="#_p4login_ps1">7.3.6. p4login.ps1</a></li> <li><a href="#_recover_edge_ps1">7.3.7. recover-edge.ps1</a></li> <li><a href="#_recreate_live_from_offline_db_ps1">7.3.8. recreate-live-from-offline-db.ps1</a></li> <li><a href="#_replica_status_ps1">7.3.9. replica-status.ps1</a></li> <li><a href="#_rotate_log_files_ps1">7.3.10. rotate-log-files.ps1</a></li> <li><a href="#_sdp_functions_ps1">7.3.11. SDP-functions.ps1</a></li> <li><a href="#_send_test_email_ps1">7.3.12. send-test-email.ps1</a></li> <li><a href="#_svcinst_exe">7.3.13. svcinst.exe</a></li> <li><a href="#_sync_replica_ps1">7.3.14. sync-replica.ps1</a></li> <li><a href="#_upgrade_ps1">7.3.15. upgrade.ps1</a></li> </ul> </li> </ul> </li> <li><a href="#_frequently_asked_questions">Appendix A: Frequently Asked Questions</a> <ul class="sectlevel2"> <li><a href="#_journal_out_of_sequence">A.1. Journal out of sequence</a></li> <li><a href="#_emails_not_being_sent">A.2. Emails not being sent</a> <ul class="sectlevel3"> <li><a href="#_gmail_less_secure_app_access">A.2.1. Gmail Less Secure App Access</a></li> <li><a href="#_implicit_and_explicit_settings">A.2.2. Implicit and Explicit Settings</a></li> <li><a href="#_explicit_ssl">A.2.3. Explicit SSL</a></li> <li><a href="#_implicit_ssl">A.2.4. Implicit SSL</a></li> </ul> </li> </ul> </li> <li><a href="#_sdp_package_contents_and_planning">Appendix B: SDP Package Contents and Planning</a> <ul class="sectlevel2"> <li><a href="#_memory_and_cpu">B.1. Memory and CPU</a> <ul class="sectlevel3"> <li><a href="#_monitoring_sdp_activities">B.1.1. Monitoring SDP activities</a></li> </ul> </li> </ul> </li> </ul> </div> </div> <div id="content"> <div class="sect1"> <h2 id="_preface">Preface</h2> <div class="sectionbody"> <div class="paragraph"> <p>The Server Deployment Package (SDP) is the implementation of Perforce’s recommendations for operating and managing a production Perforce Helix Core Version Control System. It is intended to provide the Helix Core administration team with tools to help:</p> </div> <div class="ulist"> <ul> <li> <p>Simplify Management</p> </li> <li> <p>High Availability (HA)</p> </li> <li> <p>Disaster Recovery (DR)</p> </li> <li> <p>Fast and Safe Upgrades</p> </li> <li> <p>Production Focus</p> </li> <li> <p>Best Practice Configurables</p> </li> <li> <p>Optimal Performance, Data Safety, and Simplified Backup</p> </li> </ul> </div> <div class="paragraph"> <p>This guide is intended to provide instructions of setting up the SDP to help provide users of Helix Core with the above benefits.</p> </div> <div class="paragraph"> <p>This guide assumes some familiarity with Perforce and does not duplicate the basic information in the Perforce user documentation. This document only relates to the Server Deployment Package (SDP) all other Helix Core documentation can be found here: <a href="https://www.perforce.com/support/self-service-resources/documentation">Perforce Support Documentation</a></p> </div> <div class="paragraph"> <p><strong>Please Give Us Feedback</strong></p> </div> <div class="paragraph"> <p>Perforce welcomes feedback from our users. Please send any suggestions for improving this document or the SDP to <a href="mailto:consulting@perforce.com">consulting@perforce.com</a>.</p> </div> </div> </div> <div class="sect1"> <h2 id="_overview">1. Overview</h2> <div class="sectionbody"> <div class="paragraph"> <p>The SDP has four main components:</p> </div> <div class="ulist"> <ul> <li> <p>Hardware and storage layout recommendations for Perforce.</p> </li> <li> <p>Scripts to automate critical maintenance activities</p> </li> <li> <p>Scripts to aid the setup and management of replication (including failover for DR/HA)</p> </li> <li> <p>Scripts to assist with routine administration tasks.</p> </li> </ul> </div> <div class="paragraph"> <p>Each of these components is covered, in detail, in this guide.</p> </div> <div class="sect2"> <h3 id="_windows_sdp_vs_unix_sdp">1.1. Windows SDP vs Unix SDP</h3> <div class="paragraph"> <p>The principles of the SDP are the same on both operating systems. The similarities are:</p> </div> <div class="ulist"> <ul> <li> <p>Similar logical structure for file/directory layout (starting from <code>/p4</code> and <code>c:\p4</code> respectively)</p> </li> <li> <p>This logical structure can be mapped to flexible physical structure for desired performance and redundancy criteria</p> </li> <li> <p>Support for offline checkpointing (<code>root</code> vs <code>offline_db</code>) using an automated daily script</p> </li> <li> <p>Support for regular archive verification using an automated script</p> </li> <li> <p>Emailing of results for basic monitoring</p> </li> <li> <p>Some things like triggers written in Python or Perl are cross platform</p> </li> </ul> </div> <div class="paragraph"> <p>The differences are:</p> </div> <div class="ulist"> <ul> <li> <p>Unix scripts/tools are mainly written in Bash, whereas Windows mainly uses Powershell</p> </li> <li> <p>Windows Perforce Helix Core deployments tend to be simpler than Unix ones (fewer replicas etc), so there are more scripts for Unix SDP to manage replicas.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="_downloading_sdp">1.2. Downloading SDP</h3> <div class="paragraph"> <p>This is available: <a href="https://swarm.workshop.perforce.com/files/guest/perforce_software/sdp/downloads/sdp.Windows.zip" class="bare">https://swarm.workshop.perforce.com/files/guest/perforce_software/sdp/downloads/sdp.Windows.zip</a></p> </div> <div class="paragraph"> <p>See <a href="#_clean_installation">Section 3.1, “Clean Installation”</a> for where to put it after downloading.</p> </div> </div> <div class="sect2"> <h3 id="_checking_the_sdp_version">1.3. Checking the SDP Version</h3> <div class="paragraph"> <p>Once installed, the SDP <code>Version</code> file exists as <code>C:\p4\sdp\Version</code>. This is a simple text file that contains the SDP version string. The version can be checked using a command like <code>TYPE</code>, as in this sample command:</p> </div> <div class="literalblock"> <div class="content"> <pre>C:\p4\sdp> TYPE Version Rev. SDP/MultiArch/2020.1/27955 (2021/08/13)</pre> </div> </div> <div class="paragraph"> <p>That string can be found in Change History section of the <a href="ReleaseNotes.html">SDP Release Notes</a>. This can be useful in determining if your SDP is the latest available, and to see what features are included.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_configuring_the_perforce_server">2. Configuring the Perforce Server</h2> <div class="sectionbody"> <div class="paragraph"> <p>This chapter tells you how to configure a Perforce server machine and an instance of the Perforce Server. These topics are covered more fully in the <a href="https://community.perforce.com/s/article/2529">Knowledge Base</a>; this chapter covers the details most relevant to the SDP.</p> </div> <div class="paragraph"> <p>The SDP can be installed on multiple server machines, and each server machine can host one or more Perforce server instances. (In this guide, the term <em>server</em> refers to a Perforce server instance unless otherwise specified.) Each server instance is assigned a number. This guide uses instance number 1 in the example commands and procedures. Other instance numbers can be substituted as required.</p> </div> <div class="paragraph"> <p>This chapter also describes the general usage of SDP scripts and tools.</p> </div> <div class="sect2"> <h3 id="_volume_layout_and_hardware">2.1. Volume Layout and Hardware</h3> <div class="paragraph"> <p>To ensure maximum data integrity and performance, use three different physical volumes for each server instance. Three volumes can be used for all instances hosted on one server machine, but using three volumes per instance reduces the chance of hardware failure affecting more than one instance.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> While re recommend 3 volumes (drives), it is often practical to put all the files onto a single physical volume. We do NOT recommend the use of the C: drive (operating system root)! </td> </tr> </table> </div> <div class="ulist"> <ul> <li> <p><strong>Perforce metadata (database files):</strong> Use the fastest volume possible, ideally RAID 1+0 on a dedicated controller with the maximum cache available on it. This volume is normally called <code>metadata</code>.</p> </li> <li> <p><strong>Journals and logs:</strong> Use a fast volume, ideally RAID 1+0 on its own controller with the standard amount of cache on it. This volume is normally called <code>logs</code>. If a separate logs volume is not available, put the logs on the depotdata volume.</p> </li> <li> <p><strong>Depot data, archive files, scripts, and checkpoints</strong>: Use a large volume, with RAID 5 on its own controller with a standard amount of cache or a SAN or NAS volume. This volume is the only volume that MUST be backed up (although we recommend also backing up <code>logs</code>). The backup scripts place the metadata snapshots on this volume. This volume can be backed up to tape or another long term backup device. This volume is normally called <code>depotdata</code>.</p> </li> </ul> </div> <div class="paragraph"> <p>If three controllers are not available, put the logs and depotdata volumes on the same controller. Do not run anti-virus tools or back up tools against the metadata volume(s) or logs volume(s), because they can interfere with the operation of the Perforce server.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> The SDP assumes (but does not require) the three volumes described above. It can easily be configured to use a single volume on which all data is stored. </td> </tr> </table> </div> <div class="paragraph"> <p>View Figure 2: Volume Layout (below), viewed from the top down, displays a Perforce <em>application</em> administrator’s view of the system, which shows how to navigate the directory structure to find databases, log files, and versioned files in the depots. Viewed from the bottom up, it displays a Perforce <em>system</em> administrator’s view, emphasizing the physical volume where Perforce data is stored.</p> </div> <div class="paragraph"> <p>Both Unix and Windows installation of the SDP now use symlinks (on Windows this is via the mklink tool).</p> </div> <div class="paragraph"> <p><span class="image"><img src="media/fs_layout.png" alt="fs_layout.png" width="576" height="435"></span></p> </div> <div class="paragraph"> <p>Figure 2: Volume Layout</p> </div> <div class="paragraph"> <p>The links are shown as <SYMLINKD> below on a Windows installation.</p> </div> <div class="literalblock"> <div class="content"> <pre>Directory of c:\p4 20/06/2020 15:05 <DIR> . 20/06/2020 15:05 <DIR> .. 20/06/2020 15:05 <SYMLINKD> common [f:\p4\common] 20/06/2020 15:05 <SYMLINKD> config [f:\p4\config] 20/06/2020 15:05 <SYMLINKD> 1 [f:\p4\1]</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>Directory of c:\p4\1 20/06/2020 15:05 <DIR> . 20/06/2020 15:05 <DIR> .. 20/06/2020 15:05 <DIR> bin 20/06/2020 15:05 <DIR> checkpoints 20/06/2020 15:05 <DIR> depots 20/06/2020 15:05 <SYMLINKD> logs [g:\p4\1\logs] 20/06/2020 15:05 <SYMLINKD> offline_db [e:\p4\1\offline_db] 20/06/2020 15:05 <SYMLINKD> root [e:\p4\1\root] 20/06/2020 15:05 <DIR> ssl 20/06/2020 15:05 <DIR> tmp</pre> </div> </div> </div> <div class="sect2"> <h3 id="_instance_names">2.2. Instance Names</h3> <div class="paragraph"> <p>Traditionally the SDP has used integers for instance names which show up in the paths above, for example C:\p4\ <strong>1</strong>\root.</p> </div> <div class="paragraph"> <p>However it is increasingly the case that alphanumeric names are used for instances, e.g. C:\p4\ <strong><em>Acme</em></strong>\root. Commonly organizations strive to use a single Perforce instance, one logical data set, which may be replicated around the globe. Using a single instance optimizes collaboration and simplifies code access for all development activity. When there is a single instance, the name ‘<strong><em>1</em></strong>' is as good as any. When there is more than one instance, e.g. if there are isolated silos of development activity, an alphanumeric name may be more helpful than an integer for identifying the data set, such as <strong><em>Acme</em></strong> or perhaps <strong><em>LegacyApps</em></strong>. Another instance is sometimes to develop and test things like Perforce trigger scripts before rolling them out to the live production instance, or to provide a standing internal training data set.</p> </div> <div class="paragraph"> <p>In any case it is worth thinking and planning your naming, particularly if you have multiple instances including replicas of different types and these are located on different hosts.</p> </div> <div class="paragraph"> <p>If you are using instance numbers, then an example configuration where there are 2 master server instances, each with a replica, might be:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top"><strong>Server hostname</strong></th> <th class="tableblock halign-left valign-top"><strong>Instance ID</strong></th> <th class="tableblock halign-left valign-top"><strong>Port</strong></th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">p4d-sfo-01</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1666</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-01</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">2666</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-02</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">1666</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-02</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">2</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">2666</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>For consistency, instances with same ID should refer to the same logical data set, they just run on different machines.</p> </div> <div class="paragraph"> <p>Alternatively, alphanumeric names can be clearer and easier:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top"><strong>Server hostname</strong></th> <th class="tableblock halign-left valign-top"><strong>Instance ID</strong></th> <th class="tableblock halign-left valign-top"><strong>Port</strong></th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-01</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Acme</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5000</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-01</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Test</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5999</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-02</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Acme</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5000</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">sfo-p4d-02</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Test</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">5999</p></td> </tr> </tbody> </table> <div class="paragraph"> <p>Some sites apply a convention to the port number to identify whether the P4PORT value is that of a master server, a broker, replica, edge server, or proxy. In such cases the first digit is reserved to identify the instance, and the remaining 3 digits identify the target service, e.g. 666 for a broker, 999 for a master server, 668 for a proxy.</p> </div> <div class="paragraph"> <p>Host naming conventions vary from site to site, and often have local naming preferences or constraints. These examples the the code of the nearest major airport, sfo in this case, as a location code. Using location in the hostname is merely an example of a site preference, not necessarily a best practice.</p> </div> <div class="paragraph"> <p>End user <strong>P4PORT</strong> values typically do not reference the actual machine names. Instead they reference an alias, e.g. perforce or sfo-p4d (without the -01). This helps make failover operations more transparent.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_installing_the_perforce_server_and_the_sdp">3. Installing the Perforce Server and the SDP</h2> <div class="sectionbody"> <div class="paragraph"> <p>This chapter tells you how to install a Perforce server instance in the SDP framework. For more details about server installation, refer to the <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/install.windows.html">Perforce System Administrator’s Guide</a>.</p> </div> <div class="paragraph"> <p>Many companies use a single Perforce Server to manage their files, while others use multiple servers. The choice depends on network topology, the geographic distribution of work, and the relationships among the files being managed. If multiple servers are run, assign each instance a number and use that number as part of the name assigned to depots, to make the relationship of depots and servers obvious. See the discussion above on Instance Names.</p> </div> <div class="sect2"> <h3 id="_clean_installation">3.1. Clean Installation</h3> <div class="paragraph"> <p>In this section we describe the server and SDP installation process on Windows. The process consists of:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Initial setup of the file system and configuration files.</p> </li> <li> <p>Running the SDP configuration script.</p> </li> <li> <p>Starting the server and performing initial configuration.</p> </li> </ol> </div> <div class="sect3"> <h4 id="_pre_requisites">3.1.1. Pre-requisites</h4> <div class="paragraph"> <p>The following are required (details mentioned below):</p> </div> <div class="ulist"> <ul> <li> <p>Administrator account on the server</p> </li> <li> <p>Python installed (see below)</p> </li> <li> <p>Perforce Helix Core executables (p4.exe/p4d.exe - see below)</p> </li> <li> <p>Powershell 5.x or greater (default on Windows 10 or Windows Server 2016+)</p> </li> </ul> </div> <div class="paragraph"> <p>Optional (but recommended):</p> </div> <div class="ulist"> <ul> <li> <p>Perforce Helix Visual client (P4V - optional but very useful, together with P4Admin - the Admin tool)</p> </li> <li> <p>An editor (Notepad will do, but <a href="https://notepad-plus-plus.org/downloads/">Download Notepad++</a>)</p> </li> <li> <p><a href="https://github.com/bmatzelle/gow/releases">GOW (Gnu on Windows)</a> - optional but very useful for parsing log files etc.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_configuring_powershell">3.1.2. Configuring Powershell</h4> <div class="paragraph"> <p>The scripts now use Powershell rather than .BAT files due to improved error handling and options, and code re-use (via a single included module rather than duplication of functionality in every script). This also allows us to keep the scripts more closely aligned with the functionality of the Unix scripts.</p> </div> <div class="paragraph"> <p>It is important to enable local scripts to be run. The following command must be run within an Powershell Administrator prompt:</p> </div> <div class="literalblock"> <div class="content"> <pre>get-executionpolicy</pre> </div> </div> <div class="paragraph"> <p>The result needs to be either <code>RemoteSigned</code> or <code>Unrestricted</code>. If not then set it as below.</p> </div> <div class="paragraph"> <p>For Windows 10, Windows Server 2016 or later, run the following commands as Administrator:</p> </div> <div class="ulist"> <ul> <li> <p><em>x86</em><br> Open <code>C:\Windows\SysWOW64\cmd.exe</code><br> Run the command:</p> <div class="literalblock"> <div class="content"> <pre>powershell Set-ExecutionPolicy RemoteSigned</pre> </div> </div> </li> <li> <p><em>x64</em><br> Open <code>C:\Windows\system32\cmd.exe</code><br> Run the command:</p> <div class="literalblock"> <div class="content"> <pre>powershell Set-ExecutionPolicy RemoteSigned</pre> </div> </div> </li> </ul> </div> <div class="paragraph"> <p>Use <code>get-executionpolicy</code> to check the policy has been updated. You may need to ensure that the various scripts are not "blocked" - right click in Windows Explorer and check Properties options.</p> </div> </div> <div class="sect3"> <h4 id="_initial_setup">3.1.3. Initial setup</h4> <div class="paragraph"> <p>Prior to installing the Perforce server, perform the following steps.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Mount the volumes for the three-volume configuration described in Volume Layout and Hardware. The procedure assumes the drives are mapped as follows:</p> <div class="ulist"> <ul> <li> <p>Metadata on <code>e:</code></p> </li> <li> <p>Depotdata on <code>f:</code></p> </li> <li> <p>Logs on <code>g:</code></p> </li> </ul> </div> </li> </ol> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> If you do not have a logs volume, put the logs on the depot data volume. If you have only a single data volume, e.g. <code>d:</code> then set all the values to that volume. </td> </tr> </table> </div> <div class="olist arabic"> <ol class="arabic" start="2"> <li> <p>Copy the SDP to the <code>f:\sdp</code> directory (let us call this <code>%SDP%</code>).</p> </li> </ol> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> It is likely that Windows will have blocked the various scripts and files for security reasons. It is important to run the following command (in Powershell window as Administrator) </td> </tr> </table> </div> <div class="literalblock"> <div class="content"> <pre>dir -Path f:\sdp -Recurse | Unblock-File</pre> </div> </div> <div class="olist arabic"> <ol class="arabic" start="3"> <li> <p>Customize the following for your environment. It requires you to identify the master server and all replicas that we need to setup for the SDP, including instance names, hostnames, etc. This information is all in a single file:</p> <div class="literalblock"> <div class="content"> <pre>%SDP%\Server\Windows\setup\sdp_master_config.ini</pre> </div> </div> </li> <li> <p>Download and install Python, e.g. from <a href="http://www.python.org">www.python.org</a>. We use Python 2.7.x (latest) and 3.7.x (latest). 64-bit version is fine. Typically we install to default dir, e.g. c:\python27. For initial installation we only require base Python. For subsequent scripting you may wish to install P4Python (e.g. using pip).</p> </li> <li> <p>Other tools we find useful: Notepad++ and GOW (Gnu on Windows - Unix command line utilities such as wc, head, tail). These are recommended but not strictly required.</p> </li> <li> <p>Download to directory <code>%SDP%\Server\Windows\setup</code> the desired release of p4.exe and p4d.exe. For example, for Helix Core for release 2020.1 on 64 bit Windows, use this URL:</p> <div class="literalblock"> <div class="content"> <pre>http://ftp.perforce.com/perforce/r20.1/bin.ntx64</pre> </div> </div> <div class="paragraph"> <p>From that directory listing, select <code>p4.exe</code> and then <code>p4d.exe</code> to download each of those files. If you are using 32 bit Windows (unusual these days), substitute <code>bin.ntx86</code> for <code>bin.ntx64</code> in the URL above. The following works within Powershell</p> </div> <div class="literalblock"> <div class="content"> <pre>Invoke-WebRequest "http://ftp.perforce.com/perforce/r20.1/bin.ntx64/p4.exe" -OutFile "p4.exe" Invoke-WebRequest "http://ftp.perforce.com/perforce/r20.1/bin.ntx64/p4d.exe" -OutFile "p4d.exe"</pre> </div> </div> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_running_configuration_script">3.1.4. Running Configuration script</h4> <div class="paragraph"> <p>The <code>create_env.py</code> script, available in <code>%SDP%\Server\Windows\setup</code>, sets up the basic directory structure used by the SDP. It creates .bat files to register the Perforce service as Windows services. It parses and validates the <code>sdp_master_config.ini</code> file in the same directory.</p> </div> <div class="paragraph"> <p>You need to customize this <code>sdp_master_config.ini</code> file. It contains lots of comments as to how to set the various configuration values.</p> </div> <div class="paragraph"> <p>The following shows a sample config after editing:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[DEFAULT] SDP_P4SUPERUSER=perforce SDP_P4SUPERUSER_PASSWORD=SomeRandomPassword ADMIN_PASS_FILENAME=adminpass.txt mailfrom=perforce@example.com maillist=p4ra@example.com mailhost=mail.example.com mailhostport=25 EMAIL_PASS_FILENAME=emailpass.txt EMAIL_PASSWORD= KEEPCKPS=10 KEEPLOGS=20 LIMIT_ONE_DAILY_CHECKPOINT=false SDP_GLOBAL_ROOT=c: # Assuming output of `hostname` is this value, and we are using instance `1` [1:perforce-svr-01] SDP_SERVERID=Master SDP_SERVICE_TYPE=standard SDP_P4PORT_NUMBER=1666 # Everything on D: drive METADATA_ROOT=D: DEPOTDATA_ROOT=D: LOGDATA_ROOT=D: REMOTE_DEPOTDATA_ROOT=</code></pre> </div> </div> <div class="paragraph"> <p>Review the contents of <code>template_configure_new_server.bat</code> file which defines the recommended default configurable values for any server, and make any desired changes. This file will be parsed and used to create instance specific configuration files.</p> </div> <div class="paragraph"> <p>After updating the configuration file, run <code>create_env.py</code> from the same directory.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> You must run this command from a CMD window which has <strong>administrator</strong> rights. </td> </tr> </table> </div> <div class="literalblock"> <div class="content"> <pre>cd %SDP%\Server\Windows\setup</pre> </div> </div> <div class="paragraph"> <p>Edit and save changes:</p> </div> <div class="literalblock"> <div class="content"> <pre>notepad sdp_master_config.ini</pre> </div> </div> <div class="paragraph"> <p>Run the command to create the environment (by default it looks for the config file sdp_master_config.ini but this can be changed with -c option):</p> </div> <div class="literalblock"> <div class="content"> <pre>Create_env.py</pre> </div> </div> <div class="paragraph"> <p>The output will look something like this:</p> </div> <div class="literalblock"> <div class="content"> <pre>D:\sdp\Server\Windows\setup>create_env.py INFO: Found the following sections: ['1:EC2AMAZ-LJ68A4I'] INFO: Config file written: sdp_config.ini INFO: The following directories/links would be created with the -y/--yes flag INFO: Creating target dir 'c:\p4' INFO: Creating target dir 'D:\p4\1' INFO: Creating target dir 'D:\p4\1' INFO: Creating link 'c:\p4\1' to 'D:\p4\1' INFO: Creating target dir 'D:\p4\common' INFO: Creating link 'c:\p4\common' to 'D:\p4\common' INFO: Creating target dir 'D:\p4\config' INFO: Creating link 'c:\p4\config' to 'D:\p4\config' INFO: Creating target dir 'c:\p4\common\bin' INFO: Creating target dir 'c:\p4\common\bin\triggers' INFO: Creating target dir 'c:\p4\1\bin' INFO: Creating target dir 'c:\p4\1\tmp' INFO: Creating target dir 'c:\p4\1\depots' INFO: Creating target dir 'c:\p4\1\checkpoints' INFO: Creating target dir 'c:\p4\1\ssl' INFO: Creating target dir 'D:\p4\1\root' INFO: Creating link 'c:\p4\1\root' to 'D:\p4\1\root' INFO: Creating target dir 'c:\p4\1\root\save' INFO: Creating target dir 'D:\p4\1\offline_db' INFO: Creating link 'c:\p4\1\offline_db' to 'D:\p4\1\offline_db' INFO: Creating target dir 'D:\p4\1\logs' INFO: Creating link 'c:\p4\1\logs' to 'D:\p4\1\logs' INFO: Copying 'D:\sdp\Server\Windows\p4\common\bin\create-filtered-edge-checkpoint.ps1' to 'c:\p4\common\bin\create-filtered-edge-checkpoint.ps1' INFO: Copying 'D:\sdp\Server\Windows\p4\common\bin\create-offline-db-from-checkpoint.bat' to 'c:\p4\common\bin\create-offline-db-from-checkpoint.bat' INFO: Copying 'D:\sdp\Server\Windows\p4\common\bin\create-offline-db-from-checkpoint.ps1' to 'c:\p4\common\bin\create-offline-db-from-checkpoint.ps1' : INFO: Copying 'D:\sdp\Server\Windows\setup\p4.exe' to 'c:\p4\1\bin' INFO: Copying 'D:\sdp\Server\Windows\setup\p4d.exe' to 'c:\p4\1\bin' INFO: Copying 'D:\sdp\Server\Windows\setup\p4d.exe' to 'c:\p4\1\bin\p4s.exe' INFO: Copying 'D:\sdp\Server\Windows\setup\sdp_config.ini' to 'c:\p4\config' INFO: Copying 'D:\sdp\Server\Windows\setup\Master_server.id' to 'c:\p4\1\root\server.id' INFO: Creating instance bat file 'c:\p4\1\bin\daily-backup.bat' INFO: Creating instance bat file 'c:\p4\1\bin\p4verify.bat' INFO: Creating instance bat file 'c:\p4\1\bin\replica-status.bat' INFO: Creating service configure commands on 'ec2amaz-lj68a4i' for instance '1' in install_services_ec2amaz-lj68a4i.bat</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>The following commands have been created - but you are in report mode so no directories have been created install_services_ec2amaz-lj68a4i.bat configure_Master.bat You will also need to seed the replicas from a checkpoint and run the appropriate commands on those machines INFO: Running in reporting mode: use -y or --yes to perform actions.</pre> </div> </div> <div class="paragraph"> <p>If the output looks correct then re-run the script with <code>-y</code> parameter to actually perform the copying of files and creation of directories and links.</p> </div> <div class="literalblock"> <div class="content"> <pre>create_env.py -y</pre> </div> </div> </div> <div class="sect3"> <h4 id="_sdp_config_ini">3.1.5. sdp_config.ini</h4> <div class="paragraph"> <p>This file is written to <code>c:\p4\config</code>. It will look something like this (note the value <code>EC2AMAZ-LJ68A4I</code> is an example of the output of the <code>hostname</code> command - your value will be different):</p> </div> <div class="literalblock"> <div class="content"> <pre>[1:EC2AMAZ-LJ68A4I] p4port=EC2AMAZ-LJ68A4I:1777 sdp_serverid=Master sdp_p4serviceuser= sdp_global_root=c: sdp_p4superuser=perforce admin_pass_filename=adminpass.txt email_pass_filename=emailpass.txt mailfrom=perforce@example.com maillist=p4ra@example.com mailhost=mail.example.com mailhostport=25 python=None remote_depotdata_root= keepckps=10 keeplogs=20 limit_one_daily_checkpoint=false remote_sdp_instance= p4target=</pre> </div> </div> <div class="paragraph"> <p>The above are the values for a single master/commit server.</p> </div> <div class="paragraph"> <p>If you configure a replica then these fields should be set to appropriate values:</p> </div> <div class="literalblock"> <div class="content"> <pre>[1:EC2AMAZ-REPLICA] : sdp_p4serviceuser=svc_p4d_ha_aws : remote_depotdata_root=\\EC2AMAZ-LJ68A4I\d$ remote_sdp_instance=1 p4target=EC2AMAZ-LJ68A4I:1777</pre> </div> </div> </div> <div class="sect3"> <h4 id="_installing_services">3.1.6. Installing service(s)</h4> <div class="paragraph"> <p>The above command will create a couple of files in that directory. The first is <code>install_services_<hostname>.bat</code>, so on a machine where the hostname is <code>svrp4master</code>, it will be <code>install_services_svrp4master.bat</code></p> </div> <div class="paragraph"> <p>Validate the contents of this file and run it if it looks appropriate - this installs the service(s) with appropriate parameters. Please note that it is specific to the <strong>hostname</strong> that you specified inside <code>sdp_master_config.ini</code> - so it will only run on the correct host server. It should look something like:</p> </div> <div class="literalblock"> <div class="content"> <pre>D:\sdp\Server\Windows\setup>install_services_ec2amaz-lj68a4i.bat D:\sdp\Server\Windows\setup>c:\p4\common\bin\instsrv.exe p4_1 "c:\p4\1\bin\p4s.exe" The service was successfully added!</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>Make sure that you go into the Control Panel and use the Services applet to change the Account Name and Password that this newly installed service will use for its Security Context.</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>D:\sdp\Server\Windows\setup>c:\p4\1\bin\p4.exe set -S p4_1 P4ROOT=c:\p4\1\root D:\sdp\Server\Windows\setup>c:\p4\1\bin\p4.exe set -S p4_1 P4JOURNAL=c:\p4\1\logs\journal D:\sdp\Server\Windows\setup>c:\p4\1\bin\p4.exe set -S p4_1 P4NAME=Master D:\sdp\Server\Windows\setup>c:\p4\1\bin\p4.exe set -S p4_1 P4PORT=1777 D:\sdp\Server\Windows\setup>c:\p4\1\bin\p4.exe set -S p4_1 P4LOG=c:\p4\1\logs\Master.log</pre> </div> </div> <div class="paragraph"> <p>Note that if you have defined multiple instances in <code>sdp_master_config.ini</code> to run on this same hostname, then they will all be installed by this .bat file.</p> </div> </div> <div class="sect3"> <h4 id="_start_the_server_to_test">3.1.7. Start the server to test</h4> <div class="paragraph"> <p>Having installed the service, we now test that it will start: <code>c:\p4\common\bin\svcinst start -n p4_<instance name></code>, e.g.</p> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\common\bin\svcinst start -n p4_1</pre> </div> </div> <div class="paragraph"> <p>Or</p> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\common\bin\svcinst start -n p4_Master</pre> </div> </div> <div class="paragraph"> <p>If the service fails to start, then examine the log file for the reason (e.g. missing license file) in <code>c:\p4\<instance>\logs</code>.</p> </div> <div class="paragraph"> <p>Ensure the server is running (specify appropriate port):</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 -p 1666 info</pre> </div> </div> <div class="paragraph"> <p>Use <code>c:\p4\common\bin\svcinst stop -n p4_<instance></code> to stop the service if required.</p> </div> </div> <div class="sect3"> <h4 id="_create_p4admin_shortcuts">3.1.8. Create P4Admin Shortcuts</h4> <div class="paragraph"> <p>Desktop shortcuts simplify setting up the SDP shell environment, making it easy to interact with the configured Helix Core service.</p> </div> <div class="paragraph"> <p>Create a shortcut for each SDP instance on the Desktop of the user account used to manage the Perforce Helix services, and/or the human administrators who login directly to the server machine.</p> </div> <div class="paragraph"> <p>The shortcut brings up a Windows Command Prompt (<code>cmd.exe</code>) with the SDP environment configured.</p> </div> <div class="paragraph"> <p>For each SDP instance configured, create a separate shortcut named <code>P4Admin N</code>, replacing <code>N</code> with the SDP instance name. For example, if the instance name is <code>1</code> (the default), create a shortcut named <code>P4Admin 1</code>.</p> </div> <div class="sect4"> <h5 id="_create_the_promptsetup_bat_file">3.1.8.1. Create the <code>PromptSetup.bat</code> File</h5> <div class="paragraph"> <p>In the <code>C:\p4\N\bin</code> directory for the instance (e.g. <code>C:\p4\1\bin\PromptSetup.bat</code> for SDP instance <code>1</code>), create a file named <code>PromptSetup.bat</code>. It should have these contents:</p> </div> <div class="literalblock"> <div class="content"> <pre>@ECHO OFF CLS CALL C:\p4\common\bin\p4env.bat 1</pre> </div> </div> <div class="paragraph"> <p>In the file contents, replace the <code>1</code> with the appropiate SDP instance name.</p> </div> </div> <div class="sect4"> <h5 id="_create_the_shortcut">3.1.8.2. Create the Shortcut</h5> <div class="paragraph"> <p>To create each <code>P4Admin N</code> shortcut:</p> </div> <div class="paragraph"> <p>On the Windows Desktop, point the mouse anywhere in the desktop background, right-click, and select <code>New</code> → <code>Shortcut</code>. The <code>Create Shortcut</code> dialog will come up prompting: <code>Type the location of the item:</code>. In the text box, enter:</p> </div> <div class="paragraph"> <p><code>C:\Windows\System32\cmd.exe /K C:\p4\N\bin\PromptSetup.bat</code></p> </div> <div class="paragraph"> <p>replacing the <code>N</code> with the appropriate instance name, and then click Next. Then when it prompts <code>Type a name for this shortcut:</code>, enter:</p> </div> <div class="paragraph"> <p><code>P4Admin N</code></p> </div> <div class="paragraph"> <p>again replacin the <code>N</code> with the appropriate instance name, and then click <code>Finish</code>.</p> </div> <div class="paragraph"> <p>Next, right-click on the new shortcut, and click <code>Properties</code>. On the <code>P4Admin Properties</code> dialog, click the <code>Advanced</code> button. On the <code>Advanced Properties</code> dialog, check the <code>Run as administrator</code> checkbox, and then click OK.</p> </div> <div class="paragraph"> <p>Next, back on the <code>P4Admin Properties</code>, in the <code>Start in:</code> field, enter the value <code>C:\p4\N\bin</code> (replacing <code>N</code> with the instance name), and then click <code>Apply</code> and then <code>OK</code>.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> Note: Changing the <code>Start in</code> is only informational, as a command prompt that starts as Administrator will start in the <code>C:\Windows\System32</code> folder. But then it will call the <code>PromptSetup.bat</code>, which does a CD into that folder, so you do end up in a folder like <code>C:\p4\1\bin</code>. </td> </tr> </table> </div> </div> </div> <div class="sect3"> <h4 id="_applying_configurables_to_the_server_instance">3.1.9. Applying configurables to the server instance</h4> <div class="paragraph"> <p>For each instance defined in <code>sdp_master_config.ini</code>, a configuration .bat file will be created, called <code>configure_<instance>.bat</code>, so for instance master, it will be <code>configure_master.bat</code>.</p> </div> <div class="paragraph"> <p>Review the contents of the file and make any desired changes.</p> </div> <div class="paragraph"> <p>You will only be able to run the .bat file if you have started the server instance as per previous section.</p> </div> <div class="paragraph"> <p>If an instance is a replica (or similar), then you should apply the configurables to the master server and then checkpoint it before seeding the replica - see the Distributing Perforce guide.</p> </div> </div> <div class="sect3"> <h4 id="_configuring_the_server">3.1.10. Configuring the server</h4> <div class="paragraph"> <p>To configure the server, perform the following steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Make sure your server is running (specify appropriate port below):</p> <div class="literalblock"> <div class="content"> <pre>p4 -p 1666 info</pre> </div> </div> </li> <li> <p>Create your Perforce administrator account within the Perforce repository, using the user name and password specified in <code>sdp_master_config.ini</code>.</p> </li> <li> <p>Optional. To create a Perforce stream depot called PerforceSDP and load the SDP, issue the following commands:</p> <div class="literalblock"> <div class="content"> <pre>p4 depot -t stream -o PerforceSDP | p4 depot -i p4 stream -t mainline -o //PerforceSDP/main | p4 stream -i cd /d C:\sdp p4 client -S //Perforce/main -o PerforceSDP_ws | p4 client -i p4 -c PerforceSDP_ws reconcile p4 -c PerforceSDP_ws submit -d "Added SDP."</pre> </div> </div> </li> <li> <p>Optional. To create a Perforce spec depot, issue the following commands:</p> <div class="literalblock"> <div class="content"> <pre>p4 depot -t spec -o spec | p4 depot -i</pre> </div> </div> <div class="paragraph"> <p>Then add the following to the Protections table, near the bottom (about super user entries), to hide specs which could have security implications:</p> </div> <div class="literalblock"> <div class="content"> <pre>list user * * -//spec/protect.p4s list user * * -//spec/triggers.p4s</pre> </div> </div> <div class="paragraph"> <p>Then update specs in the depot with this command:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 admin updatespecdepot -a</pre> </div> </div> </li> <li> <p>Optional. To create an unload depot, issue the following command:</p> <div class="literalblock"> <div class="content"> <pre>p4 depot -t unload -o unload | p4 depot -i</pre> </div> </div> </li> <li> <p>Optional. To delete the default Perforce depot named depot, issue the following command: <code>p4 depot -d depot</code>. Create one or more depots as required to store your files, following your site’s directory naming conventions.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_verifying_your_server_installation">3.1.11. Verifying your server installation</h4> <div class="paragraph"> <p>To verify your installation, perform these steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Issue the p4 info command, after setting appropriate environment variables. If the server is running, it will display details about its settings.</p> </li> <li> <p>Create a client workspace and verify that it is archived in the spec depot and written to the <code>c:\p4\1\depots\specs\client</code> (assuming instance <code>1</code>) directory.</p> </li> <li> <p>Add a file to the server and verify that the archive file gets created in the corresponding directory under <code>c:\p4\1\depots</code>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_scheduling_maintenance_scripts">3.1.12. Scheduling maintenance scripts</h4> <div class="paragraph"> <p>In Windows 2012 or later you should use the Task Scheduler. We recommend that you create a folder called Perforce at the top level in which to create your tasks (otherwise they can be hard to find when you next look in Task scheduler!).</p> </div> <div class="paragraph"> <p>Note that the <code>schtasks</code> command can be useful from command line, or <code>taskschd.msc</code> to get the control panel equivalent.</p> </div> <div class="paragraph"> <p>The recommendation is to run the following scheduled tasks on a master server:</p> </div> <div class="ulist"> <ul> <li> <p><code>daily-backup.bat</code> every day at say 1:00 am (or similar time).</p> </li> <li> <p><code>p4verify.bat</code> to run once a week, say at 2:00am on a Saturday.</p> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> Monitor <code>p4verify.bat</code> to see how long it takes to run (the log file is <code>c:\p4\<instance>\logs\p4verify.log</code>). It is possible to run this script on a replica instead of the master if you have a replica setup, and if it runs for too long. </td> </tr> </table> </div> </li> </ul> </div> <div class="paragraph"> <p>If you are on a replica server, then the recommendation is to run these scheduled tasks:</p> </div> <div class="ulist"> <ul> <li> <p><code>replica-status.bat</code> to run nightly.</p> </li> <li> <p><code>c:\p4\common\bin\rotate-log-files.bat <instance></code> to run nightly. This prevents log files getting too big.</p> </li> </ul> </div> <div class="paragraph"> <p>These are all setup in a similar way to the screenshots below <a href="#_daily_backup_bat">Section 3.1.12.1, “Daily-backup.bat”</a>, with the exception of 'rotate-log-files.bat' which requires an argument to be specified which is the <instance>, e.g. <code>1</code> or <code>master</code>.</p> </div> <div class="sect4"> <h5 id="_daily_backup_bat">3.1.12.1. Daily-backup.bat</h5> <div class="sect5"> <h6 id="_task_basics">Task Basics</h6> <div class="paragraph"> <p><span class="image"><img src="media/task_basics.png" alt="task_basics.png" width="426" height="324"></span></p> </div> </div> <div class="sect5"> <h6 id="_trigger_screen">Trigger screen</h6> <div class="paragraph"> <p>Set the time to run like this:</p> </div> <div class="paragraph"> <p><span class="image"><img src="media/task_trigger.png" alt="task_trigger.png" width="427" height="373"></span></p> </div> </div> <div class="sect5"> <h6 id="_action">Action</h6> <div class="paragraph"> <p>Program: <code>c:\p4\<instance>\bin\daily-backup.bat</code></p> </div> <div class="paragraph"> <p>e.g.</p> </div> <div class="paragraph"> <p>Program: <code>c:\p4\1\bin\daily-backup.bat</code> Program: <code>c:\p4\master\bin\daily-backup.bat</code></p> </div> <div class="literalblock"> <div class="content"> <pre>Where `1` or `master` is your instance name.</pre> </div> </div> <div class="paragraph"> <p>Note that no parameter is required as those scripts hard code the instance id.</p> </div> </div> </div> </div> <div class="sect3"> <h4 id="_saving_your_configuration_files_in_perforce">3.1.13. Saving your configuration files in Perforce</h4> <div class="paragraph"> <p>It is sensible to create a Perforce workspace and to store the configuration files in Perforce.</p> </div> <div class="paragraph"> <p>Typically the depot root might be something like <code>//perforce/sdp</code>. If you have many machines, then you might use <code>//perforce/sdp/<machine></code> using either a physical or a logical name for the machine.</p> </div> <div class="paragraph"> <p>A typical workspace view (e.g. for workspace called p4admin.sdp and for instance master), might be:</p> </div> <div class="literalblock"> <div class="content"> <pre>Root: c:\p4 View: //perforce/sdp/p4/*1*/bin/... //p4admin.sdp/*1*/bin/... //perforce/sdp/p4/common/bin/... //p4admin.sdp/common/bin/... //perforce/sdp/p4/config/... //p4admin.sdp/config/...</pre> </div> </div> <div class="paragraph"> <p>You would have appropriate workspaces for each machine, and appropriate lines for each instance on that machine.</p> </div> </div> <div class="sect3"> <h4 id="_archiving_configuration_files">3.1.14. Archiving configuration files</h4> <div class="paragraph"> <p>Now that the server is running properly, copy the following configuration files to the depotdata volume for backup:</p> </div> <div class="ulist"> <ul> <li> <p>The scheduler configuration.</p> </li> <li> <p>Cluster configuration scripts, failover scripts, and disk failover configuration files.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_configuring_a_new_instance_on_an_existing_machine">3.1.15. Configuring a New Instance on an existing machine</h4> <div class="paragraph"> <p>It is possible to add a new instance to an existing machine.</p> </div> <div class="paragraph"> <p>Edit the <code>sdp_master_config.ini</code> and add a new section for the new instance.</p> </div> <div class="paragraph"> <p>The run <code>create_env.py</code>, specifying to just create the new instance.</p> </div> <div class="literalblock"> <div class="content"> <pre>cd %SDP%\Server\Windows\setup</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>notepad sdp_master_config.ini</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>create_env.py -c sdp_master_config.ini --instance Replica2</pre> </div> </div> <div class="paragraph"> <p>If the output looks correct then re-run the script with <code>-y</code> parameter to actually perform the copying of files and creation of directories and links.</p> </div> </div> <div class="sect3"> <h4 id="_upgrading_an_existing_non_sdp_windows_installation">3.1.16. Upgrading an existing (non SDP) Windows installation</h4> <div class="paragraph"> <p>The easiest way to upgrade a service instance is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Create new <code>sdp_master_config.ini</code> file to describe the existing installations.</p> </li> <li> <p>Run <code>create_env.py</code> to create the new environment</p> </li> <li> <p>Run <code>install_services_<hostname>.bat</code> to create new services.</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>Stop existing services</p> </li> <li> <p>Manually move the following files from their existing to new locations:</p> <div class="olist lowerroman"> <ol class="lowerroman" type="i"> <li> <p><code>db.*</code> files</p> </li> <li> <p><code>license</code></p> </li> <li> <p>log file(s)</p> </li> <li> <p><code>journal</code></p> </li> <li> <p>checkpoints and archived journals</p> </li> </ol> </div> </li> <li> <p>Start new service and check it runs successfully</p> </li> <li> <p>Adjust the depot root paths (with 2014.1 or greater use the configurable <code>server.depot.root</code>, otherwise manually edit depot specs and install the appropriate trigger for new depot specs)</p> </li> </ol> </div> </li> </ol> </div> <div class="paragraph"> <p>Simple reporting commands to compare before/after include:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 changes -m20 -l -t > changes.txt p4 depots > depots.txt p4 verify -q //...@yyyy/mm/dd,#head (specifying a few days before the cutover)</pre> </div> </div> </div> <div class="sect3"> <h4 id="_upgrading_an_older_windows_sdp_installation">3.1.17. Upgrading an older Windows SDP installation</h4> <div class="paragraph"> <p>Older versions of the Windows SDP (pre June 2014) stored configuration values for each instance in a p4env.bat file within the <code>p4\common\bat</code> directory.</p> </div> <div class="paragraph"> <p>They also didn’t link all directories from <code>c:\p4</code>, but instead used drives such as <code>E:</code>, <code>F:</code> and <code>G:</code> and paths on those drives.</p> </div> <div class="paragraph"> <p>The easiest way to upgrade (most of the work can be done without stopping the service) is:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Ensure that existing instance files are checked in to Perforce (<code>instance\bin</code> and <code>common\bin</code> files), for example in workspace p4admin.sdp.orig (use a root directory of %DEPOTDATA% - see next step).</p> </li> <li> <p>Extract existing values from <code>p4env.bat</code> such as mailfrom, mailhost, mailto, and also METADATA, LOGDATA and DEPOTDATA</p> </li> <li> <p>Edit <code>sdp_master_config.ini</code> and set the appropriate values using extracted ones, and appropriate instance specific values.</p> </li> <li> <p>Set the values for <code>METADATA_ROOT</code>, <code>DEPOTDATA_ROOT</code> and <code>LOGDATA_ROOT</code> to the same (dummy) value, e.g. <code>c:\p4assets</code></p> </li> <li> <p>Run 'create_env.py` to generate the new structure.</p> </li> <li> <p>Manually edit <code>c:\p4assets\p4\config\sdp_config.ini</code> and set the ROOT values to the existing values taken from step 2.</p> </li> <li> <p>Using a different but similar workspace p4admin.sdp.new, which has a root directory of <code>c:\p4</code>, run <code>p4 sync -k</code>, then do a <code>p4 reconcile</code> to identify all the changed files - this will include most of the .bat files, but it shouldn’t include <code>p4d.exe</code> or <code>p4s.exe</code> as we are not updating these files.</p> </li> <li> <p>Submit the new changes.</p> </li> <li> <p>In workspace <code>p4admin.sdp.orig</code>, carefully check the updated files that need to be synced (recommend you review diffs one by one), and then sync them.</p> </li> <li> <p>Manually remove and recreate the links (using <code>del</code> and <code>mklink /d</code>) for directories under <code>c:\p4</code> so that they point to the existing directories on <code>e:</code>, <code>f:</code> or <code>g:</code> (the original DEPOTDATA).</p> </li> <li> <p>Review existing configurables and adjust as appropriate.</p> </li> <li> <p>Setup the scheduled tasks for daily/weekly backup and verify as appropriate. Validate that the daily backup works (typically wait until the next day)</p> </li> <li> <p>At an appropriate point, stop the existing service, adjust the service paths to use the new paths starting from <code>c:\p4</code>.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_configuring_protections_file_types_monitoring_and_security">3.1.18. Configuring protections, file types, monitoring and security</h4> <div class="paragraph"> <p>After the server is installed and configured, most sites will want to modify server permissions (protections) and security settings. Other common configuration steps include modifying the file type map and enabling process monitoring. To configure permissions, perform the following steps:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>To set up protections, issue the p4 protect command. The protections table is displayed.</p> </li> <li> <p>Delete the following line:</p> <div class="literalblock"> <div class="content"> <pre>write user * * //depot/...</pre> </div> </div> </li> <li> <p>Define protections for your server using groups. Perforce uses an inclusionary model. No access is given by default, you must specifically grant access to users/groups in the protections table. It is best for performance to grant users specific access to the areas of the depot that they need rather than granting everyone open access, and then trying to remove access via exclusionary mappings in the protect table even if that means you end up generating a larger protect table.</p> </li> <li> <p>To set the server’s default file types, run the <code>p4 typemap</code> command and define your typemap to override Perforce’s default behavior.</p> <div class="paragraph"> <p>Add any file type entries that are specific to your site. Suggestions:</p> </div> <div class="ulist"> <ul> <li> <p>For already-compressed file types (such as .zip, .gz, .avi, .gif), assign a file type of binary+Fl to prevent the server from attempting to compress them again before storing them.</p> </li> <li> <p>For regular binary files, add binary+l to make so that only one person at a time can check them out.</p> </li> <li> <p>A sample file is provided in <code>$SDP/Server/config/typemap</code></p> </li> </ul> </div> </li> <li> <p>For large, generated text files (e.g. postscript files), assign the text+C file type, to avoid causing server memory issues.</p> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> Perforce provides most IT required password management practices internally. It is recommend to use internal passwords over LDAP/AD to avoid exposing LDAP/AD passwords to the Perforce admin via the auth trigger. </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="_general_sdp_usage">3.2. General SDP Usage</h3> <div class="paragraph"> <p>This section presents an overview of the SDP scripts and tools. Details about the specific scripts are provided in later sections.</p> </div> <div class="paragraph"> <p>Most tools reside in <code>c:\p4\common\bin</code>. The directory <code>c:\p4\<instance>\bin</code> contains scripts and executables that are specific to a server instance, such as the <code>p4.exe</code> client. The scripts in <code>c:\p4\<instance>\bin</code> generally set the environment for an instance correctly, then invoke the corresponding script in <code>c:\p4\common\bin</code>.</p> </div> <div class="paragraph"> <p>Run important administrative commands using the scripts in <code>c:\p4\<instance>\bin</code>, when available. Then, use the <code>p4.exe</code> executable located in <code>c:\p4\<instance>\bin</code>.</p> </div> <div class="paragraph"> <p>Below are some usage examples for instance 1 or instance master.</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 50%;"> <col style="width: 50%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Example</th> <th class="tableblock halign-left valign-top">Remarks</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">c:\p4\common\bin\live-checkpoint.ps1 1</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Take a checkpoint of the live database on instance <strong><em>1</em></strong></p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">c:\p4\common\bin\daily-backup.ps1 master</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">A daily checkpoint of the <strong><em>master</em></strong> instance.</p></td> </tr> </tbody> </table> </div> </div> </div> <div class="sect1"> <h2 id="_backup_replication_and_recovery">4. Backup, Replication, and Recovery</h2> <div class="sectionbody"> <div class="paragraph"> <p>Perforce servers maintain <em>metadata</em> and <em>versioned files</em>. The metadata contains all the information about the files in the depots. Metadata resides in database (db.*) files in the server’s root directory (P4ROOT). The versioned files contain the file changes that have been submitted to the server. Versioned files reside on the depotdata volume.</p> </div> <div class="paragraph"> <p>This section assumes that you understand the basics of Perforce backup and recovery. For more information, consult the Perforce <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/chapter.backup.html">System Administrator’s Guide</a> and <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/failover.html#Failover">failover</a>.</p> </div> <div class="sect2"> <h3 id="_typical_backup_procedure">4.1. Typical Backup Procedure</h3> <div class="paragraph"> <p>The SDP’s maintenance scripts, run as <em>cron</em> tasks on Unix/Linux or as Windows <em>scheduled tasks</em>, periodically back up the metadata. The weekly sequence is described below. See also <a href="#_scheduling_maintenance_scripts">Section 3.1.12, “Scheduling maintenance scripts”</a>.</p> </div> <div class="paragraph"> <p><strong>Seven nights a week, perform the following tasks.</strong></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Rotate/truncate the active journal.</p> </li> <li> <p>Replay the journal to the offline database. (Refer to Figure 2: Volume Layout for more information on the location of the live and offline databases.)</p> </li> <li> <p>Create a checkpoint from the offline database.</p> </li> <li> <p>Recreate the offline database from the last checkpoint.</p> </li> </ol> </div> <div class="paragraph"> <p><strong>Once a week, perform the following tasks.</strong></p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Verify all depots.</p> <div class="paragraph"> <p>This normal maintenance procedure puts the checkpoints (metadata snapshots) on the depotdata volume, which contains the versioned files. Backing up the depotdata volume with a normal backup utility like <em>robocopy</em> or <em>rsync</em> provides you with all the data necessary to recreate the server.</p> </div> <div class="paragraph"> <p>To ensure that the backup does not interfere with the metadata backups (checkpoints), coordinate backup of the depotdata volume using the SDP maintenance scripts.</p> </div> <div class="paragraph"> <p>The preceding maintenance procedure minimizes server downtime, because checkpoints are created from offline or saved databases while the server is running.</p> </div> </li> </ol> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> With no additional configuration, the normal maintenance prevents loss of more than one day’s metadata changes. To provide an optimal <a href="http://en.wikipedia.org/wiki/Recovery_point_objective">Recovery Point Objective</a> (RPO), the SDP provides additional tools for replication. </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="_planning_for_ha_and_dr">4.2. Planning for HA and DR</h3> <div class="paragraph"> <p>The concepts for HA (High Availability) and DR (Disaster Recovery) are fairly similar - they are both types of Helix Core replica.</p> </div> <div class="paragraph"> <p>When you have server specs with <code>Services</code> field set to <code>commit-server</code>, <code>standard</code>, or <code>edge-server</code> - see <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/deployment-architecture.html">deployment architectures</a> you should consider your requirements for how to recover from a failure to any such servers.</p> </div> <div class="paragraph"> <p>See also <a href="https://community.perforce.com/s/article/5434">Replica types and use cases</a></p> </div> <div class="paragraph"> <p>The key issues are around ensuring that you have have appropriate values for the following measures for your Helix Core installation:</p> </div> <div class="ulist"> <ul> <li> <p>RTO - Recovery Time Objective - how long will it take you to recover to a backup?</p> </li> <li> <p>RPO - Recovery Point Objective - how much data are you prepared to risk losing if you have to failover to a backup server?</p> </li> </ul> </div> <div class="paragraph"> <p>We need to consider planned vs unplanned failover. Planned may be due to upgrading the core Operating System or some other dependency in your infrastructure, or a similar activity.</p> </div> <div class="paragraph"> <p>Unplanned covers risks you are seeking to mitigate with failover:</p> </div> <div class="ulist"> <ul> <li> <p>loss of a machine, or some machine related hardware failure (e.g. network)</p> </li> <li> <p>loss of a VM cluster</p> </li> <li> <p>failure of storage</p> </li> <li> <p>loss of a data center or machine room</p> </li> <li> <p>etc…​</p> </li> </ul> </div> <div class="paragraph"> <p>So, if your main <code>commit-server</code> fails, how fast should be you be able to be up and running again, and how much data might you be prepared to lose? What is the potential disruption to your organisation if the Helix Core repository is down? How many people would be impacted in some way?</p> </div> <div class="paragraph"> <p>You also need to consider the costs of your mitigation strategies. For example, this can range from:</p> </div> <div class="ulist"> <ul> <li> <p>taking a backup once per 24 hours and requiring maybe an hour or two to restore it. Thus you might lose up to 24 hours of work for an unplanned failure, and require several hours to restore.</p> </li> <li> <p>having a high availability replica which is a mirror of the server hardware and ready to take over within minutes if required</p> </li> </ul> </div> <div class="paragraph"> <p>Having a replica for HA or DR is likely to reduce your RPO and RTO to well under an hour (<10 minutes if properly prepared for) - at the cost of the resources to run such a replica, and the management overhead to monitor it appropriately.</p> </div> <div class="paragraph"> <p>Typically we would define:</p> </div> <div class="ulist"> <ul> <li> <p>An HA replica is close to its upstream server, e.g. in the same Data Center - this minimizes the latency for replication, and reduces RPO</p> </li> <li> <p>A DR replica is in a more remote location, so maybe risks being further behind in replication (thus higher RPO), but mitigates against catastrophic loss of a data center or similar. Note that "further behind" is still typically seconds for metadata, but can be minutes for submits with many GB of files.</p> </li> </ul> </div> <div class="sect3"> <h4 id="_further_resources">4.2.1. Further Resources</h4> <div class="ulist"> <ul> <li> <p><a href="https://community.perforce.com/s/article/3166">High Reliability Solutions</a></p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_creating_a_failover_replica_for_commit_or_edge_server">4.2.2. Creating a Failover Replica for Commit or Edge Server</h4> <div class="paragraph"> <p>A commit server instance is the ultimate store for submitted data, and also for any workspace state (WIP - work in progress) for users directly working with the commit server (part of the same "data set")</p> </div> <div class="paragraph"> <p>An edge server instance maintains its own copy of workspace state (WIP). If you have people connecting to an edge server, then any workspaces they create (and files they open for some action) will be only stored on the edge server. Thus it is normally recommended to have an HA backup server, so that users don’t lose their state in case of failover.</p> </div> <div class="paragraph"> <p>There is a concept of a "build edge" which is an edge server which only supports build farm users. In this scenario it may be deemed acceptable to not have an HA backup server, since in the case of failure of the edge, it can be re-seeded from the commit server. All build farm clients would be recreated from scratch so there would be no problems.</p> </div> </div> <div class="sect3"> <h4 id="_what_is_a_failover_replica">4.2.3. What is a Failover Replica?</h4> <div class="paragraph"> <p>As of 2018.2 release, p4d supports a <code>p4 failover</code> command that performs a failover to a <code>standby</code> replica (i.e. a replica with <code>Services:</code> field value set to <code>standby</code> or <code>forwarding-standby</code>). Such a replica performs a <code>journalcopy</code> replication of metadata, with a local pull thread to update its <code>db.*</code> files.</p> </div> <div class="paragraph"> <p>See also: <a href="https://community.perforce.com/s/article/16462">Configuring a Helix Core Standby</a>.</p> </div> </div> <div class="sect3"> <h4 id="_mandatory_vs_non_mandatory_standbys">4.2.4. Mandatory vs Non-mandatory Standbys</h4> <div class="paragraph"> <p>You can modify the server spec of a <code>standby</code> replica to make it <code>mandatory</code>.</p> </div> <div class="paragraph"> <p>When a <code>standby</code> server instance is configured as mandatory, the master/commit server will wait until this server confirms it has processed journal data before allow that journal data to be released to other replicas. This can simplify failover, since it provides a guarantee that no downstream servers are <strong>ahead</strong> of the replica.</p> </div> <div class="paragraph"> <p>Thus downstream servers can simply be re-directed to point to the standby and will carry on working without problems.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> If a server which is marked as <code>mandatory</code> goes offline for any reason, the replication to other replicas will stop replicating. In this scenario, the server spec of the replica can be changed to <code>nomandatory</code>, and then replication will immediately resume (so long as the replication has not been offline for too long, typically several days or weeks depending on the KEEPJNLS setting). </td> </tr> </table> </div> <div class="paragraph"> <p>If set to <code>nomandatory</code> then there is no risk of delaying downstream replicas, however there is equally no guarantee that they will be able to switch seamlessly over to the new server.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> We recommend creating <code>mandatory</code> replica(s) if the server is local to its commit server, and also if you have good monitoring in place to quickly detect replication lag or other issues. </td> </tr> </table> </div> <div class="paragraph"> <p>To change a server spec to be <code>mandatory</code> or <code>nomandatory</code>, modify the server spec with a command like <code>p4 server p4d_ha_bos</code> to edit the form, and then change the value in the <code>Options:</code> field to be as desired, <code>mandatory</code> or <code>nomandatory</code>, and the save and exit the editor.</p> </div> </div> <div class="sect3"> <h4 id="_server_host_naming_conventions">4.2.5. Server host naming conventions</h4> <div class="paragraph"> <p>This is recommended, but not a requirement for SDP scripts to implement failover.</p> </div> <div class="ulist"> <ul> <li> <p>Use a name that does not indicate switchable roles, e.g. don’t indicate in the name whether a host is a master/primary or backup, or edge server and its backup. This might otherwise lead to confusion once you have performed a failover and the host name is no longer appropriate.</p> </li> <li> <p>Use names ending numeric designators, e.g. -01 or -05. The goal is to avoid being in a post-failover situation where a machine with <code>master</code> or <code>primary</code> is actually the backup. Also, the assumption is that host names will never need to change.</p> </li> <li> <p>While you don’t want switchable roles baked into the hostname, you can have static roles, e.g. use p4d vs. p4p in the host name (as those generally don’t change). The p4d could be primary, standby, edge, edge’s standby (switchable roles).</p> </li> <li> <p>Using a short geographic site is sometimes helpful/desirable. If used, use the same site tag used in the ServerID, e.g. aus.</p> </li> <li> <p>Using a short tag to indicate the major OS version is <strong>sometimes</strong> helpful/desirable, eg. c7 for CentOS 7, or r8 for RHEL 8. This is based on the idea that when the major OS is upgraded, you either move to new hardware, or change the host name (an exception to the rule above about never changing the hostname). This option maybe overkill for many sites.</p> </li> <li> <p>End users should reference a DNS name that may include the site tag, but would exclude the number, OS indicator, and server type (<code>p4d</code>/<code>p4p</code>/<code>p4broker</code>), replacing all that with just <code>perforce</code> or optionally just <code>p4</code>. General idea is that users needn’t be bothered by under-the-covers tech of whether something is a proxy or replica.</p> </li> <li> <p>For edge servers, it is advisable to include <code>edge</code> in both the host and DNS name, as users and admins needs to be aware of the functional differences due to a server being an edge server.</p> </li> </ul> </div> <div class="paragraph"> <p>Examples:</p> </div> <div class="ulist"> <ul> <li> <p><code>p4d-aus-r7-03</code>, a master in Austin on RHEL 7, pointed to by a DNS name like <code>p4-aus</code>.</p> </li> <li> <p><code>p4d-aus-03</code>, a master in Austin (no indication of server OS), pointed to by a DNS name like <code>p4-aus</code>.</p> </li> <li> <p><code>p4d-aus-r7-04</code>, a standby replica in Austin on RHEL 7, not pointed to by a DNS until failover, at which point it gets pointed to by <code>p4-aus</code>.</p> </li> <li> <p><code>p4p-syd-r8-05</code>, a proxy in Sydney on RHEL 8, pointed to by a DNS name like <code>p4-syd</code>.</p> </li> <li> <p><code>p4d-syd-r8-04</code>, a replica that replaced the proxy in Sydney, on RHEL 8, pointed to by a DNS name like <code>p4-syd</code> (same as the proxy it replaced).</p> </li> <li> <p><code>p4d-edge-tok-s12-03</code>, an edge in Tokyo running SuSE12, pointed to by a DNS name like <code>p4edge-tok</code>.</p> </li> <li> <p><code>p4d-edge-tok-s12-04</code>, a replica of an edge in Tokyo running SuSE12, not pointed to by a DNS name until failover, at which point it gets pointed to by <code>p4edge-tok</code>.</p> </li> </ul> </div> <div class="paragraph"> <p>FQDNs (fully qualified DNS names) of short DNS names used in these examples would also exist, and would be based on the same short names.</p> </div> </div> <div class="sect3"> <h4 id="_pre_requisites_for_failover">4.2.6. Pre-requisites for Failover</h4> <div class="paragraph"> <p>These are vital as part of your planning.</p> </div> <div class="ulist"> <ul> <li> <p>Obtain and install a license for your replica(s)</p> <div class="paragraph"> <p>Your commit or standard server has a license file (tied to IP address), while your replicas do not require one to function as replicas.</p> </div> <div class="paragraph"> <p>However, in order for a replica to function as a replacement for a commit or standard server, it must have a suitable license installed.</p> </div> <div class="paragraph"> <p>This should be requested when the replica is first created. See the form: <a href="https://www.perforce.com/support/duplicate-server-request" class="bare">https://www.perforce.com/support/duplicate-server-request</a></p> </div> </li> <li> <p>Review your authentication mechanism (LDAP etc) - is the LDAP server contactable from the replica machine (firewalls etc configured appropriately).</p> </li> <li> <p>Review all your triggers and how they are deployed - will they work on the failover host?</p> <div class="paragraph"> <p>Is the right version of Perl/Python etc correctly installed and configured on the failover host with all imported libraries?</p> </div> </li> </ul> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> TEST, TEST, TEST!!! It is important to test the above issues as part of your planning. For peace of mind you don’t want to be finding problems at the time of trying to failover for real, which may be in the middle of the night! </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="_full_one_way_replication">4.3. Full One-Way Replication</h3> <div class="paragraph"> <p>Perforce supports a full one-way <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/replication.html">replication</a> of data from a master server to a replica, including versioned files. The <a href="https://www.perforce.com/manuals/cmdref/Content/CmdRef/p4_pull.html#p4_pull">p4 pull</a> command is the replication mechanism, and a replica server can be configured to know it is a replica and use the replication command. The p4 pull mechanism requires very little configuration and no additional scripting. As this replication mechanism is simple and effective, we recommend it as the preferred replication technique. Replica servers can also be configured to only contain metadata, which can be useful for reporting or offline checkpointing purposes. See the Distributing Perforce Guide for details on setting up replica servers.</p> </div> <div class="paragraph"> <p>If you wish to use the replica as a read-only server, you can use the <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/chapter.broker.html">P4Broker</a> to direct read-only commands to the replica or you can use a forwarding replica. The broker can do load balancing to a pool of replicas if you need more than one replica to handle your load.</p> </div> <div class="sect3"> <h4 id="_replication_setup">4.3.1. Replication Setup</h4> <div class="paragraph"> <p>To configure a replica server, first configure a machine identically to the master server (at least as regards the link structure such as <code>/p4</code>, <code>/p4/common/bin</code> and <code>/p4/<strong><em>instance</em></strong>/*</code>), then install the SDP on it to match the master server installation. Once the machine and SDP install is in place, you need to configure the master server for replication.</p> </div> <div class="paragraph"> <p>Perforce supports many types of replicas suited to a variety of purposes, such as:</p> </div> <div class="ulist"> <ul> <li> <p>Real-time backup,</p> </li> <li> <p>Providing a disaster recovery solution,</p> </li> <li> <p>Load distribution to enhance performance,</p> </li> <li> <p>Distributed development,</p> </li> <li> <p>Dedicated resources for automated systems, such as build servers, and more.</p> </li> </ul> </div> <div class="paragraph"> <p>We always recommend first setting up the replica as a read-only replica and ensuring that everything is working. Once that is the case you can easily modify server specs and configurables to change it to a forwarding replica, or an edge server etc.</p> </div> </div> </div> <div class="sect2"> <h3 id="_replication_setup_details">4.4. Replication Setup Details</h3> <div class="paragraph"> <p>Note, it is required that you set P4TICKETS for the service and for the users on the machine to a common location for replication to work. To set this up, run the following on both the master and the replica:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 set -s P4TICKETS=c:\p4\1\p4tickets.txt p4 set -S p4_1 P4TICKETS=c:\p4\1\p4tickets.txt</pre> </div> </div> <div class="paragraph"> <p>Once the machine and SDP install is in place, you need to configure the master server for replication. We will assume the following for the setup:</p> </div> <div class="paragraph"> <p>The replica name will be <code>p4d_ha_lon</code>, the service user name is <code>svc_rp4d_ha_lon</code>, and the master server’s name is <code>master</code>, and the metadata volume is <code>e:</code>, the depotdata volume is <code>f:</code>, and the logs volume is <code>g:</code>. You will run the following commands on the master server:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 configure set P4TICKETS=c:\p4\1\p4tickets.txt p4 configure set p4d_ha_lon#P4PORT=1667 p4 configure set p4d_ha_lon#P4TARGET=master:1667 p4 configure set p4d_ha_lon#journalPrefix=c:\p4\1\checkpoints\p4_1 p4 configure set p4d_ha_lon#server=3 p4 configure set "p4d_ha_lon#startup.1=pull -i 1" p4 configure set "p4d_ha_lon#startup.2=pull -u -i 1" p4 configure set "p4d_ha_lon#startup.3=pull -u -i 1" p4 configure set "p4d_ha_lon#startup.4=pull -u -i 1" p4 configure set "p4d_ha_lon#startup.5=pull -u -i 1" p4 configure set "p4d_ha_lon#db.replication=readonly" p4 configure set "p4d_ha_lon#lbr.replication=readonly" p4 configure set p4d_ha_lon#serviceUser=svc_p4d_ha_lon</pre> </div> </div> <div class="paragraph"> <p>The following commands will also need to be run:</p> </div> <div class="ulist"> <ul> <li> <p><code>p4 user -f svc_p4d_ha_lon</code> (You need to add the <code>Type: service</code> field to the user form before saving)</p> </li> <li> <p><code>p4 passwd svc_p4d_ha_lon</code> (Set the service user’s password)</p> </li> <li> <p><code>p4 group ServiceUsers</code> (Add the service user to the <code>Users:</code> section and set the <code>Timeout:</code> to unlimited.)</p> </li> <li> <p><code>p4 protect</code> (Give <code>super</code> rights to the group <code>ServiceUsers</code> to <code>//…​</code>)</p> </li> </ul> </div> <div class="paragraph"> <p>Now that the settings are in the master server, you need to create a checkpoint to seed the replica. Run:</p> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\common\bin\daily-backup.ps1 1</pre> </div> </div> <div class="paragraph"> <p>When the checkpoint finishes, copy the checkpoint plus the versioned files over to the replica server. You can use xcopy or something like robocopy for this step.</p> </div> <div class="literalblock"> <div class="content"> <pre>xcopy c:\p4\1\checkpoints\p4_1.ckp.###.gz replica_f_drive:\p4\1\checkpoints</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>xcopy c:\p4\1\depots replica_f_drive:\p4\1\depots /S</pre> </div> </div> <div class="paragraph"> <p>(<mark>#</mark> is the checkpoint number created by the daily backup)</p> </div> <div class="paragraph"> <p>Once the copy finishes, go to the replica machine run the following:</p> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\1\bin\p4d -r c:\p4\1\root -jr -z c:\p4\1\checkpoints\p4_1.ckp.###.gz c:\p4\1\bin\p4 -p master:1667 -u svc_p4d_ha_lon login (enter the service user's password) c:\p4\common\bin\svcinst start -n p4_1</pre> </div> </div> <div class="paragraph"> <p>Now, you check the log on the master server (<code>c:\p4\1\logs\log</code>) to look for the rmt-Journal entries that show you the replication is running. If you see those entries, then you can make some changes on the master server, and then go to the replica server and check to see that they changes were replicated across. For example, you can submit a change to the master server, then go to the replica server and check to see that the change was replicated over to the replica by running p4 describe on the changelist against the replica server.</p> </div> <div class="paragraph"> <p>The final steps for setting up the replica server are to set up the task scheduler to run the replica sync scripts. This has to be done via task scheduler running as a regular AD user so that the scripts can access the network in order to get to the drives on the replica machine.</p> </div> <div class="paragraph"> <p>You need to configure a task to run <code>c:\p4\common\bin\sync-replica.ps1 <instance></code> every day. The task should be set up to run after the master server finishes running <code>daily-backup.ps1</code>. Be sure to give it some buffer for the length of time it takes the master to run that script is likely to become gradually longer over time.</p> </div> </div> <div class="sect2"> <h3 id="_recovery_procedures">4.5. Recovery Procedures</h3> <div class="paragraph"> <p>There are three scenarios that require you to recover server data:</p> </div> <table class="tableblock frame-all grid-all stretch"> <colgroup> <col style="width: 33.3333%;"> <col style="width: 33.3333%;"> <col style="width: 33.3334%;"> </colgroup> <thead> <tr> <th class="tableblock halign-left valign-top">Metadata</th> <th class="tableblock halign-left valign-top">Depotdata</th> <th class="tableblock halign-left valign-top">Action required</th> </tr> </thead> <tbody> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">lost or corrupt</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">intact</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Recover metadata as described below</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">Intact</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">lost or corrupt</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">Call Perforce Support</p></td> </tr> <tr> <td class="tableblock halign-left valign-top"><p class="tableblock">lost or corrupt</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">lost or corrupt</p></td> <td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph"> <p>Recover metadata as described below.</p> </div> <div class="paragraph"> <p>Recover the depotdata volume using your normal backup utilities.</p> </div></div></td> </tr> </tbody> </table> <div class="paragraph"> <p>Restoring the metadata from a backup also optimizes the database files.</p> </div> <div class="sect3"> <h4 id="_recovering_from_a_checkpoint_and_journals">4.5.1. Recovering from a checkpoint and journal(s)</h4> <div class="paragraph"> <p>The checkpoint files are stored in the <code>c:\p4\<instance>\checkpoints</code> directory, and the most recent checkpoint is named <code>p4_<instance>.ckp.<number>.gz</code>. Recreating up-to-date database files requires the most recent checkpoint, from c:\p4\<instance>\checkpoints, and the journal file from c:\p4\<instance>\logs.</p> </div> <div class="paragraph"> <p>To recover the server database manually, perform the following steps from the root directory of the server (<code>c:\p4\<instance>\root</code>). In the examples below we assume the <instance> is <code>1</code>.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Stop the Perforce Server by issuing the following command:</p> <div class="literalblock"> <div class="content"> <pre>c:\p4\1\bin\p4 admin stop</pre> </div> </div> </li> <li> <p>Delete the old database files in <code>c:\p4\1\root\save</code> directory (note there may not be any files there as they will typically be cleared out <strong>after</strong> successful completion of the previous invocation of the recovery process - see below).</p> </li> <li> <p>Move the live database files (db.*) to the save directory.</p> </li> <li> <p>Use the following command to restore from the most recent checkpoint.</p> <div class="literalblock"> <div class="content"> <pre>c:\p4\1\bin\p4d -r c:\p4\1\root -jr -z</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\1\checkpoints\p4_1.ckp.<most recent #>.gz</pre> </div> </div> </li> <li> <p>To replay the transactions that occurred after the checkpoint was created, issue the following command:</p> <div class="literalblock"> <div class="content"> <pre>c:\p4\1\bin\p4d -r c:\p4\1\root -jr c:\p4\1\logs\journal</pre> </div> </div> </li> <li> <p>Restart your Perforce server.</p> </li> </ol> </div> <div class="paragraph"> <p>If the Perforce service starts without errors, delete the old database files from <code>c:\p4\1\root\save</code>.</p> </div> <div class="paragraph"> <p>If problems are reported when you attempt to recover from the most recent checkpoint, try recovering from the preceding checkpoint and journal. If you are successful, replay the subsequent journal. If the journals are corrupted, contact <a href="mailto:support@perforce.com">Perforce Technical Support</a>. For full details about back up and recovery, refer to the <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/chapter.backup.html">Perforce System Administrator’s Guide</a>.</p> </div> </div> <div class="sect3"> <h4 id="_recovering_from_a_tape_backup">4.5.2. Recovering from a tape backup</h4> <div class="paragraph"> <p>This section describes how to recover from a tape or other offline backup to a new server machine if the server machine fails. The tape backup for the server is made from the depotdata volume. The new server machine must have the same volume layout and user/group settings as the original server. In other words, the new server must be as identical as possible to the server that failed.</p> </div> <div class="paragraph"> <p>To recover from a tape backup, perform the following steps.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Recover the depotdata volume from your backup tape.</p> </li> <li> <p>As a super-user, reinstall and enable the Windows services that run the Perforce instance.</p> </li> <li> <p>Find the last available checkpoint, under <code>c:\p4\<instance>\checkpoints</code>.</p> </li> <li> <p>Recover the latest checkpoint by running:</p> <div class="literalblock"> <div class="content"> <pre>c:\p4\<instance>\bin\p4d_<instance> -r c:\p4\<instance>\root -jr -z _last_ckp_file_</pre> </div> </div> </li> </ol> </div> <div class="olist arabic"> <ol class="arabic" start="5"> <li> <p>Recover the checkpoint (as shown in the preceding step) into the offline_db directory rather than the root directory.</p> </li> </ol> </div> <div class="paragraph"> <p>c:\p4\<instance>\bin\p4d_<instance> -r c:\p4\<instance>\offline_db -jr -z <em>last_ckp_file</em></p> </div> <div class="olist arabic"> <ol class="arabic" start="6"> <li> <p>Reinstall the Perforce server license to the server root directory.</p> </li> <li> <p>Start the Perforce service.</p> </li> <li> <p>Verify that the server instance is running.</p> </li> <li> <p>Reinstall the server crontab or scheduled tasks.</p> </li> <li> <p>Perform any other initial server machine configuration.</p> </li> <li> <p>Verify the database and versioned files by running the p4verify script. Note that files using the <a href="https://www.perforce.com/manuals/cmdref/Content/CmdRef/file.types.synopsis.modifiers.html">+k</a> file type modifier might be reported as BAD! after being moved. Contact Perforce Technical Support for assistance in determining if these files are actually corrupt.</p> </li> </ol> </div> </div> <div class="sect3"> <h4 id="_failover_to_a_replicated_standby_machine">4.5.3. Failover to a replicated standby machine</h4> <div class="paragraph"> <p>See <a href="SDP_Failover_Guide.pdf">SDP Failover Guide (PDF)</a> or <a href="SDP_Failover_Guide.html">SDP Failover Guide (HTML)</a> for detailed steps.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_server_maintenance">5. Server Maintenance</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes typical maintenance tasks and best practices for administering server machines. The directory <code>c:\p4\sdp\Unsupported</code> contains scripts for several common maintenance tasks.</p> </div> <div class="paragraph"> <p>The user running the maintenance scripts must have administrative access to Perforce for most activities. All of these scripts can be run from any client machine.</p> </div> <div class="sect2"> <h3 id="_server_upgrades">5.1. Server upgrades</h3> <div class="paragraph"> <p>Upgrading a server instance in the SDP framework is a simple process involving a few steps.</p> </div> <div class="ulist"> <ul> <li> <p>Download the new p4 and p4d executables from <a href="ftp://ftp.perforce.com/perforce">ftp.perforce.com</a> and place them in <code>c:\p4\common\bin</code></p> </li> <li> <p>Run <code>c:\p4\common\bin\upgrade.ps1 <instance></code>, e.g.</p> <div class="literalblock"> <div class="content"> <pre>powershell -f c:\p4\common\bin\upgrade.ps1 1</pre> </div> </div> </li> </ul> </div> <div class="admonitionblock warning"> <table> <tr> <td class="icon"> <i class="fa icon-warning" title="Warning"></i> </td> <td class="content"> If upgrading a pre-2013.3 server, then this will require a checkpoint restore and the script cannot be used. Contact Perforce Support if in doubt. </td> </tr> </table> </div> <div class="sect3"> <h4 id="_database_modifications">5.1.1. Database Modifications</h4> <div class="paragraph"> <p>Occasionally modifications are made to the Perforce database. For example, server upgrades and some recovery procedures modify the database.</p> </div> <div class="paragraph"> <p>When upgrading the server, replaying a journal patch, or performing any activity that modifies the db.* files, you must restart the offline checkpoint process so that the files in the offline_db directory match the ones in the live server directory. The easiest way to restart the offline checkpoint process is to run the live-checkpoint script after modifying the db.* files <a href="#_live_checkpoint_ps1">Section 7.3.5, “live-checkpoint.ps1”</a></p> </div> </div> <div class="sect3"> <h4 id="_unloading_and_reloading_labels">5.1.2. Unloading and Reloading labels</h4> <div class="paragraph"> <p>Archiving labels is a best practice for large installations, with hundreds of users and Perforce checkpoints that are gigabytes in size. Smaller sites need not necessarily concern themselves with archiving labels to maintain performance, though doing so will minimize database size if labels are used extensively.</p> </div> <div class="paragraph"> <p>To use the <code>p4 unload</code> and <code>p4 reload</code> commands for archiving clients and labels, you must first create an unload depot using the p4 depot command. Run:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 depot unload</pre> </div> </div> <div class="paragraph"> <p>Set the type of the depot to unload and save the form.</p> </div> <div class="paragraph"> <p>After the depot is created, you can use the following command to archive all the clients and labels that have been accessed since the given date:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 unload -f -L -z -a -d <date></pre> </div> </div> <div class="paragraph"> <p>For example, to unload all clients and labels that haven’t been accessed since Jan. 1, 2019, you would run:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 unload -f -L -z -a -d 2019/01/01</pre> </div> </div> <div class="paragraph"> <p>Users can reload their own clients/labels using the reload command. They can run:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 reload -c <clientname></pre> </div> </div> <div class="paragraph"> <p>or</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 reload -l <labelname></pre> </div> </div> <div class="paragraph"> <p>As a super user, you can reload and unloaded item by adding the -f flag to the reload command as follows:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 reload -f -c|l <specname></pre> </div> </div> <div class="paragraph"> <p>In addition, you can avoid having to unload/reload labels by creating a trigger to set the autoreload option as the default on all new labels. That will cause the server to use the unload depot for storing the labels rather than storing them in db.label. This helps with performance of the server by not increasing the size of the database for label storage.</p> </div> <div class="paragraph"> <p>You can automate these tasks with $SDP/Maintenance/unload_clients.py and $SDP/Maintenance/unload_labels.py</p> </div> </div> <div class="sect3"> <h4 id="_workspace_management">5.1.3. Workspace management</h4> <div class="paragraph"> <p>The simplest option is to use create a template client workspace (usual name is <code>template.client</code>) and then set configurable <code>template.client</code> to that name. This will mean that all new client workspaces created after that time will have the same options and view, unless otherwise explicitly updated.</p> </div> <div class="literalblock"> <div class="content"> <pre>p4 client template.client [edit and save]</pre> </div> </div> <div class="literalblock"> <div class="content"> <pre>p4 configure set template.client=template.client</pre> </div> </div> <div class="paragraph"> <p>Alternatively the old fashioned way is to install a trigger from the Unsupported/Samples/triggers folder.</p> </div> <div class="paragraph"> <p>The <a href="https://www.perforce.com/perforce/doc.current/manuals/p4sag/Content/P4SAG/scripting.triggers.basics.html">form-out trigger</a> $SDP/Unsupported/Sample/triggers/SetWsOptions.py contains default <a href="https://www.perforce.com/manuals/cmdref/Content/CmdRef/p4_client.html#p4_client">workspace options</a>, such as leaveunchanged instead of submitunchanged.</p> </div> <div class="paragraph"> <p>To use the trigger, first copy it to /p4/common/bin/triggers</p> </div> <div class="paragraph"> <p>To enable the trigger, first modify the OPTIONS variable in the script, providing the set of desired options. Then insert an entry in the trigger table like the following:</p> </div> <div class="literalblock"> <div class="content"> <pre>setwsopts form-out client "python /p4/common/bin/triggers/SetWsOptions.py %formfile%"</pre> </div> </div> <div class="paragraph"> <p>The <a href="http://www.perforce.com/perforce/doc.current/manuals/p4sag/06_scripting.html#1062348">form-save trigger</a> $SDP/Server/common/p4/common/bin/triggers/PreventWsNonAscii.py enforces the policy that no workspaces may contain non-ASCII characters.</p> </div> <div class="paragraph"> <p>To use the trigger, first copy it to /p4/common/bin/triggers</p> </div> <div class="paragraph"> <p>To enable the trigger, insert an entry in the trigger table like the following:</p> </div> <div class="literalblock"> <div class="content"> <pre>nowsascii form-save client "python /p4/common/bin/triggers/PreventWsNonAscii.py %formfile%"</pre> </div> </div> </div> <div class="sect3"> <h4 id="_removing_empty_changelists">5.1.4. Removing empty changelists</h4> <div class="paragraph"> <p>To delete empty pending changelists, run python remove_empty_pending_changes.py.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_maximizing_server_performance">6. Maximizing Server Performance</h2> <div class="sectionbody"> <div class="paragraph"> <p>The following sections provide some guidelines for maximizing the performance of the Perforce Server, using tools provided by the SDP. More information on this topic can be found in the <a href="https://community.perforce.com/s/article/2529">Knowledge Base</a>.</p> </div> <div class="sect2"> <h3 id="_optimizing_the_database_files">6.1. Optimizing the database files</h3> <div class="paragraph"> <p>The Perforce Server’s database is composed of b-tree files. The server does not fully rebalance and compress them during normal operation. To optimize the files, you must checkpoint and restore the server. The weekly checkpoint script used as part of the normal server maintenance automates this task.</p> </div> <div class="paragraph"> <p>To minimize the size of back up files and maximize server performance, minimize the size of the db.have and db.label files. The scripts described in Unloading and Reloading labels, <strong>Deleting users</strong>, and</p> </div> </div> <div class="sect2"> <h3 id="_managing_server_load">6.2. Managing server load</h3> <div class="sect3"> <h4 id="_limiting_large_requests">6.2.1. Limiting large requests</h4> <div class="paragraph"> <p>To prevent large requests from overwhelming the server, you can limit the amount of data and time allowed per query by setting the maxresults, maxscanrows and maxlocktime parameters to the lowest setting that does not interfere with normal daily activities. As a good starting point, set maxscanrows to maxresults * 3; set maxresults to slightly larger than the maximum number of files the users need to be able to sync to do their work; and set maxlocktime to 30000 milliseconds. These values must be adjusted up as the size of your server and the number of revisions of the files grow. To simplify administration, assign limits to groups rather than individual users.</p> </div> <div class="paragraph"> <p>To prevent users from inadvertently accessing large numbers of files, define their client view to be as narrow as possible, considering the requirements of their work. Similarly, limit users' access in the protections table to the smallest number of directories that are required for them to do their job.</p> </div> <div class="paragraph"> <p>Finally, keep triggers simple. Complex triggers increase load on the server.</p> </div> </div> <div class="sect3"> <h4 id="_offloading_remote_syncs">6.2.2. Offloading remote syncs</h4> <div class="paragraph"> <p>For remote users who need to sync large numbers of files, Perforce offers a <a href="http://perforce.com/perforce/doc.current/manuals/p4sag/09_p4p.html#1056059">proxy server</a>. P4P, the Perforce Proxy, is run on a machine that is on the remote users' local network. The Perforce Proxy caches file revisions, serving them to the remote users and diverting that load from the main server.</p> </div> <div class="paragraph"> <p>P4P is included in the Windows installer.</p> </div> <div class="paragraph"> <p>P4P does not require special hardware because it doesn’t use much processing power, and it doesn’t need to be backed up. If the P4P instance isn’t working, users can switch their port back to the main server and continue working until the instance of P4P is fixed.</p> </div> </div> </div> <div class="sect2"> <h3 id="_p4v_performance_settings">6.3. P4V performance settings</h3> <div class="paragraph"> <p>At large sites with hundreds or thousands of simultaneous users, the P4V data retrieval settings can help prevent P4V requests from impacting server performance. As of the 2010.1 release, P4V settings that affect performance can be centrally managed for all users or specific groups of users, using the <a href="http://www.perforce.com/perforce/doc.current/manuals/p4jsapi/index.html">JavaScript API</a> (P4JsApi).</p> </div> <div class="paragraph"> <p>The SDP includes a sample P4V settings file, along with the P4JsApi centralsettings file that enables it. These files are located in //Perforce/sdp/JsApi.</p> </div> <div class="paragraph"> <p>Follow these steps to provide P4V performance settings for your users.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Determine whether you want P4V settings common to all users, or different settings for different groups. If the latter, make a unique copy of //Perforce/sdp/JsApi/p4vsettings.xml for each group of users. For example, you may create //Perforce/sdp/JsApi/p4vsettings_dev.xml for developers and //Perforce/sdp/JsApi/p4vsettings_qa.xml for QA.</p> </li> <li> <p>Review and set the performance limits in //Perforce/sdp/JsApi/p4vsettings.xml, or in each copy of this file. (The file contains suggested default values.) The available settings are:</p> <div class="olist loweralpha"> <ol class="loweralpha" type="a"> <li> <p>The ServerRefresh interval in minutes, which defines how often P4V attempts to get updated information from the server.</p> </li> <li> <p>The MaxFiles that P4V will retrieve for one fetch command.</p> </li> <li> <p>The MaxFilePreviewSize in kilobytes.</p> </li> <li> <p>The FetchCount, which affects the number of forms fetched for some operations.</p> </li> </ol> </div> </li> <li> <p>If using common settings for all users, proceed with this step; otherwise proceed to the next step. Install the centralsettings file by adding a line to the protections table like:</p> <div class="literalblock"> <div class="content"> <pre>list group All.G centralsettings //Perforce/sdp/JsApi/centralsettings.js</pre> </div> </div> </li> </ol> </div> <div class="paragraph"> <p>(This line assumes that you have a group called All.G that represents all users.)</p> </div> <div class="olist arabic"> <ol class="arabic" start="4"> <li> <p>(Skip this step if using common settings for all users.) If using different settings for different groups, create a copy of //Perforce/sdp/JsApi/centralsettings.js for each group of users. For example, you may create //Perforce/sdp/JsApi/centralsettings_dev.js for developers and //Perforce/sdp/JsApi/centralsettings_qa.js for QA. Modify the line that references p4vsettings.xml to reference the copy for the group.</p> </li> <li> <p>(Skip this step if using common settings for all users.) Install each copy of centralsettings.js in the protections table. In our example with separate copies for developers and QA, we would use lines like:</p> <div class="literalblock"> <div class="content"> <pre>list group Dev.G centralsettings //Perforce/sdp/JsApi/centralsettings_dev.js list group QA.G centralsettings //Perforce/sdp/JsApi/centralsettings_qa.js</pre> </div> </div> </li> </ol> </div> <div class="olist arabic"> <ol class="arabic" start="6"> <li> <p>Each P4V user must follow the instructions in the P4JsApi manual to enable P4V extensions.</p> </li> </ol> </div> <div class="paragraph"> <p>Of course, the P4JsApi provides many other valuable features. If you choose to use these features, you can use the same centralsettings files for your groups to enable them. Refer to the P4JsApi manual for details.</p> </div> </div> </div> </div> <div class="sect1"> <h2 id="_tools_and_scripts">7. Tools and Scripts</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes the various scripts and files provided as part of the SDP package on Windows.</p> </div> <div class="paragraph"> <p>Scripts are located typically in the following directory unless otherwise specified:</p> </div> <div class="literalblock"> <div class="content"> <pre>c:\p4\common\bin</pre> </div> </div> <div class="paragraph"> <p>The following sections describe the scripts in detail.</p> </div> <div class="sect2"> <h3 id="_standard_scripts">7.1. Standard scripts</h3> <div class="paragraph"> <p>The scripts are implemented in <strong>Powershell</strong>, and usually have a simple <code>.bat</code> wrapper script. Note that for historical reasons there will often be 2 versions of the <code>.bat</code> which both call the same underlying Powershell script. For example, one uses '-' and one '_' as separators:</p> </div> <div class="literalblock"> <div class="content"> <pre>daily-backup.bat daily_backup.bat</pre> </div> </div> <div class="paragraph"> <p>Both are effectively identical and call the same Powershell script like this:</p> </div> <div class="literalblock"> <div class="content"> <pre>powershell -file c:\p4\common\bin\daily-backup.ps1 %1</pre> </div> </div> <div class="paragraph"> <p>In the sub-sections below we refer to the <code>.ps1</code> scripts. Please assume the <code>.bat</code> calling wrappers are present.</p> </div> </div> <div class="sect2"> <h3 id="_core_scripts">7.2. Core scripts</h3> <div class="sect3"> <h4 id="_daily_backup_ps1">7.2.1. daily-backup.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/daily-backup.ps1">This script</a> is configured to run seven days a week using the Windows scheduler. The script truncates the journal, replays it into the <code>offline_db</code> directory, creates a new checkpoint from the resulting database files, then recreates the <code>offline_db</code> directory from the new checkpoint.</p> </div> <div class="paragraph"> <p>This procedure rebalances and compresses the database files in the offline_db directory. These can be rotated into the live database directory on an occasional (e.g. monthly) basis using <a href="#_recreate_live_from_offline_db_ps1">Section 7.3.8, “recreate-live-from-offline-db.ps1”</a>.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Daily_Backup.ps1 performs journal rotation to offline database and creates offline checkpoint .Description Admin access is required. Also recovers from the offline checkpoint to ensure that it is good, and that offline DB files are unfragmented. .Parameter sdp-instance The specified instance to backup .Example daily_backup.ps1 Master .Example daily_backup.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_p4verify_ps1">7.2.2. p4verify.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/p4verify.ps1">This script</a> verifies the integrity of the depot files. This script is run by Windows scheduler, usually on a weekly basis, e.g. Saturday morning. It emails the resulting report - please check for any errors contained.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> for larger repositories this can take many hours to run, and places some load on the server. Run it at the weekends when this is less of a problem. </td> </tr> </table> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis p4verify.ps1 performs p4d archive verification on all appropriate depots .Description Runs "p4 verify -qz //depot/..." as appropriate to the depot type. For replicas it adds the "-t" flag to transfer missing revisions. Sends an error message with errors if BAD! or MISSING! is found in the output. .Parameter sdp-instance The specified SDP instance to verify .Example p4verify.ps1 Master .Example p4verify.ps1 1 #></code></pre> </div> </div> </div> </div> <div class="sect2"> <h3 id="_other_scripts_and_tools">7.3. Other scripts and tools</h3> <div class="sect3"> <h4 id="_create_filtered_edge_checkpoint_ps1">7.3.1. create-filtered-edge-checkpoint.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/create-filtered-edge-checkpoint.ps1">This script</a> creates a checkpoint from the offline_db files, filtered for use with an edge server. Note restrictions below.</p> </div> <div class="paragraph"> <p>See also partner script <a href="#_recover_edge_ps1">Section 7.3.7, “recover-edge.ps1”</a> which replays the checkpoint on the edge server machine.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Creates a filtered edge checkpoint from a master offline database. The resulting checkpoint can be copied to the remote edge server and restored using recover-edge.ps1 .Description Create filtered checkpoint using the server spec (output of 'p4 server -o', and in particular the fields RevisionDataFilter: and ArchiveDataFilter: which specify filtering). IMPORTANT NOTE: Because this uses the offline database, you can not just edit an existing server spec to change the filter and have it picked up by this script. After changing the server spec for the live server, you must ensure that the metadata changes are reflected in the offline_db - which is easy to do by running daily-backup.ps1 as normal (this rotates the journal and applies it to offline_db). Alternatively you can wait until the following day to run this script, by which time a scheduled daily backup should have run! Output of this script: A gzipped (filtered) checkpoint file, reflecting the name of the current instance. E.g. if current instance is Master, then result will be c:\p4\Master\checkpoints\p4_Master.ckp.filtered-edge.193.gz where 193 is the latest numbered checkpoint in that directory. .Parameter SDPInstance The specified instance to process, e.g. 1 or Master .Parameter EdgeServer The specified id of edge server (a server spec visible in output of 'p4 servers' command). .Example create-filtered-edge-checkpoint.ps1 Master Edge-server #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_create_offline_db_from_checkpoint_ps1">7.3.2. create-offline-db-from-checkpoint.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/create-offline-db-from-checkpoint.ps1">This script</a> recreates offline db from the latest checkpoint found.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Create-offline-db-from-checkpoint.ps1 recreates offline_db using latest checkpoint found. .Description This script recreates offline_db files from the latest checkpoint. If it fails, then check to see if the most recent checkpoint in the c:\p4\<INSTANCE>\checkpoints directory is bad (ie doesn't look like the right size compared to the others), and if so, delete it and rerun this script. If the error you are getting is that the journal replay failed, then the only option is to run live-checkpoint.ps1 script (which locks database while it runs). .Parameter sdp-instance The specified instance to process .Example Create-offline-db-from-checkpoint.ps1 Master .Example Create-offline-db-from-checkpoint.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_grep_exe">7.3.3. grep.exe</h4> <div class="paragraph"> <p>Windows version of Unix <code>grep</code> command. Useful for searching inside files.</p> </div> <div class="paragraph"> <p>There is a Windows equivalent which is <code>findstr</code> (although not as powerful).</p> </div> </div> <div class="sect3"> <h4 id="_gzip_exe">7.3.4. gzip.exe</h4> <div class="paragraph"> <p>Windows version of Unix <code>gzip</code> command - useful for checkpoint (de)compression.</p> </div> </div> <div class="sect3"> <h4 id="_live_checkpoint_ps1">7.3.5. live-checkpoint.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/live-checkpoint.ps1">This script</a> stops the server, creates a checkpoint from the live database files, recovers from that checkpoint to rebalance and compress the files, then recovers the checkpoint in the offline_db directory to ensure that the database files are optimized.</p> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> This script should only be run on your commit server (it should not be run on edge servers or replicas). Be aware that this script <strong>locks the database</strong> for the duration of the checkpoint. This can take tens of minutes or even hours to run. So be careful! </td> </tr> </table> </div> <div class="paragraph"> <p>This script makes a new checkpoint of the modified database files in the live root directory, then recovers that checkpoint to the offline_db directory so that both directories are in sync. This script can also be used anytime to create a checkpoint of the live database (with above warnings about locking!).</p> </div> <div class="paragraph"> <p>This command may be required to be run when an error occurs during offline checkpointing. It restarts the offline checkpoint process from the live database files to bring the offline copy back in sync. If the live checkpoint script fails, contact Perforce Consulting at <a href="mailto:consulting@perforce.com">consulting@perforce.com</a>.</p> </div> <div class="paragraph"> <p>Run this script when creating the server and if an error occurs while replaying a journal during the off-line checkpoint process.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Live_checkpoint.ps1 checkpoints the live database and creates offline checkpoint .Description Admin access is required. This will lock the database for the duration which can be hours for large repositories! .Parameter sdp-instance The specified instance to checkpoint .Example live_checkpoint.ps1 Master .Example live_checkpoint.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_p4login_ps1">7.3.6. p4login.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/p4login.ps1">This script</a> logs the standard superuser account in to the server with their stored password, using the details from <a href="#_sdp_config_ini">Section 3.1.5, “sdp_config.ini”</a>.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis p4login.ps1 performs a login with the SDP superuser as defined in sdp_config.ini .Description Available for admins to run manually. .Parameter sdp-instance The specified instance to login to. .Example p4login.ps1 Master .Example p4login.ps1 1 #></code></pre> </div> </div> <div class="paragraph"> <p>Examples of using the <code>p4login.bat</code> wrapper and specifying <code>SDP Instance</code> parameter:</p> </div> <div class="literalblock"> <div class="content"> <pre>p4login.bat 1 p4login.bat master</pre> </div> </div> </div> <div class="sect3"> <h4 id="_recover_edge_ps1">7.3.7. recover-edge.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/recover-edge.ps1">This script</a> recreates an edge server from create-filtered-edge-checkpoint, maintaining local data such as workspaces (in edge specific db.have table) plus the other 6+ edge tables.</p> </div> <div class="paragraph"> <p>Partner script to <a href="#_create_filtered_edge_checkpoint_ps1">Section 7.3.1, “create-filtered-edge-checkpoint.ps1”</a></p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Recovers an edge server from specified Master checkpoint (which may be filtered) Particularly intended for use with filtered edge servers, but handles an unfiltered edge server too. .Description Recover the edge server from the latest commit server checkpoint, while keeping any local edge server specific state such as db.have/db.working etc. The normal expectation is that you will use a checkpoint created by the script create-filtered-edge-checkpoint.ps1 If you want the edge server to be filtered, then you MUST use that script. If you just use the latest Master/Commit server checkpoint as input, then the edge will be assumed to be unfiltered - this script will still work. NOTE: This script will stop and restart the edge server while it is running - so it will be unavailable for periods while this script is running. This script also resets the offline_db directory for the edge server. .Parameter SDPInstance The specified instance to process .Parameter CkpFile The specified (master/commit server) checkpoint file to recover from (assumed to be gzipped). .Example recover-edge.ps1 Edge1 p4_1.ckp.filtered-edge.1234.gz Will recover for SDP instance Edge1. #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_recreate_live_from_offline_db_ps1">7.3.8. recreate-live-from-offline-db.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/recreate-live-from-offline-db.ps1">This script</a> can be scheduled to run every few months - it used to be run weekly, but that is no longer best practice since database files are not fragmented as they used to be. It will move the db.* files from offline to live root (so requires stopping the service).</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis Recreate-live-from-offline-db.ps1 updates the offline database and then swaps it over to replace the live database. .Description Admin access is required. .Parameter sdp-instance The specified instance to process .Example Recreate-live-from-offline-db.ps1 Master .Example Recreate-live-from-offline-db.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_replica_status_ps1">7.3.9. replica-status.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/replica-status.ps1">This script</a> sends an email with the results of the latest <code>p4 pull -lj</code>. Useful for basic monitoring services.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis replica-status.ps1 emails the latest state of the replica status using "p4 pull -lj" .Description Normally set up to run once per day. .Parameter sdp-instance The specified instance to backup .Example replica-status.ps1 Master .Example replica-status.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_rotate_log_files_ps1">7.3.10. rotate-log-files.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/rotate-log-files.ps1">This script</a> is intended to be run nightly on a replica which may not have any other scheduled tasks running. It ensures that the log files are appropriately rotated and old logs (and journals) are deleted according the settings of KEEP_CKPS in sdp_config.ini</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis rotate-log-files.ps1 rotates key log files for service. .Description Rotates all log files found and zips them. Useful for replicas which may not otherwise have scheduled tasks set. For use in Windows Task Scheduler. .Parameter sdp-instance The specified SDP instance to verify .Example rotate-log-files.ps1 Master .Example rotate-log-files.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_sdp_functions_ps1">7.3.11. SDP-functions.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/SDP-functions.ps1">This script</a> is the main repository of all shared functions used by other scripts.</p> </div> <div class="paragraph"> <p>They each source the file and then call individual functions as required. This is not intended by be called directly by the user - just sourced by other scripts.</p> </div> <div class="paragraph"> <p>E.g.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell"># Source the SDP Functions shared between scripts $SDPFunctionsPath = Split-Path -parent $MyInvocation.MyCommand.Path | Join-Path -childpath "SDP-Functions.ps1" . $SDPFunctionsPath</code></pre> </div> </div> <div class="paragraph"> <p>It understands how to parse config files, start/stop instances, rotate log files etc.</p> </div> </div> <div class="sect3"> <h4 id="_send_test_email_ps1">7.3.12. send-test-email.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/send-test-email.ps1">This script</a> is useful for debugging the setup of the sending of emails by the various scripts.</p> </div> <div class="paragraph"> <p>It sends a test email using the values found in <code>c:\p4\config\sdp_config.ini</code></p> </div> <div class="paragraph"> <p>If successful then it shows other script emails will work correctly.</p> </div> <div class="paragraph"> <p>See <a href="#_emails_not_being_sent">Section A.2, “Emails not being sent”</a> in Appendix A if having problems.</p> </div> </div> <div class="sect3"> <h4 id="_svcinst_exe">7.3.13. svcinst.exe</h4> <div class="paragraph"> <p>This is used for the Windows service to:</p> </div> <div class="ulist"> <ul> <li> <p>start</p> </li> <li> <p>stop</p> </li> <li> <p>create</p> </li> <li> <p>remove</p> </li> </ul> </div> <div class="admonitionblock important"> <table> <tr> <td class="icon"> <i class="fa icon-important" title="Important"></i> </td> <td class="content"> It is vital that you should use this utility rather than <code>net stop p4_1</code> or other <code>net</code> commands. This utility ensures that the service is shut down cleanly, and it will not timeout. </td> </tr> </table> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre>C:\p4\common\bin> svcinst.exe Perforce Service Manager Utility: SVCINST action [-d] [-n name] [-e exe] [-a] -d enables debug messages, (use as first flag) actions - info, create, start, stop, remove info -n name Specify the name of the service. create -n name Specify the name of the service. -e exe Specify the executable for the service, required. -a The service is to be autostart on boot, optional. start -n name Specify the name of the service. stop -n name Specify the name of the service. remove -n name Specify the name of the service.</pre> </div> </div> <div class="paragraph"> <p>So example usage would be:</p> </div> <div class="literalblock"> <div class="content"> <pre>svcinst stop -n p4_1</pre> </div> </div> </div> <div class="sect3"> <h4 id="_sync_replica_ps1">7.3.14. sync-replica.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/sync-replica.ps1">This script</a> copies checkpoint files from master to the current replica.</p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis sync-replica.ps1 copies checkpoint files from master to replica to ensure that they are local in case of replica reseeding being required. .Description Admin access is required. This script rebuilds the offline_db from the copied most recent checkpoint. .Parameter sdp-instance The specified instance to process .Example sync-replica.ps1 Master .Example sync-replica.ps1 1 #></code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_upgrade_ps1">7.3.15. upgrade.ps1</h4> <div class="paragraph"> <p><a href="../Server/Windows/p4/common/bin/upgrade.ps1">This script</a> upgrades the <code>p4d.exe</code> and related files (including Windows service <code>p4s.exe</code>), performing the appropriate <code>-xu</code> to upgraded the database.</p> </div> <div class="paragraph"> <p>Before running this script you should ensure the new versions of p4.exe and p4d.exe have been downloaded into <code>c:\p4\common\bin</code></p> </div> <div class="listingblock"> <div class="title">Usage</div> <div class="content"> <pre class="highlight"><code><# .Synopsis upgrade.ps1 performs upgrades the specified Perforce SDP instance to a new version of p4d .Description Rotates the journal, stops the live service, updates the executable, updates the offline and root databases, and restarts the service. REQUIRED: prior to running, download new p4d.exe to c:\p4\common\bin This script is aware of p4d versions up to 20.1 (so recognised 19.1+ new db.storage) .Parameter sdp-instance The specified SDP instance to upgrade .Example upgrade.ps1 Master .Example upgrade.ps1 1 #></code></pre> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_frequently_asked_questions">Appendix A: Frequently Asked Questions</h2> <div class="sectionbody"> <div class="paragraph"> <p>This appendix lists common questions and problems encountered by SDP users. Do not hesitate to contact <a href="mailto:consulting@perforce.com">consulting@perforce.com</a> if additional assistance is required.</p> </div> <div class="sect2"> <h3 id="_journal_out_of_sequence">A.1. Journal out of sequence</h3> <div class="paragraph"> <p>This error is encountered when the offline and live databases are no longer in sync, and will cause the offline checkpoint process to fail. This error can be fixed by running the create-offline-db-from-checkpoint (or if that doesn’t work then live-checkpoint script - which blocks live server), as described in Server upgrades.</p> </div> </div> <div class="sect2"> <h3 id="_emails_not_being_sent">A.2. Emails not being sent</h3> <div class="paragraph"> <p>The Powershell function <code>send-email</code> in <a href="#_sdp_functions_ps1">Section 7.3.11, “SDP-functions.ps1”</a> sends SDP emails.</p> </div> <div class="sect3"> <h4 id="_gmail_less_secure_app_access">A.2.1. Gmail Less Secure App Access</h4> <div class="paragraph"> <p>To send from Gmail, you may need to set the "Less Secure App Access" setting, which is configured in the gmail account. While logged into the gmail account from which you want the SDP scripts to send email, go to this URL: <a href="https://myaccount.google.com/lesssecureapps" class="bare">https://myaccount.google.com/lesssecureapps</a></p> </div> <div class="paragraph"> <p>That page should contain a slider button titled <code>Allow less secure apps:</code>. If the value is <code>OFF</code>, slide the slider button to the right so that it indicates <code>ON</code>.</p> </div> </div> <div class="sect3"> <h4 id="_implicit_and_explicit_settings">A.2.2. Implicit and Explicit Settings</h4> <div class="paragraph"> <p>Problems have been observed with some SMTP providers. For example on port 465 which is implicit SSL. There are 2 possibilities:</p> </div> <div class="ulist"> <ul> <li> <p><strong>explicit SSL</strong> - this means that the client first connects to the server using an unsecure channel, requests that conversations be moved to a secure channel, and then both server and client switch to a secure connection and the rest of the communication is encrypted. Though this sounds somewhat lengthy, it’s the standard procedure for setting up an SSL connection (see RFC 2228). Gmail handles explicit SSL without any difficulties, as do many other mail servers; Gmail’s explicit SSL server runs on port 587.</p> </li> <li> <p><strong>implicit SSL</strong> - In contrast, implicit SSL drops the SSL negotiation and jumps right into the SSL connection to begin with. Often, this is done through a connection to a specific port that only accepts secure connections. There is no official standard for this mode of communication, though it’s widely implemented; Gmail also handles implicit SSL, this time on port 465.</p> </li> </ul> </div> </div> <div class="sect3"> <h4 id="_explicit_ssl">A.2.3. Explicit SSL</h4> <div class="paragraph"> <p>If the server is <strong>explicit SSL</strong> then the script will just work, e.g. the relevant entries in <a href="#_sdp_config_ini">Section 3.1.5, “sdp_config.ini”</a>:</p> </div> <div class="literalblock"> <div class="content"> <pre>mailhost=smtp.gmail.com mailhostport=587</pre> </div> </div> </div> <div class="sect3"> <h4 id="_implicit_ssl">A.2.4. Implicit SSL</h4> <div class="paragraph"> <p>The easiest solution for <strong>implicit SSL</strong> is to run a local copy of <a href="https://www.stunnel.org/">stunnel</a> which configures a local port and knows how to talk to the remote server (for example Rackspace, or Gmail).</p> </div> <div class="paragraph"> <p>The relevant section in <a href="https://www.stunnel.org/config_windows.html">the example Windows config file</a>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[gmail-smtp] client = yes accept = 127.0.0.1:25 connect = smtp.gmail.com:465 verifyChain = yes CAfile = ca-certs.pem checkHost = smtp.gmail.com OCSPaia = yes</code></pre> </div> </div> <div class="paragraph"> <p>Using the above we can set the relevant entries in <a href="#_sdp_config_ini">Section 3.1.5, “sdp_config.ini”</a>:</p> </div> <div class="literalblock"> <div class="content"> <pre>mailhost=localhost mailhostport=25</pre> </div> </div> <div class="paragraph"> <p>Since <code>stunnel</code> will forward local port 25 to remote port 465.</p> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_sdp_package_contents_and_planning">Appendix B: SDP Package Contents and Planning</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_memory_and_cpu">B.1. Memory and CPU</h3> <div class="paragraph"> <p>Maximum performance is obtained if the server has enough memory to keep all of the database files in memory. Make sure the server has enough memory to cache the <strong>db.rev</strong> database file and to prevent the server from paging during user queries.</p> </div> <div class="paragraph"> <p>Below are some approximate guidelines for allocating memory.</p> </div> <div class="ulist"> <ul> <li> <p>1.5 kilobyte of RAM per file stored in the server.</p> </li> <li> <p>32 MB of RAM per user.</p> </li> </ul> </div> <div class="paragraph"> <p>Use the fastest processors available with the fastest available bus speed. Faster processors with a lower number of cores provide better performance for Perforce. Quick bursts of computational speed are more important to Perforce’s performance than the number of processors, but have a minimum of two processors so that the offline checkpoint and back up processes do not interfere with your Perforce server.</p> </div> <div class="sect3"> <h4 id="_monitoring_sdp_activities">B.1.1. Monitoring SDP activities</h4> <div class="paragraph"> <p>The important SDP maintenance and backup scripts generate email notifications when they complete.</p> </div> <div class="paragraph"> <p>For further monitoring, you can consider options such as:</p> </div> <div class="ulist"> <ul> <li> <p>Making the SDP log files available via a password protected HTTP server.</p> </li> <li> <p>Directing the SDP notification emails to an automated system that interprets the logs.</p> </li> </ul> </div> </div> </div> </div> </div> </div> <div id="footer"> <div id="footer-text"> Version v2021.1<br> Last updated 2021-11-09 12:35:32 -0500 </div> </div> </body> </html>
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#21 | 30915 | C. Thomas Tyler |
Released SDP 2024.1.30913 (2024/11/20). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#20 | 30388 | C. Thomas Tyler |
Released SDP 2024.1.30385 (2024/06/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#19 | 30297 | C. Thomas Tyler |
Released SDP 2023.2.30295 (2024/05/08). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#18 | 30043 | C. Thomas Tyler |
Released SDP 2023.2.30041 (2023/12/22). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#17 | 29954 | C. Thomas Tyler |
Released SDP 2023.1.29949 (2023/12/01). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#16 | 29701 | C. Thomas Tyler |
Released SDP 2023.1.29699 (2023/07/11). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#15 | 29612 | C. Thomas Tyler |
Released SDP 2023.1.29610 (2023/05/25). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#14 | 29252 | C. Thomas Tyler |
Released SDP 2022.2.29250 (2022/12/08). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#13 | 29143 | C. Thomas Tyler |
Released SDP 2022.1.29141 (2022/10/29). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#12 | 28989 | C. Thomas Tyler |
Released SDP 2022.1.28987 (2022/08/25). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#11 | 28858 | C. Thomas Tyler |
Released SDP 2022.1.28855 (2022/05/27). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#10 | 28651 | C. Thomas Tyler |
Released SDP 2021.2.28649 (2022/03/03). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#9 | 28412 | C. Thomas Tyler |
Released SDP 2021.2.28410 (2021/11/24). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#8 | 28240 | C. Thomas Tyler |
Released SDP 2021.1.28238 (2021/11/12). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#7 | 27921 | C. Thomas Tyler |
Released SDP 2020.1.27919 (2021/07/19). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#6 | 27901 | C. Thomas Tyler |
Released SDP 2020.1.27899 (2021/07/13). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#5 | 27822 | C. Thomas Tyler |
Released SDP 2020.1.27820 (2021/06/19). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#4 | 27761 | C. Thomas Tyler |
Released SDP 2020.1.27759 (2021/05/07). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#3 | 27527 | C. Thomas Tyler |
Released SDP 2020.1.27524 (2021/02/26). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#2 | 27354 | C. Thomas Tyler |
Released SDP 2020.1.27351 (2021/01/31). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
#1 | 27331 | C. Thomas Tyler |
Released SDP 2020.1.27325 (2021/01/29). Copy Up using 'p4 copy -r -b perforce_software-sdp-dev'. |
||
//guest/perforce_software/sdp/dev/doc/SDP_Guide.Windows.html | |||||
#8 | 27213 | C. Thomas Tyler | Regenerated docs. | ||
#7 | 27156 | C. Thomas Tyler |
Consolidated SDP Standards into the SDP Guide for UNIX/Linux. Added references to those sections in the Windows SDP Guide. Normalized doc titles. Various other doc update. |
||
#6 | 27041 | Robert Cowham |
Windows Guide directly includes chunks of the Unix guide for replication etc, with a little ifdef to avoid Unix only comments. Fix Makefile and add missing generated man page. |
||
#5 | 26747 | Robert Cowham |
Update with some checklists for failover to ensure valid. Update to v2020.1 Add Usage sections where missing to Unix guide Refactor the content in Unix guide to avoid repetition and make things read more sensibly. |
||
#4 | 26727 | Robert Cowham |
Add section on server host naming conventions Clarify HA and DR, and update links across docs Fix doc structure for Appendix numbering |
||
#3 | 26665 | Robert Cowham |
Make sure we use svcinst.exe not instsrv.exe Add notes for SDP-functions.ps1 Add section on email troubleshooting and mention use of stunnel if required (where implicit SSL is used by server). |
||
#2 | 26659 | Robert Cowham |
Removing out-of-date files and ancient utilities. Updating SDP Guide for Windows with includes to various .ps1 scripts Add new sync-replica.ps1 and call it from sync_replica.bat |
||
#1 | 26631 | Robert Cowham | New AsciiDoc version of Windows SDP guide |