<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "serializer/log/extent_manager.hpp"

#include <queue>

#include "arch/arch.hpp"
#include "logger.hpp"
#include "perfmon/perfmon.hpp"
#include "serializer/log/log_serializer.hpp"

struct extent_info_t {
public:
    enum state_t {
        state_unreserved,
        state_in_use,
        state_free
    };
private:
    state_t state_;

public:
    void set_state(state_t new_state) {
        guarantee(state_ != state_in_use || extent_use_refcount == 0);
        state_ = new_state;
    }

    state_t state() const { return state_; }

    // Valid and non-zero when state_in_use.  There are two ways to own a part of
    // this refcount.  One is if you believe you're currently "using" the extent (if
    // you're the LBA or data_block_manager_t).  The other is (at the time of
    // writing) for every (extent_transaction_t, block_id) for live extent
    // transactions that have set an i_array entry to zero (in the data block
    // manager) but have not yet been commmitted.  The data_block_manager_t and LBA
    // ownership of the refcount also can get passed into the extent_transaction_t
    // object.
    int32_t extent_use_refcount;

    extent_info_t() : state_(state_unreserved),
                      extent_use_refcount(0) { }
};

class extent_zone_t {
    const size_t extent_size;

    unsigned int offset_to_id(int64_t extent) const {
        rassert(divides(extent_size, extent));
        return extent / extent_size;
    }

    /* Combination free-list and extent map. Contains one entry per extent.
    During the state_reserving_extents phase, each extent has state state_unreserved
    or state state_in_use. When we transition to the state_running phase,
    we link all of the state_unreserved entries in each zone together into an
    extent free list, such that each free entry's 'next_in_free_list' field is the
    offset of the next free extent. */

    segmented_vector_t<extent_info_t, MAX_DATA_EXTENTS> extents;

    // We want to remove the minimum element from the free_queue first, leaving
    // free extents at the end of the file.
    std::priority_queue<unsigned int,
                        std::vector<unsigned int>,
                        std::greater<unsigned int> > free_queue;

    file_t *const dbfile;

private:
    int held_extents_;

public:
    int held_extents() const {
        return held_extents_;
    }

    extent_zone_t(file_t *_dbfile, size_t _extent_size)
        : extent_size(_extent_size), dbfile(_dbfile), held_extents_(0) { }

    extent_reference_t reserve_extent(int64_t extent) {
        unsigned int id = offset_to_id(extent);

        if (id >= extents.get_size()) {
            extent_info_t default_info;
            extents.set_size(id + 1, default_info);
        }

        rassert(extents[id].state() == extent_info_t::state_unreserved);
        extents[id].set_state(extent_info_t::state_in_use);
        return make_extent_reference(extent);
    }

    void reconstruct_free_list() {
        for (int64_t extent = 0;
             extent < static_cast<int64_t>(extents.get_size() * extent_size);
             extent += extent_size) {
            const unsigned int extent_id = offset_to_id(extent);
            if (extents[extent_id].state() == extent_info_t::state_unreserved) {
                extents[extent_id].set_state(extent_info_t::state_free);
                free_queue.push(extent_id);
                ++held_extents_;
            }
        }
    }

    extent_reference_t gen_extent() {
        int64_t extent;

        if (free_queue.empty()) {
            extent = extents.get_size() * extent_size;
            extents.set_size(extents.get_size() + 1);
        } else {
            extent = free_queue.top() * extent_size;
            free_queue.pop();
            --held_extents_;
        }

        extent_info_t *info = &extents[offset_to_id(extent)];
        info->set_state(extent_info_t::state_in_use);

        extent_reference_t extent_ref = make_extent_reference(extent);

        dbfile->set_size_at_least(extent + extent_size);

        return extent_ref;
    }

    extent_reference_t make_extent_reference(const int64_t extent) {
        unsigned int id = offset_to_id(extent);
        guarantee(id < extents.get_size());
        extent_info_t *info = &extents[id];
        guarantee(info->state() == extent_info_t::state_in_use);
        ++info->extent_use_refcount;
        return extent_reference_t(extent);
    }

    void release_extent(extent_reference_t &&extent_ref) {
        int64_t extent = extent_ref.release();
        extent_info_t *info = &extents[offset_to_id(extent)];
        guarantee(info->state() == extent_info_t::state_in_use);
        guarantee(info->extent_use_refcount > 0);
        --info->extent_use_refcount;
        if (info->extent_use_refcount == 0) {
            info->set_state(extent_info_t::state_free);
            free_queue.push(offset_to_id(extent));
            ++held_extents_;
        }
    }
};
<commit_msg>Made extent_zone_t::extents be a vector.<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "serializer/log/extent_manager.hpp"

#include <queue>

