Repository: ClickHouse/ClickHouse
File: src/Storages/IStorage.cpp (C++)

Code before:
{
    if (metadata_)
        metadata.set(std::move(metadata_));
    else
        metadata.set(std::make_unique<StorageInMemoryMetadata>());
}

bool IStorage::isVirtualColumn(const String & column_name, const StorageMetadataPtr & metadata_snapshot) const
{
    /// Virtual column maybe overridden by real column
    return !metadata_snapshot->getColumns().has(column_name) && (virtuals.get()->has(column_name) || common_virtuals.has(column_name));
}

VirtualColumnsDescription IStorage::createCommonVirtuals()
{
    VirtualColumnsDescription desc;

    desc.addEphemeral("_table", std::make_shared<DataTypeLowCardinality>(std::make_shared<DataTypeString>()), "The name of table which the row comes from");

    return desc;
}

RWLockImpl::LockHolder IStorage::tryLockTimed(
    const RWLock & rwlock, RWLockImpl::Type type, const String & query_id, const std::chrono::milliseconds & acquire_timeout) const
{
    auto lock_holder = rwlock->getLock(type, query_id, acquire_timeout);
    if (!lock_holder)
    {
        const String type_str = type == RWLockImpl::Type::Read ? "READ" : "WRITE";
        throw Exception(ErrorCodes::DEADLOCK_AVOIDED,
            "{} locking attempt on \"{}\" has timed out! ({}ms) Possible deadlock avoided. Client should retry. Owner query ids: {}",
            type_str, getStorageID(), acquire_timeout.count(), rwlock->getOwnerQueryIdsDescription());
    }
    return lock_holder;
}

TableLockHolder IStorage::lockForShare(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
{
    TableLockHolder result = tryLockTimed(drop_lock, RWLockImpl::Read, query_id, acquire_timeout);
    auto table_id = getStorageID();
    if (!table_id.hasUUID() && (is_dropped || is_detached))
        throw Exception(ErrorCodes::TABLE_IS_DROPPED, "Table {}.{} is dropped or detached", table_id.database_name, table_id.table_name);

    if (is_being_restarted)
        throw Exception(
            ErrorCodes::TABLE_IS_BEING_RESTARTED, "Table {}.{} is being restarted", table_id.database_name, table_id.table_name);
    return result;
}

TableLockHolder IStorage::tryLockForShare(const String & query_id, const std::chrono::milliseconds & acquire_timeout)
{

Review comment (suggestion):
Converting `Poco::Timespan` to `std::chrono::milliseconds` via `totalMilliseconds()` truncates any sub-millisecond portion, which can make the effective timeout shorter than requested. If the API is moving to `Poco::Timespan`, consider converting using `totalMicroseconds()` and rounding up to milliseconds (or change the internal lock API to accept microseconds) to avoid unintended early timeouts.

Code after:
{
    if (metadata_)
        metadata.set(std::move(metadata_));
    else
        metadata.set(std::make_unique<StorageInMemoryMetadata>());
}

bool IStorage::isVirtualColumn(const String & column_name, const StorageMetadataPtr & metadata_snapshot) const
{
    /// Virtual column maybe overridden by real column
    return !metadata_snapshot->getColumns().has(column_name) && (virtuals.get()->has(column_name) || common_virtuals.has(column_name));
}

VirtualColumnsDescription IStorage::createCommonVirtuals()
{
    VirtualColumnsDescription desc;

    desc.addEphemeral("_table", std::make_shared<DataTypeLowCardinality>(std::make_shared<DataTypeString>()), "The name of table which the row comes from");

    return desc;
}

RWLockImpl::LockHolder IStorage::tryLockTimed(
    const RWLock & rwlock, RWLockImpl::Type type, const String & query_id, const Poco::Timespan & acquire_timeout) const
{
    auto lock_holder = rwlock->getLock(type, query_id, std::chrono::milliseconds(acquire_timeout.totalMilliseconds()));
    if (!lock_holder)
    {
        const String type_str = type == RWLockImpl::Type::Read ? "READ" : "WRITE";
        throw Exception(ErrorCodes::DEADLOCK_AVOIDED,
            "{} locking attempt on \"{}\" has timed out! ({}ms) Possible deadlock avoided. Client should retry. Owner query ids: {}",
            type_str, getStorageID(), acquire_timeout.totalMilliseconds(), rwlock->getOwnerQueryIdsDescription());
    }
    return lock_holder;
}

TableLockHolder IStorage::lockForShare(const String & query_id, const Poco::Timespan & acquire_timeout)
{
    TableLockHolder result = tryLockTimed(drop_lock, RWLockImpl::Read, query_id, acquire_timeout);
    auto table_id = getStorageID();
    if (!table_id.hasUUID() && (is_dropped || is_detached))
        throw Exception(ErrorCodes::TABLE_IS_DROPPED, "Table {}.{} is dropped or detached", table_id.database_name, table_id.table_name);

    if (is_being_restarted)
        throw Exception(
            ErrorCodes::TABLE_IS_BEING_RESTARTED, "Table {}.{} is being restarted", table_id.database_name, table_id.table_name);
    return result;
}

TableLockHolder IStorage::tryLockForShare(const String & query_id, const Poco::Timespan & acquire_timeout)
{