ColumnUnique.h 20.8 KB
Newer Older
1
#pragma once
2
#include <Columns/IColumnUnique.h>
3 4
#include <Columns/ReverseIndex.h>

5 6
#include <Columns/ColumnVector.h>
#include <Columns/ColumnNullable.h>
7
#include <Columns/ColumnString.h>
8
#include <Columns/ColumnFixedString.h>
9

N
Nikolai Kochetov 已提交
10
#include <DataTypes/DataTypeNullable.h>
11
#include <DataTypes/NumberTraits.h>
12

13
#include <Common/typeid_cast.h>
14
#include <Common/assert_cast.h>
15
#include <ext/range.h>
16

A
Alexey Milovidov 已提交
17 18 19
#include <common/unaligned.h>


20 21 22
namespace DB
{

P
proller 已提交
23 24 25 26
namespace ErrorCodes
{
    extern const int ILLEGAL_COLUMN;
}
27

28
template <typename ColumnType>
29
class ColumnUnique final : public COWHelper<IColumnUnique, ColumnUnique<ColumnType>>
30
{
31
    friend class COWHelper<IColumnUnique, ColumnUnique<ColumnType>>;
32 33

private:
34
    explicit ColumnUnique(MutableColumnPtr && holder, bool is_nullable);
35
    explicit ColumnUnique(const IDataType & type);
36
    ColumnUnique(const ColumnUnique & other);
37

38
public:
39 40 41
    MutableColumnPtr cloneEmpty() const override;

    const ColumnPtr & getNestedColumn() const override;
42
    const ColumnPtr & getNestedNotNullableColumn() const override { return column_holder; }
43
    bool nestedColumnIsNullable() const override { return is_nullable; }
44

45 46
    size_t uniqueInsert(const Field & x) override;
    size_t uniqueInsertFrom(const IColumn & src, size_t n) override;
47 48 49
    MutableColumnPtr uniqueInsertRangeFrom(const IColumn & src, size_t start, size_t length) override;
    IColumnUnique::IndexesWithOverflow uniqueInsertRangeWithOverflow(const IColumn & src, size_t start, size_t length,
                                                                     size_t max_dictionary_size) override;
50 51
    size_t uniqueInsertData(const char * pos, size_t length) override;
    size_t uniqueDeserializeAndInsertFromArena(const char * pos, const char *& new_pos) override;
52

53
    size_t getDefaultValueIndex() const override { return 0; }
54
    size_t getNullValueIndex() const override;
55
    size_t getNestedTypeDefaultValueIndex() const override { return is_nullable ? 1 : 0; }
56 57
    bool canContainNulls() const override { return is_nullable; }

58 59 60
    Field operator[](size_t n) const override { return (*getNestedColumn())[n]; }
    void get(size_t n, Field & res) const override { getNestedColumn()->get(n, res); }
    StringRef getDataAt(size_t n) const override { return getNestedColumn()->getDataAt(n); }
N
Nikolai Kochetov 已提交
61 62
    StringRef getDataAtWithTerminatingZero(size_t n) const override
    {
63
        return getNestedColumn()->getDataAtWithTerminatingZero(n);
N
Nikolai Kochetov 已提交
64
    }
65 66 67
    UInt64 get64(size_t n) const override { return getNestedColumn()->get64(n); }
    UInt64 getUInt(size_t n) const override { return getNestedColumn()->getUInt(n); }
    Int64 getInt(size_t n) const override { return getNestedColumn()->getInt(n); }
68
    Float64 getFloat64(size_t n) const override { return getNestedColumn()->getFloat64(n); }
69
    Float32 getFloat32(size_t n) const override { return getNestedColumn()->getFloat32(n); }
70
    bool getBool(size_t n) const override { return getNestedColumn()->getBool(n); }
71
    bool isNullAt(size_t n) const override { return is_nullable && n == getNullValueIndex(); }
72
    StringRef serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const override;
73
    void updateHashWithValue(size_t n, SipHash & hash_func) const override
N
Nikolai Kochetov 已提交
74
    {
75
        return getNestedColumn()->updateHashWithValue(n, hash_func);
N
Nikolai Kochetov 已提交
76
    }
77

78
    int compareAt(size_t n, size_t m, const IColumn & rhs, int nan_direction_hint) const override;
79

80 81 82 83 84 85 86
    void getExtremes(Field & min, Field & max) const override { column_holder->getExtremes(min, max); }
    bool valuesHaveFixedSize() const override { return column_holder->valuesHaveFixedSize(); }
    bool isFixedAndContiguous() const override { return column_holder->isFixedAndContiguous(); }
    size_t sizeOfValueIfFixed() const override { return column_holder->sizeOfValueIfFixed(); }
    bool isNumeric() const override { return column_holder->isNumeric(); }

    size_t byteSize() const override { return column_holder->byteSize(); }
87
    void protect() override { column_holder->protect(); }
N
Nikolai Kochetov 已提交
88 89
    size_t allocatedBytes() const override
    {
90
        return column_holder->allocatedBytes()
91
               + index.allocatedBytes()
92
               + (nested_null_mask ? nested_null_mask->allocatedBytes() : 0);
93 94 95
    }
    void forEachSubcolumn(IColumn::ColumnCallback callback) override
    {
96
        callback(column_holder);
97
        index.setColumn(getRawColumnPtr());
98 99
        if (is_nullable)
            nested_column_nullable = ColumnNullable::create(column_holder, nested_null_mask);
N
Nikolai Kochetov 已提交
100
    }
101

102 103 104 105 106 107 108
    bool structureEquals(const IColumn & rhs) const override
    {
        if (auto rhs_concrete = typeid_cast<const ColumnUnique *>(&rhs))
            return column_holder->structureEquals(*rhs_concrete->column_holder);
        return false;
    }

109 110
    const UInt64 * tryGetSavedHash() const override { return index.tryGetSavedHash(); }

111 112
    UInt128 getHash() const override { return hash.getHash(*getRawColumnPtr()); }

113 114
private:

115
    IColumn::WrappedPtr column_holder;
116
    bool is_nullable;
117
    size_t size_of_value_if_fixed = 0;
118
    ReverseIndex<UInt64, ColumnType> index;
N
Nikolai Kochetov 已提交
119

120
    /// For DataTypeNullable, stores null map.
121 122
    IColumn::WrappedPtr nested_null_mask;
    IColumn::WrappedPtr nested_column_nullable;
N
Nikolai Kochetov 已提交
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    class IncrementalHash
    {
    private:
        UInt128 hash;
        std::atomic<size_t> num_added_rows;

        std::mutex mutex;
    public:
        IncrementalHash() : num_added_rows(0) {}

        UInt128 getHash(const ColumnType & column);
    };

    mutable IncrementalHash hash;

139
    void createNullMask();
140 141
    void updateNullMask();

142 143
    static size_t numSpecialValues(bool is_nullable) { return is_nullable ? 2 : 1; }
    size_t numSpecialValues() const { return numSpecialValues(is_nullable); }
144

145 146
    ColumnType * getRawColumnPtr() { return assert_cast<ColumnType *>(column_holder.get()); }
    const ColumnType * getRawColumnPtr() const { return assert_cast<const ColumnType *>(column_holder.get()); }
147

148 149
    template <typename IndexType>
    MutableColumnPtr uniqueInsertRangeImpl(
150 151 152
        const IColumn & src,
        size_t start,
        size_t length,
153
        size_t num_added_rows,
154
        typename ColumnVector<IndexType>::MutablePtr && positions_column,
155
        ReverseIndex<UInt64, ColumnType> * secondary_index,
156
        size_t max_dictionary_size);
157 158
};

159 160 161 162 163 164
template <typename ColumnType>
MutableColumnPtr ColumnUnique<ColumnType>::cloneEmpty() const
{
    return ColumnUnique<ColumnType>::create(column_holder->cloneResized(numSpecialValues()), is_nullable);
}

165
template <typename ColumnType>
166 167 168
ColumnUnique<ColumnType>::ColumnUnique(const ColumnUnique & other)
    : column_holder(other.column_holder)
    , is_nullable(other.is_nullable)
169
    , size_of_value_if_fixed (other.size_of_value_if_fixed)
170 171 172
    , index(numSpecialValues(is_nullable), 0)
{
    index.setColumn(getRawColumnPtr());
173
    createNullMask();
174 175 176 177 178 179
}

template <typename ColumnType>
ColumnUnique<ColumnType>::ColumnUnique(const IDataType & type)
    : is_nullable(type.isNullable())
    , index(numSpecialValues(is_nullable), 0)
N
Nikolai Kochetov 已提交
180
{
181 182
    const auto & holder_type = is_nullable ? *static_cast<const DataTypeNullable &>(type).getNestedType() : type;
    column_holder = holder_type.createColumn()->cloneResized(numSpecialValues());
183
    index.setColumn(getRawColumnPtr());
184
    createNullMask();
185 186 187

    if (column_holder->valuesHaveFixedSize())
        size_of_value_if_fixed = column_holder->sizeOfValueIfFixed();
N
Nikolai Kochetov 已提交
188 189
}

190
template <typename ColumnType>
K
kreuzerkrieg 已提交
191
ColumnUnique<ColumnType>::ColumnUnique(MutableColumnPtr && holder, bool is_nullable_)
192
    : column_holder(std::move(holder))
K
kreuzerkrieg 已提交
193 194
    , is_nullable(is_nullable_)
    , index(numSpecialValues(is_nullable_), 0)
195
{
196 197
    if (column_holder->size() < numSpecialValues())
        throw Exception("Too small holder column for ColumnUnique.", ErrorCodes::ILLEGAL_COLUMN);
C
chertus 已提交
198
    if (isColumnNullable(*column_holder))
199
        throw Exception("Holder column for ColumnUnique can't be nullable.", ErrorCodes::ILLEGAL_COLUMN);
200 201

    index.setColumn(getRawColumnPtr());
202
    createNullMask();
203 204 205

    if (column_holder->valuesHaveFixedSize())
        size_of_value_if_fixed = column_holder->sizeOfValueIfFixed();
206 207
}

208
template <typename ColumnType>
209
void ColumnUnique<ColumnType>::createNullMask()
N
Nikolai Kochetov 已提交
210 211 212
{
    if (is_nullable)
    {
213
        size_t size = getRawColumnPtr()->size();
214
        if (!nested_null_mask)
215 216 217
        {
            ColumnUInt8::MutablePtr null_mask = ColumnUInt8::create(size, UInt8(0));
            null_mask->getData()[getNullValueIndex()] = 1;
218 219
            nested_null_mask = std::move(null_mask);
            nested_column_nullable = ColumnNullable::create(column_holder, nested_null_mask);
220
        }
221 222 223 224 225 226 227 228 229 230 231 232 233 234
        else
            throw Exception("Null mask for ColumnUnique is already created.", ErrorCodes::LOGICAL_ERROR);
    }
}

template <typename ColumnType>
void ColumnUnique<ColumnType>::updateNullMask()
{
    if (is_nullable)
    {
        if (!nested_null_mask)
            throw Exception("Null mask for ColumnUnique is was not created.", ErrorCodes::LOGICAL_ERROR);

        size_t size = getRawColumnPtr()->size();
235

236
        if (nested_null_mask->size() != size)
237
            assert_cast<ColumnUInt8 &>(*nested_null_mask).getData().resize_fill(size);
N
Nikolai Kochetov 已提交
238
    }
239 240 241 242 243 244 245 246
}

template <typename ColumnType>
const ColumnPtr & ColumnUnique<ColumnType>::getNestedColumn() const
{
    if (is_nullable)
        return nested_column_nullable;

N
Nikolai Kochetov 已提交
247 248 249
    return column_holder;
}

250 251
template <typename ColumnType>
size_t ColumnUnique<ColumnType>::getNullValueIndex() const
252 253
{
    if (!is_nullable)
254
        throw Exception("ColumnUnique can't contain null values.", ErrorCodes::LOGICAL_ERROR);
255 256 257 258

    return 0;
}

259 260
template <typename ColumnType>
size_t ColumnUnique<ColumnType>::uniqueInsert(const Field & x)
261 262 263 264
{
    if (x.getType() == Field::Types::Null)
        return getNullValueIndex();

265 266
    if (size_of_value_if_fixed)
        return uniqueInsertData(&x.get<char>(), size_of_value_if_fixed);
267

268 269
    auto & val = x.get<String>();
    return uniqueInsertData(val.data(), val.size());
270 271
}

272 273
template <typename ColumnType>
size_t ColumnUnique<ColumnType>::uniqueInsertFrom(const IColumn & src, size_t n)
274
{
275 276 277
    if (is_nullable && src.isNullAt(n))
        return getNullValueIndex();

C
chertus 已提交
278
    if (auto * nullable = checkAndGetColumn<ColumnNullable>(src))
279 280
        return uniqueInsertFrom(nullable->getNestedColumn(), n);

281 282 283 284
    auto ref = src.getDataAt(n);
    return uniqueInsertData(ref.data, ref.size);
}

285 286
template <typename ColumnType>
size_t ColumnUnique<ColumnType>::uniqueInsertData(const char * pos, size_t length)
287 288 289
{
    auto column = getRawColumnPtr();

290 291
    if (column->getDataAt(getNestedTypeDefaultValueIndex()) == StringRef(pos, length))
        return getNestedTypeDefaultValueIndex();
292

293
    auto insertion_point = index.insert(StringRef(pos, length));
294

295 296
    updateNullMask();

297
    return insertion_point;
298 299
}

300 301 302 303 304
template <typename ColumnType>
StringRef ColumnUnique<ColumnType>::serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const
{
    if (is_nullable)
    {
305
        static constexpr auto s = sizeof(UInt8);
306

307 308 309
        auto pos = arena.allocContinue(s, begin);
        UInt8 flag = (n == getNullValueIndex() ? 1 : 0);
        unalignedStore<UInt8>(pos, flag);
310

311 312
        if (n == getNullValueIndex())
            return StringRef(pos, s);
313

314
        auto nested_ref = column_holder->serializeValueIntoArena(n, arena, begin);
315

316 317
        /// serializeValueIntoArena may reallocate memory. Have to use ptr from nested_ref.data and move it back.
        return StringRef(nested_ref.data - s, nested_ref.size + s);
318 319 320 321 322
    }

    return column_holder->serializeValueIntoArena(n, arena, begin);
}

323 324
template <typename ColumnType>
size_t ColumnUnique<ColumnType>::uniqueDeserializeAndInsertFromArena(const char * pos, const char *& new_pos)
325
{
326 327 328 329 330 331 332 333 334 335 336 337
    if (is_nullable)
    {
        UInt8 val = *reinterpret_cast<const UInt8 *>(pos);
        pos += sizeof(val);

        if (val)
        {
            new_pos = pos;
            return getNullValueIndex();
        }
    }

N
Nikolai Kochetov 已提交
338
    /// Numbers, FixedString
339
    if (size_of_value_if_fixed)
340
    {
341 342
        new_pos = pos + size_of_value_if_fixed;
        return uniqueInsertData(pos, size_of_value_if_fixed);
343 344
    }

N
Nikolai Kochetov 已提交
345
    /// String
A
Alexey Milovidov 已提交
346
    const size_t string_size = unalignedLoad<size_t>(pos);
347 348
    pos += sizeof(string_size);
    new_pos = pos + string_size;
349

N
Nikolai Kochetov 已提交
350 351
    /// -1 because of terminating zero
    return uniqueInsertData(pos, string_size - 1);
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
template <typename ColumnType>
int ColumnUnique<ColumnType>::compareAt(size_t n, size_t m, const IColumn & rhs, int nan_direction_hint) const
{
    if (is_nullable)
    {
        /// See ColumnNullable::compareAt
        bool lval_is_null = n == getNullValueIndex();
        bool rval_is_null = m == getNullValueIndex();

        if (unlikely(lval_is_null || rval_is_null))
        {
            if (lval_is_null && rval_is_null)
                return 0;
            else
                return lval_is_null ? nan_direction_hint : -nan_direction_hint;
        }
    }

    auto & column_unique = static_cast<const IColumnUnique &>(rhs);
    return getNestedColumn()->compareAt(n, m, *column_unique.getNestedColumn(), nan_direction_hint);
}

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
template <typename IndexType>
static void checkIndexes(const ColumnVector<IndexType> & indexes, size_t max_dictionary_size)
{
    auto & data = indexes.getData();
    for (size_t i = 0; i < data.size(); ++i)
    {
        if (data[i] >= max_dictionary_size)
        {
            throw Exception("Found index " + toString(data[i]) + " at position " + toString(i)
                            + " which is grated or equal than dictionary size " + toString(max_dictionary_size),
                            ErrorCodes::LOGICAL_ERROR);
        }
    }
}

391 392 393
template <typename ColumnType>
template <typename IndexType>
MutableColumnPtr ColumnUnique<ColumnType>::uniqueInsertRangeImpl(
394 395 396
    const IColumn & src,
    size_t start,
    size_t length,
397
    size_t num_added_rows,
398
    typename ColumnVector<IndexType>::MutablePtr && positions_column,
399
    ReverseIndex<UInt64, ColumnType> * secondary_index,
400
    size_t max_dictionary_size)
401 402 403
{
    const ColumnType * src_column;
    const NullMap * null_map = nullptr;
404 405
    auto & positions = positions_column->getData();

406
    auto update_position = [&](UInt64 & next_position) -> MutableColumnPtr
407
    {
408 409 410
        constexpr auto next_size = NumberTraits::nextSize(sizeof(IndexType));
        using SuperiorIndexType = typename NumberTraits::Construct<false, false, next_size>::Type;

411 412 413 414 415 416 417 418
        ++next_position;

        if (next_position > std::numeric_limits<IndexType>::max())
        {
            if (sizeof(SuperiorIndexType) == sizeof(IndexType))
                throw Exception("Can't find superior index type for type " + demangle(typeid(IndexType).name()),
                                ErrorCodes::LOGICAL_ERROR);

419
            auto expanded_column = ColumnVector<SuperiorIndexType>::create(length);
420 421 422 423 424 425
            auto & expanded_data = expanded_column->getData();
            for (size_t i = 0; i < num_added_rows; ++i)
                expanded_data[i] = positions[i];

            return uniqueInsertRangeImpl<SuperiorIndexType>(
                    src,
426 427 428
                    start,
                    length,
                    num_added_rows,
429
                    std::move(expanded_column),
430
                    secondary_index,
431 432 433 434 435
                    max_dictionary_size);
        }

        return nullptr;
    };
436

C
chertus 已提交
437
    if (auto * nullable_column = checkAndGetColumn<ColumnNullable>(src))
438
    {
439
        src_column = typeid_cast<const ColumnType *>(&nullable_column->getNestedColumn());
440 441 442
        null_map = &nullable_column->getNullMapData();
    }
    else
443
        src_column = typeid_cast<const ColumnType *>(&src);
444

445 446 447
    if (src_column == nullptr)
        throw Exception("Invalid column type for ColumnUnique::insertRangeFrom. Expected " + column_holder->getName() +
                        ", got " + src.getName(), ErrorCodes::ILLEGAL_COLUMN);
448

449 450
    auto column = getRawColumnPtr();

451
    UInt64 next_position = column->size();
452 453 454
    if (secondary_index)
        next_position += secondary_index->size();

455
    auto insert_key = [&](const StringRef & ref, ReverseIndex<UInt64, ColumnType> & cur_index) -> MutableColumnPtr
456
    {
457 458 459 460
        auto inserted_pos = cur_index.insert(ref);
        positions[num_added_rows] = inserted_pos;
        if (inserted_pos == next_position)
            return update_position(next_position);
461

462
        return nullptr;
463 464
    };

465
    for (; num_added_rows < length; ++num_added_rows)
466
    {
467
        auto row = start + num_added_rows;
468

N
Nikolai Kochetov 已提交
469
        if (null_map && (*null_map)[row])
470
            positions[num_added_rows] = getNullValueIndex();
471 472
        else if (column->compareAt(getNestedTypeDefaultValueIndex(), row, *src_column, 1) == 0)
            positions[num_added_rows] = getNestedTypeDefaultValueIndex();
473 474
        else
        {
475
            auto ref = src_column->getDataAt(row);
476
            MutableColumnPtr res = nullptr;
477

478
            if (secondary_index && next_position >= max_dictionary_size)
479
            {
480 481 482
                auto insertion_point = index.getInsertionPoint(ref);
                if (insertion_point == index.lastInsertionPoint())
                    res = insert_key(ref, *secondary_index);
483
                else
484
                    positions[num_added_rows] = insertion_point;
485
            }
486 487 488 489 490
            else
                res = insert_key(ref, index);

            if (res)
                return res;
491 492
        }
    }
493

494
    // checkIndexes(*positions_column, column->size() + (overflowed_keys ? overflowed_keys->size() : 0));
495
    return std::move(positions_column);
496 497
}

498 499
template <typename ColumnType>
MutableColumnPtr ColumnUnique<ColumnType>::uniqueInsertRangeFrom(const IColumn & src, size_t start, size_t length)
500
{
501
    auto callForType = [this, &src, start, length](auto x) -> MutableColumnPtr
502
    {
503 504
        size_t size = getRawColumnPtr()->size();

505 506 507
        using IndexType = decltype(x);
        if (size <= std::numeric_limits<IndexType>::max())
        {
508
            auto positions = ColumnVector<IndexType>::create(length);
509
            return this->uniqueInsertRangeImpl<IndexType>(src, start, length, 0, std::move(positions), nullptr, 0);
510
        }
511

512 513 514 515 516 517 518 519 520 521 522 523 524 525
        return nullptr;
    };

    MutableColumnPtr positions_column;
    if (!positions_column)
        positions_column = callForType(UInt8());
    if (!positions_column)
        positions_column = callForType(UInt16());
    if (!positions_column)
        positions_column = callForType(UInt32());
    if (!positions_column)
        positions_column = callForType(UInt64());
    if (!positions_column)
        throw Exception("Can't find index type for ColumnUnique", ErrorCodes::LOGICAL_ERROR);
526

527 528
    updateNullMask();

529 530 531
    return positions_column;
}

532 533
template <typename ColumnType>
IColumnUnique::IndexesWithOverflow ColumnUnique<ColumnType>::uniqueInsertRangeWithOverflow(
534 535 536 537 538 539 540 541 542 543
    const IColumn & src,
    size_t start,
    size_t length,
    size_t max_dictionary_size)
{
    auto overflowed_keys = column_holder->cloneEmpty();
    auto overflowed_keys_ptr = typeid_cast<ColumnType *>(overflowed_keys.get());
    if (!overflowed_keys_ptr)
        throw Exception("Invalid keys type for ColumnUnique.", ErrorCodes::LOGICAL_ERROR);

544
    auto callForType = [this, &src, start, length, overflowed_keys_ptr, max_dictionary_size](auto x) -> MutableColumnPtr
545
    {
546 547
        size_t size = getRawColumnPtr()->size();

548 549 550
        using IndexType = decltype(x);
        if (size <= std::numeric_limits<IndexType>::max())
        {
551
            auto positions = ColumnVector<IndexType>::create(length);
552 553
            ReverseIndex<UInt64, ColumnType> secondary_index(0, max_dictionary_size);
            secondary_index.setColumn(overflowed_keys_ptr);
554
            return this->uniqueInsertRangeImpl<IndexType>(src, start, length, 0, std::move(positions),
555
                                                          &secondary_index, max_dictionary_size);
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
        }

        return nullptr;
    };

    MutableColumnPtr positions_column;
    if (!positions_column)
        positions_column = callForType(UInt8());
    if (!positions_column)
        positions_column = callForType(UInt16());
    if (!positions_column)
        positions_column = callForType(UInt32());
    if (!positions_column)
        positions_column = callForType(UInt64());
    if (!positions_column)
        throw Exception("Can't find index type for ColumnUnique", ErrorCodes::LOGICAL_ERROR);
572

573 574
    updateNullMask();

575 576 577 578 579 580
    IColumnUnique::IndexesWithOverflow indexes_with_overflow;
    indexes_with_overflow.indexes = std::move(positions_column);
    indexes_with_overflow.overflowed_keys = std::move(overflowed_keys);
    return indexes_with_overflow;
}

581 582 583 584
template <typename ColumnType>
UInt128 ColumnUnique<ColumnType>::IncrementalHash::getHash(const ColumnType & column)
{
    size_t column_size = column.size();
585
    UInt128 cur_hash;
586 587 588 589 590 591 592 593

    if (column_size != num_added_rows.load())
    {
        SipHash sip_hash;
        for (size_t i = 0; i < column_size; ++i)
            column.updateHashWithValue(i, sip_hash);

        std::lock_guard lock(mutex);
594 595 596 597 598 599 600 601
        sip_hash.get128(hash.low, hash.high);
        cur_hash = hash;
        num_added_rows.store(column_size);
    }
    else
    {
        std::lock_guard lock(mutex);
        cur_hash = hash;
602 603 604 605 606
    }

    return cur_hash;
}

607
}