#include "arch/arch.hpp"
#include "logger.hpp"
#include "perfmon/perfmon.hpp"
#include "serializer/log/log_serializer.hpp"

struct extent_info_t {
public:
    enum state_t {
        state_unreserved,
        state_in_use,
        state_free
    };
private:
    state_t state_;

public:
    void set_state(state_t new_state) {
        guarantee(state_ != state_in_use || extent_use_refcount == 0);
        state_ = new_state;
    }

    state_t state() const { return state_; }

    // Valid and non-zero when state_in_use.  There are two ways to own a part of
    // this refcount.  One is if you believe you're currently "using" the extent (if
    // you're the LBA or data_block_manager_t).  The other is (at the time of
    // writing) for every (extent_transaction_t, block_id) for live extent
    // transactions that have set an i_array entry to zero (in the data block
    // manager) but have not yet been commmitted.  The data_block_manager_t and LBA
    // ownership of the refcount also can get passed into the extent_transaction_t
    // object.
    int32_t extent_use_refcount;

    extent_info_t() : state_(state_unreserved),
                      extent_use_refcount(0) { }
};

class extent_zone_t {
    const size_t extent_size;

    unsigned int offset_to_id(int64_t extent) const {
        rassert(divides(extent_size, extent));
        return extent / extent_size;
    }

    /* Combination free-list and extent map. Contains one entry per extent.
    During the state_reserving_extents phase, each extent has state state_unreserved
    or state state_in_use. When we transition to the state_running phase,
    we link all of the state_unreserved entries in each zone together into an
    extent free list, such that each free entry's 'next_in_free_list' field is the
    offset of the next free extent. */

    std::vector<extent_info_t> extents;

    // We want to remove the minimum element from the free_queue first, leaving
    // free extents at the end of the file.
    std::priority_queue<unsigned int,
                        std::vector<unsigned int>,
                        std::greater<unsigned int> > free_queue;

    file_t *const dbfile;

    int held_extents_;

public:
    int held_extents() const {
        return held_extents_;
    }

    extent_zone_t(file_t *_dbfile, size_t _extent_size)
        : extent_size(_extent_size), dbfile(_dbfile), held_extents_(0) {
        // (Avoid a bunch of reallocations by resize calls (avoiding O(n log n)
        // work on average).)
        extents.reserve(dbfile->get_size() / extent_size);
    }

    extent_reference_t reserve_extent(int64_t extent) {
        unsigned int id = offset_to_id(extent);

        if (id >= extents.size()) {
            extents.resize(id + 1);
        }

        rassert(extents[id].state() == extent_info_t::state_unreserved);
        extents[id].set_state(extent_info_t::state_in_use);
        return make_extent_reference(extent);
    }

    void reconstruct_free_list() {
        // RSI: Iterate using extent id.
        for (int64_t extent = 0;
             extent < static_cast<int64_t>(extents.size() * extent_size);
             extent += extent_size) {
            const unsigned int extent_id = offset_to_id(extent);
            if (extents[extent_id].state() == extent_info_t::state_unreserved) {
                extents[extent_id].set_state(extent_info_t::state_free);
                free_queue.push(extent_id);
                ++held_extents_;
            }
        }
    }

    extent_reference_t gen_extent() {
        int64_t extent;

        if (free_queue.empty()) {
            extent = extents.size() * extent_size;
            extents.push_back(extent_info_t());
        } else {
            extent = free_queue.top() * extent_size;
            free_queue.pop();
            --held_extents_;
        }

        extent_info_t *info = &extents[offset_to_id(extent)];
        info->set_state(extent_info_t::state_in_use);

        extent_reference_t extent_ref = make_extent_reference(extent);

        dbfile->set_size_at_least(extent + extent_size);

        return extent_ref;
    }

    extent_reference_t make_extent_reference(const int64_t extent) {
        unsigned int id = offset_to_id(extent);
        guarantee(id < extents.size());
        extent_info_t *info = &extents[id];
        guarantee(info->state() == extent_info_t::state_in_use);
        ++info->extent_use_refcount;
        return extent_reference_t(extent);
    }

    void release_extent(extent_reference_t &&extent_ref) {
        int64_t extent = extent_ref.release();
        extent_info_t *info = &extents[offset_to_id(extent)];
        guarantee(info->state() == extent_info_t::state_in_use);
        guarantee(info->extent_use_refcount > 0);
        --info->extent_use_refcount;
        if (info->extent_use_refcount == 0) {
            info->set_state(extent_info_t::state_free);
            free_queue.push(offset_to_id(extent));
            ++held_extents_;
        }
    }
};

{'fraction_non_alphanumeric': 0.0942064503480051, 'fraction_numerical': 0.006175865111263602, 'mean_word_length': 2.692363373145132, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2216142', 'n_tokens_mistral': 3320, 'n_tokens_neox': 3237, 'n_words': 750}