aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/datastore/buffer_stats.h
blob: 1974efa97ec3477512391f50b368bb474ce637bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#pragma once

#include "buffer_type.h"
#include "memory_stats.h"
#include <atomic>

namespace vespalib::datastore {

/**
 * Represents statistics for a given buffer in a data store.
 */
class BufferStats {
protected:
    // The number of entries that are allocated in the buffer.
    std::atomic<EntryCount> _alloc_entries;
    // The number of entries (of the allocated) that are used: _used_entries <= _alloc_entries.
    std::atomic<EntryCount> _used_entries;
    // The number of entries (of the used) that are on hold: _hold_entries <= _used_entries.
    // "On hold" is a transitionary state used when removing entries.
    std::atomic<EntryCount> _hold_entries;
    // The number of entries (of the used) that are dead: _dead_entries <= _used_entries.
    // A dead entry was first on hold, and is now available for reuse in the free list (if enabled).
    std::atomic<EntryCount> _dead_entries;

    // Number of bytes that are heap allocated (and used) by elements that are stored in this buffer.
    // For simple types this is always 0.
    std::atomic<size_t> _extra_used_bytes;
    // Number of bytes that are heap allocated (and used) by elements that are stored in this buffer and is now on hold.
    // For simple types this is always 0.
    std::atomic<size_t> _extra_hold_bytes;

public:
    BufferStats();

    size_t size() const { return _used_entries.load(std::memory_order_relaxed); }
    size_t capacity() const { return _alloc_entries.load(std::memory_order_relaxed); }
    size_t remaining() const { return capacity() - size(); }

    void pushed_back(size_t num_entries) {
        _used_entries.store(size() + num_entries, std::memory_order_relaxed);
    }

    size_t dead_entries() const { return _dead_entries.load(std::memory_order_relaxed); }
    size_t hold_entries() const { return _hold_entries.load(std::memory_order_relaxed); }
    size_t extra_used_bytes() const { return _extra_used_bytes.load(std::memory_order_relaxed); }
    size_t extra_hold_bytes() const { return _extra_hold_bytes.load(std::memory_order_relaxed); }

    void inc_extra_used_bytes(size_t value) { _extra_used_bytes.store(extra_used_bytes() + value, std::memory_order_relaxed); }

    void add_to_mem_stats(size_t entry_size, MemoryStats& stats) const;
};

/**
 * Provides low-level access to buffer stats for integration in BufferState.
 */
class InternalBufferStats : public BufferStats {
public:
    InternalBufferStats();
    void clear();
    void set_alloc_entries(size_t value) { _alloc_entries.store(value, std::memory_order_relaxed); }
    void set_dead_entries(size_t value) { _dead_entries.store(value, std::memory_order_relaxed); }
    void set_hold_entries(size_t value) { _hold_entries.store(value, std::memory_order_relaxed); }
    void inc_dead_entries(size_t value) { _dead_entries.store(dead_entries() + value, std::memory_order_relaxed); }
    void inc_hold_entries(size_t value) { _hold_entries.store(hold_entries() + value, std::memory_order_relaxed); }
    void dec_hold_entries(size_t value);
    void inc_extra_hold_bytes(size_t value) { _extra_hold_bytes.store(extra_hold_bytes() + value, std::memory_order_relaxed); }
    std::atomic<EntryCount>& used_entries_ref() { return _used_entries; }
    std::atomic<EntryCount>& dead_entries_ref() { return _dead_entries; }
    std::atomic<size_t>& extra_used_bytes_ref() { return _extra_used_bytes; }
    std::atomic<size_t>& extra_hold_bytes_ref() { return _extra_hold_bytes; }
};

}