lxd/migrate_container.go
func (s *migrationSourceWs) preDumpLoop(args *preDumpLoopArgs) (bool, error) {
	// Do a CRIU pre-dump
	criuMigrationArgs := CriuMigrationArgs{
		cmd:          lxc.MIGRATE_PRE_DUMP,
		stop:         false,
		actionScript: false,
		preDumpDir:   args.preDumpDir,
		dumpDir:      args.dumpDir,
		stateDir:     args.checkpointDir,
		function:     "migration",
	}

	logger.Debugf("Doing another pre-dump in %s", args.preDumpDir)

	final := args.final

	err := s.container.Migrate(&criuMigrationArgs)
	if err != nil {
		return final, err
	}

	// Send the pre-dump.
	ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
	state := s.container.DaemonState()
	err = RsyncSend(ctName, shared.AddSlash(args.checkpointDir), s.criuConn, nil, args.rsyncFeatures, args.bwlimit, state.OS.ExecPath)
	if err != nil {
		return final, err
	}

	// Read the CRIU's 'stats-dump' file
	dumpPath := shared.AddSlash(args.checkpointDir)
	dumpPath += shared.AddSlash(args.dumpDir)
	written, skipped_parent, err := readCriuStatsDump(dumpPath)
	if err != nil {
		return final, err
	}

	logger.Debugf("CRIU pages written %d", written)
	logger.Debugf("CRIU pages skipped %d", skipped_parent)

	total_pages := written + skipped_parent

	percentage_skipped := int(100 - ((100 * written) / total_pages))

	logger.Debugf("CRIU pages skipped percentage %d%%", percentage_skipped)

	// threshold is the percentage of memory pages that needs
	// to be pre-copied for the pre-copy migration to stop.
	var threshold int
	tmp := s.container.ExpandedConfig()["migration.incremental.memory.goal"]
	if tmp != "" {
		threshold, _ = strconv.Atoi(tmp)
	} else {
		// defaults to 70%
		threshold = 70
	}

	if percentage_skipped > threshold {
		logger.Debugf("Memory pages skipped (%d%%) due to pre-copy is larger than threshold (%d%%)", percentage_skipped, threshold)
		logger.Debugf("This was the last pre-dump; next dump is the final dump")
		final = true
	}

	// If in pre-dump mode, the receiving side
	// expects a message to know if this was the
	// last pre-dump
	logger.Debugf("Sending another header")
	sync := migration.MigrationSync{
		FinalPreDump: proto.Bool(final),
	}

	data, err := proto.Marshal(&sync)

	if err != nil {
		return final, err
	}

	err = s.criuConn.WriteMessage(websocket.BinaryMessage, data)
	if err != nil {
		s.sendControl(err)
		return final, err
	}
	logger.Debugf("Sending another header done")

	return final, nil
}
func (s *migrationSourceWs) preDumpLoop(args *preDumpLoopArgs) (bool, error) {
	// Do a CRIU pre-dump
	criuMigrationArgs := CriuMigrationArgs{
		cmd:          lxc.MIGRATE_PRE_DUMP,
		stop:         false,
		actionScript: false,
		preDumpDir:   args.preDumpDir,
		dumpDir:      args.dumpDir,
		stateDir:     args.checkpointDir,
		function:     "migration",
	}

	logger.Debugf("Doing another pre-dump in %s", args.preDumpDir)

	final := args.final

	err := s.container.Migrate(&criuMigrationArgs)
	if err != nil {
		return final, err
	}

	// Send the pre-dump.
	ctName, _, _ := containerGetParentAndSnapshotName(s.container.Name())
	state := s.container.DaemonState()
	err = RsyncSend(ctName, shared.AddSlash(args.checkpointDir), s.criuConn, nil, args.rsyncFeatures, args.bwlimit, state.OS.ExecPath)
	if err != nil {
		return final, err
	}

	// Read the CRIU's 'stats-dump' file
	dumpPath := shared.AddSlash(args.checkpointDir)
	dumpPath += shared.AddSlash(args.dumpDir)
	written, skipped_parent, err := readCriuStatsDump(dumpPath)
	if err != nil {
		return final, err
	}

	logger.Debugf("CRIU pages written %d", written)
	logger.Debugf("CRIU pages skipped %d", skipped_parent)

	total_pages := written + skipped_parent

	percentage_skipped := int(100 - ((100 * written) / total_pages))

	logger.Debugf("CRIU pages skipped percentage %d%%", percentage_skipped)

	// threshold is the percentage of memory pages that needs
	// to be pre-copied for the pre-copy migration to stop.
	var threshold int
	tmp := s.container.ExpandedConfig()["migration.incremental.memory.goal"]
	if tmp != "" {
		threshold, _ = strconv.Atoi(tmp)
	} else {
		// defaults to 70%
		threshold = 70
	}

	if percentage_skipped > threshold {
		logger.Debugf("Memory pages skipped (%d%%) due to pre-copy is larger than threshold (%d%%)", percentage_skipped, threshold)
		logger.Debugf("This was the last pre-dump; next dump is the final dump")
		final = true
	}

	// If in pre-dump mode, the receiving side
	// expects a message to know if this was the
	// last pre-dump
	logger.Debugf("Sending another header")
	sync := migration.MigrationSync{
		FinalPreDump: proto.Bool(final),
	}

	data, err := proto.Marshal(&sync)

	if err != nil {
		return final, err
	}

	err = s.criuConn.WriteMessage(websocket.BinaryMessage, data)
	if err != nil {
		s.sendControl(err)
		return final, err
	}
	logger.Debugf("Sending another header done")

	return final, nil
}
func ( s * migrationSourceWs ) preDumpLoop ( args * preDumpLoopArgs ) ( bool , error ) { // Do a CRIU pre-dump criuMigrationArgs := CriuMigrationArgs { cmd : lxc . MIGRATE_PRE_DUMP , stop : false , actionScript : false , preDumpDir : args . preDumpDir , dumpDir : args . dumpDir , stateDir : args . checkpointDir , function : " " , } logger . Debugf ( " " , args . preDumpDir ) final := args . final err := s . container . Migrate ( & criuMigrationArgs ) if err != nil { return final , err } // Send the pre-dump. ctName , _ , _ := containerGetParentAndSnapshotName ( s . container . Name ( ) ) state := s . container . DaemonState ( ) err = RsyncSend ( ctName , shared . AddSlash ( args . checkpointDir ) , s . criuConn , nil , args . rsyncFeatures , args . bwlimit , state . OS . ExecPath ) if err != nil { return final , err } // Read the CRIU's 'stats-dump' file dumpPath := shared . AddSlash ( args . checkpointDir ) dumpPath += shared . AddSlash ( args . dumpDir ) written , skipped_parent , err := readCriuStatsDump ( dumpPath ) if err != nil { return final , err } logger . Debugf ( " " , written ) logger . Debugf ( " " , skipped_parent ) total_pages := written + skipped_parent percentage_skipped := int ( 100 - ( ( 100 * written ) / total_pages ) ) logger . Debugf ( " " , percentage_skipped ) // threshold is the percentage of memory pages that needs // to be pre-copied for the pre-copy migration to stop. var threshold int tmp := s . container . ExpandedConfig ( ) [ " " ] if tmp != " " { threshold , _ = strconv . Atoi ( tmp ) } else { // defaults to 70% threshold = 70 } if percentage_skipped > threshold { logger . Debugf ( " " , percentage_skipped , threshold ) logger . Debugf ( " " ) final = true } // If in pre-dump mode, the receiving side // expects a message to know if this was the // last pre-dump logger . Debugf ( " " ) sync := migration . MigrationSync { FinalPreDump : proto . Bool ( final ) , } data , err := proto . Marshal ( & sync ) if err != nil { return final , err } err = s . criuConn . WriteMessage ( websocket . BinaryMessage , data ) if err != nil { s . sendControl ( err ) return final , err } logger . Debugf ( " " ) return final , nil }
// The function preDumpLoop is the main logic behind the pre-copy migration.
// This function contains the actual pre-dump, the corresponding rsync
// transfer and it tells the outer loop to abort if the threshold
// of memory pages transferred by pre-dumping has been reached.
The function preDumpLoop is the main logic behind the pre - copy migration . This function contains the actual pre - dump the corresponding rsync transfer and it tells the outer loop to abort if the threshold of memory pages transferred by pre - dumping has been reached .