@@ -299,10 +299,89 @@ func (p *Manager) StartTmpMerged() error {
299299 return p .start ("-c" , fmt .Sprintf ("config_file=%s" , tmpPostgresConfPath ))
300300}
301301
302+ func (p * Manager ) moveWal () (err error ) {
303+ var curPath string
304+ var desiredPath string
305+ var tmpPath string
306+ symlinkPath := filepath .Join (p .dataDir , "pg_wal" )
307+ if curPath , err = filepath .EvalSymlinks (symlinkPath ); err != nil {
308+ log .Errorf ("could not evaluate symlink %s: %e" , symlinkPath , err )
309+ return err
310+ }
311+ if p .walDir == "" {
312+ desiredPath = symlinkPath
313+ tmpPath = filepath .Join (p .dataDir , "pg_wal_new" )
314+ } else {
315+ desiredPath = p .walDir
316+ tmpPath = p .walDir
317+ }
318+ if curPath == desiredPath {
319+ return nil
320+ }
321+ if p .walDir == "" {
322+ log .Infof ("moving wal from %s to %s first and then to %s" , curPath , tmpPath , desiredPath )
323+ } else {
324+ log .Infof ("moving wal from PGDATA/pg_wal (%s) to new location %s" , curPath , desiredPath )
325+ }
326+ // We use tmpPath here first and (if needed) mv tmpPath to desiredPath when all is copied.
327+ // This allows stolon-keeper to re-read symlink dest and continue should stolon-keeper be restarted while copying.
328+ log .Debugf ("creating %s" , tmpPath )
329+ if err = os .MkdirAll (tmpPath , 0700 ); err != nil && ! os .IsExist (err ) {
330+ log .Errorf ("could not create new dest folder %s: %e" , tmpPath , err )
331+ return err
332+ }
333+ log .Debugf ("moving wal from %s to %s" , curPath , tmpPath )
334+ if entries , err := ioutil .ReadDir (curPath ); err != nil {
335+ log .Errorf ("could not read contents of folder %s: %e" , curPath , err )
336+ return err
337+ } else {
338+ for _ , entry := range entries {
339+ srcEntry := filepath .Join (curPath , entry .Name ())
340+ dstEntry := filepath .Join (tmpPath , entry .Name ())
341+ log .Infof ("moving %s to %s" , srcEntry , dstEntry )
342+ os .Rename (srcEntry , dstEntry )
343+ }
344+ }
345+
346+ if symlinkStat , err := os .Lstat (symlinkPath ); err != nil {
347+ log .Errorf ("could not get info on current pg_wal folder/symlink %s: %e" , symlinkPath , err )
348+ return err
349+ } else if symlinkStat .Mode () & os .ModeSymlink != 0 {
350+ if err = os .Remove (symlinkPath ); err != nil {
351+ log .Errorf ("could not remove current pg_wal symlink %s: %e" , symlinkPath , err )
352+ return err
353+ }
354+ } else if symlinkStat .IsDir () {
355+ if err := syscall .Rmdir (symlinkPath ); err != nil {
356+ log .Errorf ("could not remove current folder %s: %e" , symlinkPath , err )
357+ return err
358+ }
359+ } else {
360+ err := fmt .Errorf ("location %s is no symlink and no dir, so please check and resolve by hand" , symlinkPath )
361+ log .Error (err )
362+ return err
363+ }
364+ if p .walDir == "" {
365+ // So we were moving wal files back into PGDATA. Let's rename the tmpDir now holding all wal files and use that
366+ // as PGDATA/pg_wal
367+ os .Rename (tmpPath , desiredPath )
368+ // Ah, so we were copying WAL files from PGDATA (or another location) to a location outside of PGDATA.
369+ // Then we need to point the symlink in the right direction.
370+ } else if err = os .Symlink (desiredPath , symlinkPath ); err != nil {
371+ log .Errorf ("could not create symlink %s to %s: %e" , symlinkPath , desiredPath , err )
372+ return err
373+ }
374+ log .Debugf ("finished moving pg_wal from %s to %s" , curPath , desiredPath )
375+ return nil
376+ }
377+
302378func (p * Manager ) Start () error {
303379 if err := p .writeConfs (false ); err != nil {
304380 return err
305381 }
382+ if err := p .moveWal (); err != nil {
383+ return err
384+ }
306385 return p .start ()
307386}
308387
0 commit comments