]> git.proxmox.com Git - ceph.git/blob - ceph/src/os/bluestore/ZonedAllocator.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / os / bluestore / ZonedAllocator.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 //
5 // A simple allocator that just hands out space from the next empty zone. This
6 // is temporary, just to get the simplest append-only write workload to work.
7 //
8 // Copyright (C) 2020 Abutalib Aghayev
9 //
10
11 #include "ZonedAllocator.h"
12 #include "bluestore_types.h"
13 #include "zoned_types.h"
14 #include "common/debug.h"
15
16 #define dout_context cct
17 #define dout_subsys ceph_subsys_bluestore
18 #undef dout_prefix
19 #define dout_prefix *_dout << "ZonedAllocator " << this << " "
20
21 ZonedAllocator::ZonedAllocator(CephContext* cct,
22 int64_t size,
23 int64_t block_size,
24 const std::string& name)
25 : Allocator(name, size, block_size),
26 cct(cct),
27 num_free(0),
28 size(size),
29 // To avoid interface changes, we piggyback zone size and the first
30 // sequential zone number onto the first 32 bits of 64-bit |block_size|.
31 // The last 32 bits of |block_size| is holding the actual block size.
32 block_size((block_size & 0x00000000ffffffff)),
33 zone_size(((block_size & 0x0000ffff00000000) >> 32) * 1024 * 1024),
34 starting_zone_num((block_size & 0xffff000000000000) >> 48),
35 num_zones(size / zone_size) {
36 ldout(cct, 10) << __func__ << " size 0x" << std::hex << size
37 << " zone size 0x" << zone_size << std::dec
38 << " number of zones " << num_zones
39 << " first sequential zone " << starting_zone_num
40 << dendl;
41 ceph_assert(size % zone_size == 0);
42 }
43
44 ZonedAllocator::~ZonedAllocator() {}
45
46 int64_t ZonedAllocator::allocate(
47 uint64_t want_size,
48 uint64_t alloc_unit,
49 uint64_t max_alloc_size,
50 int64_t hint,
51 PExtentVector *extents) {
52 std::lock_guard l(lock);
53
54 ceph_assert(want_size % 4096 == 0);
55
56 ldout(cct, 10) << __func__ << " trying to allocate "
57 << std::hex << want_size << dendl;
58
59 uint64_t zone_num = starting_zone_num;
60 for ( ; zone_num < num_zones; ++zone_num) {
61 if (fits(want_size, zone_num)) {
62 break;
63 }
64 ldout(cct, 10) << __func__ << " skipping zone " << zone_num
65 << " because there is not enough space: "
66 << " want_size = " << want_size
67 << " available = " << get_remaining_space(zone_num)
68 << dendl;
69 }
70
71 if (zone_num == num_zones) {
72 ldout(cct, 10) << __func__ << " failed to allocate" << dendl;
73 return -ENOSPC;
74 }
75
76 uint64_t offset = get_offset(zone_num);
77
78 ldout(cct, 10) << __func__ << " advancing zone " << std::hex
79 << zone_num << " write pointer from " << offset
80 << " to " << offset + want_size << dendl;
81
82 advance_write_pointer(zone_num, want_size);
83 if (get_remaining_space(zone_num) == 0) {
84 starting_zone_num = zone_num + 1;
85 }
86
87 ldout(cct, 10) << __func__ << std::hex << " zone " << zone_num
88 << " offset is now " << get_write_pointer(zone_num) << dendl;
89
90 ldout(cct, 10) << __func__ << " allocated " << std::hex << want_size
91 << " bytes at offset " << offset
92 << " located at zone " << zone_num
93 << " and zone offset " << offset % zone_size << dendl;
94
95 extents->emplace_back(bluestore_pextent_t(offset, want_size));
96 return want_size;
97 }
98
99 void ZonedAllocator::release(const interval_set<uint64_t>& release_set) {
100 std::lock_guard l(lock);
101 }
102
103 uint64_t ZonedAllocator::get_free() {
104 return num_free;
105 }
106
107 void ZonedAllocator::dump() {
108 std::lock_guard l(lock);
109 }
110
111 void ZonedAllocator::dump(std::function<void(uint64_t offset,
112 uint64_t length)> notify) {
113 std::lock_guard l(lock);
114 }
115
116 // This just increments |num_free|. The actual free space is added by
117 // set_zone_states, as it updates the write pointer for each zone.
118 void ZonedAllocator::init_add_free(uint64_t offset, uint64_t length) {
119 ldout(cct, 40) << __func__ << " " << std::hex
120 << offset << "~" << length << dendl;
121
122 num_free += length;
123 }
124
125 void ZonedAllocator::init_rm_free(uint64_t offset, uint64_t length) {
126 std::lock_guard l(lock);
127 ldout(cct, 40) << __func__ << " 0x" << std::hex
128 << offset << "~" << length << dendl;
129
130 num_free -= length;
131 ceph_assert(num_free >= 0);
132
133 uint64_t zone_num = offset / zone_size;
134 uint64_t write_pointer = offset % zone_size;
135 uint64_t remaining_space = get_remaining_space(zone_num);
136
137 ceph_assert(get_write_pointer(zone_num) == write_pointer);
138 ceph_assert(remaining_space <= length);
139 advance_write_pointer(zone_num, remaining_space);
140
141 ldout(cct, 40) << __func__ << " set zone 0x" << std::hex
142 << zone_num << " write pointer to 0x" << zone_size << dendl;
143
144 length -= remaining_space;
145 ceph_assert(length % zone_size == 0);
146
147 for ( ; length; length -= zone_size) {
148 advance_write_pointer(++zone_num, zone_size);
149 ldout(cct, 40) << __func__ << " set zone 0x" << std::hex
150 << zone_num << " write pointer to 0x" << zone_size << dendl;
151 }
152 }
153
154 bool ZonedAllocator::zoned_get_zones_to_clean(std::deque<uint64_t> *zones_to_clean) {
155 // TODO: make 0.25 tunable
156 if (static_cast<double>(num_free) / size > 0.25) {
157 return false;
158 }
159 {
160 std::lock_guard l(lock);
161 // TODO: populate |zones_to_clean| with the numbers of zones that should be
162 // cleaned.
163 }
164 return true;
165 }
166
167 void ZonedAllocator::zoned_set_zone_states(std::vector<zone_state_t> &&_zone_states) {
168 std::lock_guard l(lock);
169 ldout(cct, 10) << __func__ << dendl;
170 zone_states = std::move(_zone_states);
171 }
172
173 void ZonedAllocator::shutdown() {
174 ldout(cct, 1) << __func__ << dendl;
175 }