diff --git a/pageserver/src/http/openapi_spec.yml b/pageserver/src/http/openapi_spec.yml index 823f927796..25d5ceae4e 100644 --- a/pageserver/src/http/openapi_spec.yml +++ b/pageserver/src/http/openapi_spec.yml @@ -220,7 +220,7 @@ paths: format: hex responses: "201": - description: CREATED + description: Already exists or created content: application/json: schema: diff --git a/pageserver/src/tenant_mgr.rs b/pageserver/src/tenant_mgr.rs index 7076962830..77ef865ec5 100644 --- a/pageserver/src/tenant_mgr.rs +++ b/pageserver/src/tenant_mgr.rs @@ -9,11 +9,11 @@ use crate::thread_mgr::ThreadKind; use crate::timelines; use crate::walredo::PostgresRedoManager; use crate::CheckpointConfig; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use lazy_static::lazy_static; use log::*; use serde::{Deserialize, Serialize}; -use std::collections::{hash_map, HashMap}; +use std::collections::HashMap; use std::fmt; use std::sync::{Arc, Mutex, MutexGuard}; use zenith_utils::zid::{ZTenantId, ZTimelineId}; @@ -183,16 +183,16 @@ pub fn create_repository_for_tenant( ) -> Result { let new_tenant_id = new_tenant_id.unwrap_or_else(ZTenantId::generate); let wal_redo_manager = Arc::new(PostgresRedoManager::new(conf, new_tenant_id)); - let repo = timelines::create_repo(conf, new_tenant_id, wal_redo_manager)?; - - match access_tenants().entry(new_tenant_id) { - hash_map::Entry::Occupied(_) => bail!("tenant {} already exists", new_tenant_id), - hash_map::Entry::Vacant(v) => { - v.insert(Tenant { - state: TenantState::Idle, - repo, - }); + match timelines::create_repo(conf, new_tenant_id, wal_redo_manager)? { + Some(repo) => { + access_tenants() + .entry(new_tenant_id) + .or_insert_with(|| Tenant { + state: TenantState::Idle, + repo, + }); } + None => debug!("repository already exists for tenant {}", new_tenant_id), } Ok(new_tenant_id) diff --git a/pageserver/src/timelines.rs b/pageserver/src/timelines.rs index 54f0a302f4..587b9a2cf2 100644 --- a/pageserver/src/timelines.rs +++ b/pageserver/src/timelines.rs @@ -2,7 +2,7 @@ //! Timeline management code // -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use postgres_ffi::ControlFileData; use serde::{Deserialize, Serialize}; use std::{ @@ -160,7 +160,7 @@ pub fn init_pageserver( conf: &'static PageServerConf, create_tenant: Option, initial_timeline_id: Option, -) -> Result<()> { +) -> anyhow::Result<()> { // Initialize logger // use true as daemonize parameter because otherwise we pollute zenith cli output with a few pages long output of info messages let _log_file = logging::init(LOG_FILE_NAME, true)?; @@ -177,9 +177,13 @@ pub fn init_pageserver( // anymore, but I think that could still happen. let dummy_redo_mgr = Arc::new(crate::walredo::DummyRedoManager {}); + crashsafe_dir::create_dir_all(conf.tenants_path())?; + if let Some(tenant_id) = create_tenant { println!("initializing tenantid {}", tenant_id); - let repo = create_repo(conf, tenant_id, dummy_redo_mgr).context("failed to create repo")?; + let repo = create_repo(conf, tenant_id, dummy_redo_mgr) + .context("failed to create repo")? + .ok_or_else(|| anyhow!("For newely created pageserver, found already existing repository for tenant {}", tenant_id))?; let new_timeline_id = initial_timeline_id.unwrap_or_else(ZTimelineId::generate); bootstrap_timeline(conf, tenant_id, new_timeline_id, repo.as_ref()) .context("failed to create initial timeline")?; @@ -187,7 +191,6 @@ pub fn init_pageserver( } else if initial_timeline_id.is_some() { println!("Ignoring initial timeline parameter, due to no tenant id to create given"); } - crashsafe_dir::create_dir_all(conf.tenants_path())?; println!("pageserver init succeeded"); Ok(()) @@ -197,26 +200,25 @@ pub fn create_repo( conf: &'static PageServerConf, tenant_id: ZTenantId, wal_redo_manager: Arc, -) -> Result> { +) -> Result>> { let repo_dir = conf.tenant_path(&tenant_id); if repo_dir.exists() { - bail!("repo for {} already exists", tenant_id) + debug!("repo for {} already exists", tenant_id); + return Ok(None); } // top-level dir may exist if we are creating it through CLI crashsafe_dir::create_dir_all(&repo_dir) .with_context(|| format!("could not create directory {}", repo_dir.display()))?; - crashsafe_dir::create_dir(conf.timelines_path(&tenant_id))?; - info!("created directory structure in {}", repo_dir.display()); - Ok(Arc::new(LayeredRepository::new( + Ok(Some(Arc::new(LayeredRepository::new( conf, wal_redo_manager, tenant_id, conf.remote_storage_config.is_some(), - ))) + )))) } // Returns checkpoint LSN from controlfile