Status Tablet::DoReopenUnsafe()

in aios/storage/indexlib/framework/Tablet.cpp [885:1093]


Status Tablet::DoReopenUnsafe(const ReopenOptions& reopenOptions, const VersionCoord& versionCoord)
{
    // do not clean in-memory index while reopen
    // otherwise mounted version may be erased by mistake.
    std::lock_guard<std::mutex> lockCleaner(_cleanerMutex);
    BuildResource buildResource = GenerateBuildResource(COUNTER_PREFIX);
    indexlib::util::ScopeLatencyReporter reopenLatency(_tabletMetrics->GetreopenIncLatencyMetric().get());

    auto statusOrDpDesc = CreateVersionDeployDescription(versionCoord.GetVersionId());
    RETURN_IF_STATUS_ERROR(statusOrDpDesc, "create version deploy description failed for version [%d]",
                           versionCoord.GetVersionId());
    auto versionDpDesc = std::move(statusOrDpDesc.steal_value());
    auto [mountStatus, version] = MountOnDiskVersion(versionCoord, versionDpDesc);
    if (!mountStatus.IsOK()) {
        TABLET_LOG(ERROR, "mount version [%s] failed: %s", versionCoord.DebugString().c_str(),
                   mountStatus.ToString().c_str());
        return mountStatus;
    }
    std::shared_ptr<TabletData> currentTabletData;
    {
        std::lock_guard<std::mutex> lock(_dataMutex);
        currentTabletData = _tabletData;
    }
    TABLET_LOG(INFO, "do reopen, version [%d => %d]", currentTabletData->GetOnDiskVersion().GetVersionId(),
               version.GetVersionId());
    bool hasBuildingSegment;
    auto headVersionCoord = CalculateHead(currentTabletData, _fence, &hasBuildingSegment);
    bool isPrivateVersion = (versionCoord.GetVersionId() & Version::PRIVATE_VERSION_ID_MASK) > 0;
    if (_tabletOptions->IsOnline() && !isPrivateVersion &&
        !version.CanFastFowardFrom(headVersionCoord, hasBuildingSegment)) {
        TABLET_LOG(ERROR,
                   "do reopen failed, version can't fast from onDiskVersion, head version [%s], version line [%s]",
                   autil::legacy::ToJsonString(headVersionCoord, true).c_str(),
                   autil::legacy::ToJsonString(version.GetVersionLine()).c_str());
        return Status::Corruption("reopen fastford failed");
    }
    _idGenerator->UpdateBaseVersion(version);

    auto loadSchemaStatus = _tabletSchemaMgr->LoadAllSchema(version);
    if (!loadSchemaStatus.IsOK()) {
        TABLET_LOG(ERROR, "do reopen failed, load all schema failed");
        return loadSchemaStatus;
    }

    TABLET_LOG(INFO, "begin load segments, force[%d], segments [%s]", reopenOptions.IsForceReopen(),
               GetDiffSegmentDebugString(version, currentTabletData).c_str());
    auto readSchema = _tabletSchemaMgr->GetSchema(version.GetReadSchemaId());
    if (currentTabletData) {
        auto status =
            DropIndexCleaner::CleanIndexInLogical(currentTabletData, readSchema, GetRootDirectory()->GetIDirectory());
        if (!status.IsOK()) {
            TABLET_LOG(ERROR, "do reopen failed, clean drop index failed");
            return status;
        }
    }
    auto currentLifecycleTable = LifecycleTableCreator::CreateLifecycleTable(
        version, _tabletOptions->GetOnlineConfig().GetLifecycleConfig(),
        {{indexlib::file_system::LifecyclePatternBase::CURRENT_TIME,
          std::to_string(indexlib::file_system::LifecycleConfig::CurrentTimeInSeconds())}});

    if (currentLifecycleTable == nullptr) {
        TABLET_LOG(ERROR, "do reopen failed, create LifecycleTable failed for version[%d]", version.GetVersionId());
        return Status::Corruption("reopen failed due to null lifecycleTable");
    }

    std::vector<std::pair<std::shared_ptr<Segment>, bool>> segmentPairs;
    std::shared_ptr<indexlib::file_system::Directory> root = GetRootDirectory();
    for (auto [segmentId, schemaId] : version) {
        auto seg = currentTabletData->GetSegment(segmentId);
        auto segmentDirName = version.GetSegmentDirName(segmentId);
        auto currentLifecycle = currentLifecycleTable->GetLifecycle(segmentDirName + "/");
        bool needLoadDiskSegment = true;
        if (seg != nullptr && seg->GetSegmentStatus() == Segment::SegmentStatus::ST_BUILT) {
            seg->GetSegmentDirectory()->SetLifecycle(currentLifecycle);
            auto segmentSchemaId = seg->GetSegmentSchema()->GetSchemaId();
            auto preLifecycle = seg->GetSegmentLifecycle();
            if (segmentSchemaId != schemaId) {
                auto diskSegment = std::dynamic_pointer_cast<DiskSegment>(seg);
                assert(diskSegment != nullptr);
                std::vector<std::shared_ptr<config::ITabletSchema>> tabletSchemas;
                auto status = _tabletSchemaMgr->GetSchemaList(segmentSchemaId, schemaId, version, tabletSchemas);
                RETURN_IF_STATUS_ERROR(status, "get schema list failed, segmentSchemaId[%d], segmentId[%d]",
                                       segmentSchemaId, segmentId);
                if (preLifecycle != currentLifecycle) {
                    RETURN_IF_STATUS_ERROR(
                        status, "config conficts, segmentId[%d] schemaId updated [%d->%d], lifecycle updated[%s -> %s]",
                        segmentId, segmentSchemaId, schemaId, preLifecycle.c_str(), currentLifecycle.c_str());
                }
                status = diskSegment->Reopen(tabletSchemas);
                RETURN_IF_STATUS_ERROR(status, "disk segment open failed, segmentId[%d]", segmentId);
                needLoadDiskSegment = false;
            } else {
                if (preLifecycle != currentLifecycle) {
                    TABLET_LOG(INFO, "built segmentId[%d] lifecycle updated [%s] -> [%s]", segmentId,
                               preLifecycle.c_str(), currentLifecycle.c_str());
                } else {
                    needLoadDiskSegment = false;
                }
            }
        }
        if (!needLoadDiskSegment) {
            segmentPairs.emplace_back(std::make_pair(seg, /*needOpen=*/false));
        } else {
            auto segDir = root->GetDirectory(segmentDirName,
                                             /*throwExceptionIfNotExist=*/false);
            if (!segDir) {
                auto st = Status::IOError("get segment[%d] dir failed", segmentId);
                TABLET_LOG(ERROR, "do reopen failed, %s", st.ToString().c_str());
                return st;
            }
            segDir->SetLifecycle(currentLifecycle);
            SegmentMeta segmentMeta;
            segmentMeta.segmentId = segmentId;
            segmentMeta.lifecycle = currentLifecycle;
            auto schema = _tabletSchemaMgr->GetSchema(schemaId);
            segmentMeta.schema = schema;
            segmentMeta.segmentDir = segDir;
            auto readerOption = indexlib::file_system::ReaderOption::PutIntoCache(indexlib::file_system::FSOT_MEM);
            if (!segmentMeta.segmentInfo->Load(segDir->GetIDirectory(), readerOption).IsOK()) {
                auto st = Status::Corruption("load segment info[%s] failed", segDir->GetLogicalPath().c_str());
                TABLET_LOG(ERROR, "do reopen failed, %s", st.ToString().c_str());
                return st;
            }
            auto diskSegment =
                std::shared_ptr<Segment>(_tabletFactory->CreateDiskSegment(segmentMeta, buildResource).release());
            assert(diskSegment);
            segmentPairs.emplace_back(std::make_pair(diskSegment, /*needOpen=*/true));
        }
    }

    TABLET_LOG(INFO, "end load segments, segment count [%lu]", segmentPairs.size());

    TABLET_LOG(INFO, "begin load tablet data, fence name[%s]", _fence.GetFenceName().c_str());
    const indexlib::util::MemoryReserverPtr memReserver = _fence.GetFileSystem()->CreateMemoryReserver("load_segments");
    auto tabletLoader = _tabletFactory->CreateTabletLoader(_fence.GetFenceName());
    assert(tabletLoader);
    auto versionSchema = _tabletSchemaMgr->GetSchema(version.GetSchemaId());
    tabletLoader->Init(_tabletMemoryQuotaController, versionSchema, memReserver, _tabletOptions->IsOnline());

    {
        indexlib::util::ScopeLatencyReporter preloadLatency(_tabletMetrics->GetpreloadLatencyMetric().get());
        auto status = tabletLoader->PreLoad(*currentTabletData, std::move(segmentPairs), version);
        if (!status.IsOK()) {
            TABLET_LOG(ERROR, "do reopen failed, tablet preload version [%s] failed", version.DebugString().c_str());
            return status;
        }
    }

    indexlib::util::ScopeLatencyReporter finalLoadLatency(_tabletMetrics->GetfinalLoadLatencyMetric().get());
    std::lock_guard lock(_dataMutex);
    if (version.GetSchemaId() > GetTabletSchema()->GetSchemaId()) {
        auto status = DoAlterTable(versionSchema);
        if (!status.IsOK()) {
            TABLET_LOG(ERROR, "do reopen failed, do alter table on schema[%u] failed: %s", version.GetSchemaId(),
                       status.ToString().c_str());
            return status;
        }
    }
    auto [status, newTabletData] = tabletLoader->FinalLoad(*_tabletData);
    if (!status.IsOK()) {
        TABLET_LOG(ERROR, "do reopen failed, tablet final load failed");
        return status;
    }

    status = FinalizeTabletData(newTabletData.get(), GetTabletSchema());
    if (!status.IsOK()) {
        TABLET_LOG(ERROR, "do reopen failed, finalize tablet data failed: %s", status.ToString().c_str());
        return status;
    }
    assert(newTabletData->GetResourceMap());
    newTabletData->ReclaimSegmentResource();
    TABLET_LOG(INFO, "end load tablet data");

    _tabletDumper->TrimDumpingQueue(*newTabletData);
    if (version.GetVersionId() & Version::PRIVATE_VERSION_ID_MASK) {
        versionDpDesc = _tabletInfos->GetLoadedVersionDeployDescription();
    }
    status = OpenWriterAndReader(std::move(newTabletData), reopenOptions.GetOpenOptions(), versionDpDesc);
    if (status.IsOK()) {
        if (!(version.GetVersionId() & Version::PRIVATE_VERSION_ID_MASK)) {
            _tabletInfos->SetLoadedPublishVersion(version);
            _tabletInfos->SetLoadedVersionDeployDescription(versionDpDesc);
        } else {
            _tabletInfos->SetLoadedPrivateVersion(version);
        }
        if (_versionMerger) {
            _versionMerger->UpdateVersion(version);
        }
    } else {
        TABLET_LOG(ERROR, "do reopen failed, tablet open writer and reader failed");
    }
    if (!GetMemSegmentLocator().IsValid()) {
        if (_tabletInfos->GetLoadedPublishVersion().IsSealed()) {
            _sealedSourceLocator = _tabletInfos->GetLoadedPublishVersion().GetLocator();
            if (_sealedSourceLocator) {
                _tabletCommitter->SetSealed(true);
            }
        } else {
            if (_sealedSourceLocator) {
                _sealedSourceLocator.reset();
                _tabletCommitter->SetSealed(false);
            }
        }
    }
    _tabletCommitter->SetLastPublicVersion(version);
    RETURN_IF_STATUS_ERROR(status, "open writer and reader failed");

    return Status::OK();
}