TEST_P(SnapshotRestoreTest, TestFailOver) { auto foc_ctx(start_one_foc()); auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns(), VolumeSize((1 << 18) * 512), SCOMultiplier(1)); v->setFailOverCacheConfig(foc_ctx->config(GetParam().foc_mode())); VolumeConfig cfg = v->get_config(); v->createSnapshot(SnapshotName("snap0")); for(int i = 0; i < 5; ++i) { writeToVolume(*v, 0, 4096, "a"); } waitForThisBackendWrite(*v); v->restoreSnapshot(SnapshotName("snap0")); for(int i = 0; i < 7; ++i) { writeToVolume(*v, 8, 4096, "d"); } flushFailOverCache(*v); destroyVolume(v, DeleteLocalData::T, RemoveVolumeCompletely::F); SharedVolumePtr v1 = 0; v1 = getVolume(VolumeId("volume1")); ASSERT_FALSE(v1); restartVolume(cfg); v1 = getVolume(VolumeId("volume1")); ASSERT_TRUE(v1 != nullptr); checkVolume(*v1,0,4096, "\0"); checkVolume(*v1,8,4096, "d"); checkCurrentBackendSize(*v1); }
TEST_P(BigReadWriteTest, bigReadsOnFull) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns()); SCOPED_BLOCK_BACKEND(*v); size_t csz = v->getClusterSize(); size_t lba_size = v->getLBASize(); const std::string pattern(csz,'a'); size_t scoMul = v->getSCOMultiplier(); for(size_t i = 0;i < 50*scoMul; ++i) { writeToVolume(*v, i* csz / lba_size, csz, pattern); } // Stop here to manually delete sco's to check error handling for(size_t i = 0; i < scoMul; ++i) { checkVolume(*v,0, csz*scoMul, pattern); } }
TEST_P(SnapshotRestoreTest, snapshot_restoration_on_a_clone) { const auto wrns_parent(make_random_namespace()); const std::string parent_name(wrns_parent->ns().str()); SharedVolumePtr parent = newVolume(VolumeId(parent_name), be::Namespace(parent_name)); const std::string pattern1("before-parent-snapshot"); writeToVolume(*parent, 0, parent->getClusterSize(), pattern1); const SnapshotName parent_snap("parent-snapshot"); parent->createSnapshot(parent_snap); waitForThisBackendWrite(*parent); const auto wrns_clone(make_random_namespace()); const std::string clone_name(wrns_clone->ns().str()); SharedVolumePtr clone = createClone(clone_name, be::Namespace(clone_name), be::Namespace(parent_name), parent_snap); const std::string pattern2("before-clone-snapshot"); writeToVolume(*clone, 0, clone->getClusterSize(), pattern2); const SnapshotName clone_snap("clone-snapshot"); clone->createSnapshot(clone_snap); waitForThisBackendWrite(*clone); const std::string pattern3("after-clone-snapshot"); writeToVolume(*clone, 0, clone->getClusterSize(), pattern3); checkVolume(*clone, 0, clone->getClusterSize(), pattern3); restoreSnapshot(*clone, clone_snap); checkVolume(*clone, 0, clone->getClusterSize(), pattern2); }
VanillaVolumeConfigParameters make_volume_params(const be::BackendTestSetup::WithRandomNamespace& wrns) { const VolumeSize vsize(CachePage::capacity() * 10 * default_cluster_size()); return VanillaVolumeConfigParameters(VolumeId(wrns.ns().str()), wrns.ns(), vsize, new_owner_tag()) .metadata_backend_config(metadata_backend_config()) .metadata_cache_capacity(1); }
TEST_P(BigReadWriteTest, bigReadsOnEmpty) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns()); size_t csz = v->getClusterSize(); const std::string pattern(csz,'\0'); size_t scoMul = v->getSCOMultiplier(); for(size_t i = 0; i < scoMul; ++i) { checkVolume(*v,0, csz*scoMul, pattern); } }
TEST_P(BigReadWriteTest, OneBigWriteOneBigRead) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns()); SCOPED_BLOCK_BACKEND(*v); size_t csz = v->getClusterSize(); const std::string pattern(csz,'a'); size_t scoMul = v->getSCOMultiplier(); writeToVolume(*v, 0, csz * scoMul, pattern); // Stop here to manually delete sco's to check error handling checkVolume(*v,0, csz*scoMul, pattern); }
TEST_P(SnapshotRestoreTest, RestoreAndWriteAgain1) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns(), VolumeSize(1 << 26), SCOMultiplier(1)); const std::string pattern("e-manual"); v->createSnapshot(SnapshotName("snap1")); waitForThisBackendWrite(*v); writeToVolume(*v, 0, 5 * 4096, pattern); waitForThisBackendWrite(*v); restoreSnapshot(*v,"snap1"); writeToVolume(*v, 0, 4*4096, pattern); waitForThisBackendWrite(*v); checkCurrentBackendSize(*v); }
TEST_P(SnapshotRestoreTest, HaltOnError) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns()); const std::string pattern1("blah"); const TLogId tlog_id(v->getSnapshotManagement().getCurrentTLogId()); writeToVolume(*v, 0, 4096, pattern1); v->createSnapshot(SnapshotName("snap1")); waitForThisBackendWrite(*v); EXPECT_THROW(restoreSnapshot(*v, "snap42"), std::exception); EXPECT_FALSE(v->is_halted()); v->getBackendInterface()->remove(boost::lexical_cast<std::string>(tlog_id)); EXPECT_THROW(restoreSnapshot(*v, "snap1"), std::exception); EXPECT_TRUE(v->is_halted()); }
bool Backup::create_backup_volume() { LOG_INFO(__FUNCTION__); // Need and AssertLocked here VERIFY(not target_volume_); VERIFY(source_volume_config.get()); api::getManagementMutex().assertLocked(); // We check whether the source is a Normal volume boost::optional<VolumeConfig::WanBackupVolumeRole> role; VERIFY(not role); switch(source_volume_config->wan_backup_volume_role_) { case VolumeConfig::WanBackupVolumeRole::WanBackupNormal: if(start_snapshot_) { LOG_INFO("Incremental backup of a normal volume"); role = VolumeConfig::WanBackupVolumeRole::WanBackupIncremental; } else { LOG_INFO("Complete backup of a normal volume"); role = VolumeConfig::WanBackupVolumeRole::WanBackupBase; } break; case VolumeConfig::WanBackupVolumeRole::WanBackupBase: if(start_snapshot_) { LOG_INFO("Incremental backup of a backup volume"); role = VolumeConfig::WanBackupVolumeRole::WanBackupIncremental; } else { LOG_INFO("Complete backup of a normal volume"); role = VolumeConfig::WanBackupVolumeRole::WanBackupBase; } break; case VolumeConfig::WanBackupVolumeRole::WanBackupIncremental: if(start_snapshot_) { LOG_INFO("Incremental backup of a incremental volume"); role = VolumeConfig::WanBackupVolumeRole::WanBackupIncremental; } else { std::vector<SnapshotNum> snaps; source_snapshot_persistor->getAllSnapshots(snaps); VERIFY(snaps.size() >= 2); start_snapshot_ = source_snapshot_persistor->getSnapshotName(snaps[0]); LOG_INFO("Complete backup of a incremental volume, created start snapshot " << *start_snapshot_); role = VolumeConfig::WanBackupVolumeRole::WanBackupIncremental; } break; } VERIFY(role); LOG_INFO("Creating new volume in the target with role " << *role); try { boost::this_thread::interruption_point(); TODO("AR: consider OwnerTag") const auto params = WriteOnlyVolumeConfigParameters(VolumeId(source_volume_config->getNS().str()), Namespace(target_namespace), VolumeSize(source_volume_config->lba_count() * source_volume_config->lba_size_), *role, OwnerTag(1)) .lba_size(source_volume_config->lba_size_) .cluster_multiplier(source_volume_config->cluster_mult_) .sco_multiplier(source_volume_config->sco_mult_); target_volume_.reset(api::createNewWriteOnlyVolume(params)); } CATCH_STD_ALL_LOG_RETHROW("problem creating WriteOnlyVolume"); LOG_INFO("Created new volume in the target -- name is the namespace of the source" << source_volume_config->getNS()); if(start_snapshot_) { LOG_INFO("Just created a volume and start snapshot was given... we create a snapshot in the beginning of the volume"); const SnapshotNum start_snapshot_num = source_snapshot_persistor->getSnapshotNum(*start_snapshot_); const SnapshotName& start_snapshot_name = *start_snapshot_; const UUID start_snapshot_uuid(source_snapshot_persistor->getUUID(start_snapshot_num)); boost::this_thread::interruption_point(); api::createSnapshot(target_volume_.get(), SnapshotMetaData(), &start_snapshot_name, start_snapshot_uuid); WAIT_FOR_THIS_VOLUME_WRITE(target_volume_.get()); VERIFY(api::isVolumeSyncedUpTo(target_volume_.get(), start_snapshot_name)); if(*start_snapshot_ == end_snapshot_name) { LOG_INFO("start_snapshot == end_snapshot " << end_snapshot_name << " so exiting now"); while(not api::isVolumeSyncedUpTo(target_volume_.get(), *start_snapshot_)) { LOG_INFO("Waiting for the volume to finish writing to the backend, sleeping another 10 seconds"); sleep(10); } status_.finish(); LOG_INFO("Finished the Backup"); return false; } } else { LOG_INFO("Is a full backup to the newly created volume"); } return true; }
TEST_P(SnapshotRestoreTest, SimpleRestore) { auto ns_ptr = make_random_namespace(); SharedVolumePtr v = newVolume(VolumeId("volume1"), ns_ptr->ns()); const std::string pattern1("Frederik"); writeToVolume(*v, 0, 4096, pattern1); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snap1")); const std::string pattern2("Frederik"); writeToVolume(*v, 0, 4096, pattern2); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snap2")); const std::string pattern3("Arne"); writeToVolume(*v, 0, 4096, pattern3); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snap3")); const std::string pattern4("Bart"); writeToVolume(*v, 0, 4096, pattern4); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snap4")); const std::string pattern5("Wouter"); writeToVolume(*v, 0, 4096, pattern5); checkVolume(*v,0,4096,pattern5); waitForThisBackendWrite(*v); EXPECT_NO_THROW(restoreSnapshot(*v, "snap4")); checkVolume(*v,0,4096,pattern4); writeToVolume(*v, 0, 4096, "Bollocks"); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snapper")); waitForThisBackendWrite(*v); EXPECT_NO_THROW(restoreSnapshot(*v, "snap3")); checkVolume(*v,0,4096,pattern3); writeToVolume(*v, 0, 4096, "Bollocks"); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snapper")); waitForThisBackendWrite(*v); EXPECT_NO_THROW(restoreSnapshot(*v, "snap2")); checkVolume(*v,0,4096,pattern2); writeToVolume(*v, 0, 4096, "Bollocks"); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snapper")); waitForThisBackendWrite(*v); EXPECT_NO_THROW(restoreSnapshot(*v, "snap1")); checkVolume(*v,0,4096,pattern1); writeToVolume(*v, 0, 4096, "Bollocks"); waitForThisBackendWrite(*v); v->createSnapshot(SnapshotName("snapper")); waitForThisBackendWrite(*v); checkCurrentBackendSize(*v); }