config/jobstate: replace Job:load with create_state_file

it really is not necessary, since the only time we are interested in
loading the state from the file is when we list it, and there
we use JobState::load directly to avoid the lock

we still need to create the file on syncjob creation though, so
that we have the correct time for the schedule

to do this we add a new create_state_file that overwrites it on creation
of a syncjob

for safety, we subtract 30 seconds from the in-memory state in case
the statefile is missing

since we call create_state_file from  proxmox-backup-api,
we have to chown the lock file after creating to the backup user,
else the sync job scheduling cannot aquire the lock

also we remove the lock file on statefile removal

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2020-08-13 14:30:19 +02:00 committed by Dietmar Maurer
parent 713b66b6ed
commit 93bb51fe7e
4 changed files with 25 additions and 33 deletions

View File

@ -87,8 +87,7 @@ fn run_sync_job(
let userid: Userid = rpcenv.get_user().unwrap().parse()?; let userid: Userid = rpcenv.get_user().unwrap().parse()?;
let mut job = Job::new("syncjob", &id)?; let job = Job::new("syncjob", &id)?;
job.load()?;
let upid_str = do_sync_job(job, sync_job, &userid, None)?; let upid_str = do_sync_job(job, sync_job, &userid, None)?;

View File

@ -83,6 +83,8 @@ pub fn create_sync_job(param: Value) -> Result<(), Error> {
sync::save_config(&config)?; sync::save_config(&config)?;
crate::config::jobstate::create_state_file("syncjob", &sync_job.id)?;
Ok(()) Ok(())
} }

View File

@ -536,13 +536,7 @@ async fn schedule_datastore_sync_jobs() {
if next > now { continue; } if next > now { continue; }
let job = match Job::new(worker_type, &job_id) { let job = match Job::new(worker_type, &job_id) {
Ok(mut job) => match job.load() { Ok(job) => job,
Ok(_) => job,
Err(err) => {
eprintln!("error loading jobstate for {} - {}: {}", worker_type, &job_id, err);
continue;
}
}
Err(_) => continue, // could not get lock Err(_) => continue, // could not get lock
}; };

View File

@ -25,13 +25,7 @@
//! Err(err) => bail!("could not lock jobstate"), //! Err(err) => bail!("could not lock jobstate"),
//! }; //! };
//! //!
//! // job holds the lock //! // job holds the lock, we can start it
//! match job.load() {
//! Ok(()) => {},
//! Err(err) => bail!("could not load state {}", err),
//! }
//!
//! // now the job is loaded;
//! job.start("someupid")?; //! job.start("someupid")?;
//! // do something //! // do something
//! let task_state = some_code(); //! let task_state = some_code();
@ -102,16 +96,32 @@ where
{ {
let mut path = path.as_ref().to_path_buf(); let mut path = path.as_ref().to_path_buf();
path.set_extension("lck"); path.set_extension("lck");
open_file_locked(path, Duration::new(10, 0)) let lock = open_file_locked(&path, Duration::new(10, 0))?;
let backup_user = crate::backup::backup_user()?;
nix::unistd::chown(&path, Some(backup_user.uid), Some(backup_user.gid))?;
Ok(lock)
} }
/// Removes the statefile of a job, this is useful if we delete a job /// Removes the statefile of a job, this is useful if we delete a job
pub fn remove_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> { pub fn remove_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> {
let path = get_path(jobtype, jobname); let mut path = get_path(jobtype, jobname);
let _lock = get_lock(&path)?; let _lock = get_lock(&path)?;
std::fs::remove_file(&path).map_err(|err| std::fs::remove_file(&path).map_err(|err|
format_err!("cannot remove statefile for {} - {}: {}", jobtype, jobname, err) format_err!("cannot remove statefile for {} - {}: {}", jobtype, jobname, err)
) )?;
path.set_extension("lck");
// ignore errors
let _ = std::fs::remove_file(&path).map_err(|err|
format_err!("cannot remove lockfile for {} - {}: {}", jobtype, jobname, err)
);
Ok(())
}
/// Creates the statefile with the state 'Created'
/// overwrites if it exists already
pub fn create_state_file(jobtype: &str, jobname: &str) -> Result<(), Error> {
let mut job = Job::new(jobtype, jobname)?;
job.write_state()
} }
/// Returns the last run time of a job by reading the statefile /// Returns the last run time of a job by reading the statefile
@ -158,7 +168,7 @@ impl JobState {
} }
} else { } else {
Ok(JobState::Created { Ok(JobState::Created {
time: epoch_now_u64()? as i64 time: epoch_now_u64()? as i64 - 30,
}) })
} }
} }
@ -185,19 +195,6 @@ impl Job {
}) })
} }
/// Loads the state from the statefile if it exists.
/// If not, it gets created. Updates 'Started' State to 'Finished'
/// if we detect the UPID already stopped
pub fn load(&mut self) -> Result<(), Error> {
self.state = JobState::load(&self.jobtype, &self.jobname)?;
if let Err(err) = self.write_state() {
bail!("could not write statefile: {}", err);
}
Ok(())
}
/// Start the job and update the statefile accordingly /// Start the job and update the statefile accordingly
/// Fails if the job was already started /// Fails if the job was already started
pub fn start(&mut self, upid: &str) -> Result<(), Error> { pub fn start(&mut self, upid: &str) -> Result<(), Error> {