Compare commits

..
Author SHA1 Message Date
Vitaliy Filippov facaa2cc6a Release 3.0.3
- Fix csum_block_size > 0 unusable with atomic writes in the new store
  (almost all atomic write requests generated invalid checksums with csum_block_size > 0)
- Fix monitor sometimes randomly failing to optimize PGs with the "problem is
  infeasible or unbounded" message due to not waiting to read full stdout of lp_solve
- Remove reshard_abort optimisation to fix chunked resharding introduced in 3.0.2 possibly
  corrupting in-memory OSD state when handling multiple rapid PG count change requests
- Fix removed inodes not disappearing from OSD statistics in the new store, leading to
  bloating of the statistics with old inodes
- Increase test coverage for the new store and fix several minor bugs:
  - Enabling/disabling of used_for_app was recalculating inode space statistics incorrectly
  - Fix object metadata validation on OSD startup rejecting some correct sequences of entries,
    possibly leading to OSD being unable to start
  - Fix PG activation with EC failing in rare cases with EBUSY when requesting to commit an
    already committed write
  - Fix a theoretically possible metadata writeback issue on ENOSPC during commit
- Fix monitor failing to optimize PGs in presence of a host with name convertible to
  js Number (like 04e278988710) :D
- Fix vitastor-cli dd sometimes (rarely) truncating the image when writing to stdout
- Fix a theoretically possible client connection object leak when io_uring is full
- Fix a leak of RDMA-CM connection objects
- Fix crashes with data_block_size < 32KB (useless setup, but anyway) (#113)
2026-02-08 01:39:57 +03:00
Vitaliy Filippov d2ac8e3827 Fix block writeback on enospc during commit 2026-02-07 16:27:26 +03:00
Vitaliy Filippov d6dacc67db Do not return EBUSY when already stable in the new store 2026-02-07 16:10:39 +03:00
Vitaliy Filippov cbe51595cb Remove reshard_abort 2026-02-07 16:05:40 +03:00
Vitaliy Filippov 6bd0830ab8 Add a test for chunked resharding 2026-02-07 16:02:17 +03:00
Vitaliy Filippov 796e82f34d Check get_compacted_count and get_compact_queue_size 2026-02-07 15:44:54 +03:00
Vitaliy Filippov db39283970 Add a test for complete_lsn_write 2026-02-07 15:36:46 +03:00
Vitaliy Filippov 9f8c686321 Add a test for redirect_intent 2026-02-07 15:09:58 +03:00
Vitaliy Filippov 2618e559d1 Add rollback tests, simplify rollback logic 2026-02-07 15:09:58 +03:00
Vitaliy Filippov 037d2bc162 Add a test for recalc_inode_stats in the new store and fix a bug in it 2026-02-07 14:00:10 +03:00
Vitaliy Filippov f0b64adb32 Fix removed inodes not disappearing from statistics in the new store 2026-02-07 02:48:49 +03:00
Vitaliy Filippov f06d64d879 Fix validate_object commit validation bug 2026-02-06 18:52:37 +03:00
Vitaliy Filippov d164499a1c Add more iterate_compaction test cases 2026-02-06 18:52:19 +03:00
Vitaliy Filippov 725e9aa8ae Remove unused read_locked_entry 2026-02-06 17:38:59 +03:00
Vitaliy Filippov 0715feffa1 Wait for finished read, not for process exit in lp_optimizer 2026-02-04 02:33:08 +03:00
Vitaliy Filippov e9f37e8dc3 Fix NaN PG optimisation error when a hostname has a name convertible to js Number... some shit like 04e278988710 2026-02-04 15:08:03 +03:00
Vitaliy Filippov 4fbe4b5654 Fix BIG_INTENT rechecks with enabled checksums 2026-02-04 02:33:50 +03:00
Vitaliy Filippov 9fb645693b Fix checksums with BIG_INTENT writes in the new store 2026-02-04 02:33:50 +03:00
Vitaliy Filippov 9e47828383 Add a test for big_intent with checksums 2026-02-04 02:33:50 +03:00
31 changed files with 1068 additions and 310 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.12)
project(vitastor)
set(VITASTOR_VERSION "3.0.2")
set(VITASTOR_VERSION "3.0.3")
include(CTest)
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v3.0.2
VITASTOR_VERSION ?= v3.0.3
all: build push
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v3.0.2
image: vitalif/vitastor-csi:v3.0.3
args:
- "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -121,7 +121,7 @@ spec:
privileged: true
capabilities:
add: ["SYS_ADMIN"]
image: vitalif/vitastor-csi:v3.0.2
image: vitalif/vitastor-csi:v3.0.3
args:
- "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -5,7 +5,7 @@ package vitastor
const (
vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "3.0.2"
vitastorCSIDriverVersion = "3.0.3"
)
// Config struct fills the parameters of request or user input
+1 -1
View File
@@ -1,4 +1,4 @@
vitastor (3.0.2-1) unstable; urgency=medium
vitastor (3.0.3-1) unstable; urgency=medium
* Bugfixes
+1 -1
View File
@@ -1,4 +1,4 @@
VITASTOR_VERSION ?= v3.0.2
VITASTOR_VERSION ?= v3.0.3
all: build push
+1 -1
View File
@@ -4,7 +4,7 @@
#
# Desired Vitastor version
VITASTOR_VERSION=v3.0.2
VITASTOR_VERSION=v3.0.3
# Additional arguments for all containers
# For example, you may want to specify a custom logging driver here
+2 -2
View File
@@ -26,9 +26,9 @@ at Vitastor Kubernetes operator: https://github.com/Antilles7227/vitastor-operat
The instruction is very simple.
1. Download a Docker image of the desired version: \
`docker pull vitalif/vitastor:v3.0.2`
`docker pull vitalif/vitastor:v3.0.3`
2. Install scripts to the host system: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.2 install.sh`
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.3 install.sh`
3. Reload udev rules: \
`udevadm control --reload-rules`
+2 -2
View File
@@ -25,9 +25,9 @@ Vitastor можно установить в Docker/Podman. При этом etcd,
Инструкция по установке максимально простая.
1. Скачайте Docker-образ желаемой версии: \
`docker pull vitalif/vitastor:v3.0.2`
`docker pull vitalif/vitastor:v3.0.3`
2. Установите скрипты в хост-систему командой: \
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.2 install.sh`
`docker run --rm -it -v /etc:/host-etc -v /usr/bin:/host-bin vitalif/vitastor:v3.0.3 install.sh`
3. Перезагрузите правила udev: \
`udevadm control --reload-rules`
+8 -5
View File
@@ -10,16 +10,19 @@ const NO_OSD = 'Z';
async function lp_solve(text)
{
const cp = child_process.spawn('lp_solve');
let stdout = '', stderr = '', finish_cb;
let stdout = '', stderr = '', finish_cb, finished = 0;
cp.stdout.on('data', buf => stdout += buf.toString());
cp.stderr.on('data', buf => stderr += buf.toString());
cp.on('exit', () => finish_cb && finish_cb());
cp.stdout.on('end', () => finish_cb());
cp.stderr.on('end', () => finish_cb());
cp.stdin.write(text);
cp.stdin.end();
if (cp.exitCode == null)
await new Promise(ok => (finish_cb = () =>
{
await new Promise(ok => finish_cb = ok);
}
finished++;
if (finished == 2)
ok();
}));
if (!stdout.trim())
{
return null;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vitastor-mon",
"version": "3.0.2",
"version": "3.0.3",
"description": "Vitastor SDS monitor service",
"main": "mon-main.js",
"scripts": {
+1 -1
View File
@@ -195,7 +195,7 @@ async function generate_pool_pgs(state, global_config, pool_id, osd_tree, levels
const folded_tree = make_hier_tree(global_config, folded.nodes.reduce((a, c) => { a[c.id] = c; return a; }, {}));
const old_pg_count = prev_pgs.length;
const optimize_cfg = {
osd_weights: folded.nodes.reduce((a, c) => { if (Number(c.id)) { a[c.id] = c.size; } return a; }, {}),
osd_weights: folded.nodes.reduce((a, c) => { if (/^\d+$/.exec(c.id) && c.size != null) { a[c.id] = c.size||0; } return a; }, {}),
combinator: use_rules
// new algorithm:
? new RuleCombinator(folded_tree, rules, pool_cfg.max_osd_combinations)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vitastor",
"version": "3.0.2",
"version": "3.0.3",
"description": "Low-level native bindings to Vitastor client library",
"main": "index.js",
"keywords": [
+1 -1
View File
@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver
from cinder.volume import volume_utils
VITASTOR_VERSION = '3.0.2'
VITASTOR_VERSION = '3.0.3'
LOG = logging.getLogger(__name__)
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.2
Version: 3.0.3
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.2.el7.tar.gz
Source0: vitastor-3.0.3.el7.tar.gz
BuildRequires: gperftools-devel
BuildRequires: devtoolset-9-gcc-c++
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.2
Version: 3.0.3
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.2.el8.tar.gz
Source0: vitastor-3.0.3.el8.tar.gz
BuildRequires: gperftools-devel
BuildRequires: gcc-toolset-9-gcc-c++
+2 -2
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 3.0.2
Version: 3.0.3
Release: 1%{?dist}
Summary: Vitastor, a fast software-defined clustered block storage
License: Vitastor Network Public License 1.1
URL: https://vitastor.io/
Source0: vitastor-3.0.2.el9.tar.gz
Source0: vitastor-3.0.3.el9.tar.gz
BuildRequires: gperftools-devel
BuildRequires: gcc-c++
+1 -1
View File
@@ -21,7 +21,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
endif()
set(ENABLE_COVERAGE false CACHE BOOL "Enable code coverage")
add_definitions(-DVITASTOR_VERSION="3.0.2")
add_definitions(-DVITASTOR_VERSION="3.0.3")
add_definitions(-D_GNU_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -fno-omit-frame-pointer -fvisibility=hidden -I ${CMAKE_SOURCE_DIR}/src)
add_link_options(-fno-omit-frame-pointer)
if (${WITH_ASAN})
-1
View File
@@ -187,7 +187,6 @@ public:
// MUST be called only when nobody makes any modifications to the DB for this pool
virtual void* reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit) = 0;
virtual bool reshard_continue(void *reshard_state, uint64_t chunk_limit) = 0;
virtual void reshard_abort(void *reshard_state) = 0;
// Event loop
virtual void loop() = 0;
+46 -68
View File
@@ -458,19 +458,22 @@ bool blockstore_heap_t::validate_object(heap_entry_t *obj)
next_wr = wr;
if (wr->type() == BS_HEAP_ROLLBACK)
{
if (commit_wr && wr->version > commit_wr->version)
{
// rollback may not come before commit with a smaller version
fprintf(stderr, "Error: rollback entry %jx:%jx v%ju l%ju comes before a commit entry v%ju l%ju\n",
wr->inode, wr->stripe, wr->version, wr->lsn, commit_wr->version, commit_wr->lsn);
return false;
}
rollback_wr = wr;
continue;
}
if (wr->type() == BS_HEAP_COMMIT)
{
commit_wr = wr;
if (commit_wr && wr->version > commit_wr->version)
{
// commit may not come before commit with a smaller version
fprintf(stderr, "Error: commit entry %jx:%jx v%ju l%ju comes before a commit entry v%ju l%ju\n",
wr->inode, wr->stripe, wr->version, wr->lsn, commit_wr->version, commit_wr->lsn);
return false;
}
if (!commit_wr)
{
commit_wr = wr;
}
continue;
}
if (wr->entry_type & BS_HEAP_STABLE)
@@ -837,7 +840,6 @@ bool blockstore_heap_t::calc_checksums(heap_entry_t *wr, uint8_t *data, bool set
{
return true;
}
uint32_t len = 0;
if (wr->type() == BS_HEAP_SMALL_WRITE || wr->type() == BS_HEAP_INTENT_WRITE)
len = wr->small().len;
else if (wr->type() == BS_HEAP_BIG_INTENT)
@@ -854,13 +856,14 @@ bool blockstore_heap_t::calc_checksums(heap_entry_t *wr, uint8_t *data, bool set
}
if (wr->type() == BS_HEAP_BIG_WRITE)
{
assert(offset != UINT32_MAX && len != UINT32_MAX);
return calc_block_checksums((uint32_t*)(wr->get_checksums(this) + offset/dsk->csum_block_size * (dsk->data_csum_type & 0xFF)),
data, wr->get_int_bitmap(this), offset, offset+len, set, NULL);
}
if (wr->type() == BS_HEAP_BIG_INTENT)
{
auto & bi = wr->big_intent();
return calc_block_checksums((uint32_t*)(wr->get_checksums(this) + offset/dsk->csum_block_size * (dsk->data_csum_type & 0xFF)),
return calc_block_checksums((uint32_t*)(wr->get_checksums(this) + bi.offset/dsk->csum_block_size * (dsk->data_csum_type & 0xFF)),
data, wr->get_int_bitmap(this), bi.offset, bi.offset+bi.len, set, NULL);
}
assert(wr->type() == BS_HEAP_SMALL_WRITE || wr->type() == BS_HEAP_INTENT_WRITE);
@@ -1077,16 +1080,6 @@ bool blockstore_heap_t::reshard_check(pool_id_t pool, uint32_t pg_count, uint32_
set_it->second.pg_stripe_size == pg_stripe_size);
}
void blockstore_heap_t::reshard_abort(void* reshard_state)
{
heap_reshard_state_t *st = (heap_reshard_state_t*)reshard_state;
for (auto sh_it = st->old_shards.begin(); sh_it != st->old_shards.end(); sh_it++)
{
block_index[sh_it->first] = std::move(sh_it->second);
}
delete st;
}
heap_entry_t *blockstore_heap_t::lock_and_read_entry(object_id oid)
{
auto obj = read_entry(oid);
@@ -1099,27 +1092,6 @@ heap_entry_t *blockstore_heap_t::lock_and_read_entry(object_id oid)
return obj;
}
heap_entry_t *blockstore_heap_t::read_locked_entry(object_id oid, uint64_t lsn)
{
auto obj = read_entry(oid);
assert(obj);
for (auto wr = obj; wr; wr = prev(wr))
{
if (wr->is_overwrite())
{
if (lsn == wr->lsn)
{
return obj;
}
else
{
obj = prev(wr);
}
}
}
return NULL;
}
bool blockstore_heap_t::unlock_entry(object_id oid)
{
auto mvcc_it = object_mvcc.find(oid);
@@ -1347,7 +1319,6 @@ int blockstore_heap_t::add_small_write(object_id oid, heap_entry_t **obj_ptr, ui
// Small writes are written in parallel with buffered data so they require explicit_complete
return add_entry(wr_size, modified_block, false, true, [&](heap_entry_t *wr)
{
printf("add_small_write t%u %lx:%lx l%lu v%lu %u +%u loc:%lx\n", type, oid.inode, oid.stripe, wr->lsn, version, offset, len, location);
wr->entry_type = type;
wr->inode = oid.inode;
wr->stripe = oid.stripe;
@@ -1377,7 +1348,6 @@ int blockstore_heap_t::add_big_write(object_id oid, heap_entry_t *old_head, bool
// Big writes are written after writing data so they don't require explicit_complete
return add_entry(wr_size, modified_block, false, false, [&](heap_entry_t *wr)
{
printf("add_big_write %lx:%lx l%lu v%lu loc:%lx\n", oid.inode, oid.stripe, wr->lsn, version, location);
wr->entry_type = BS_HEAP_BIG_WRITE | (stable ? BS_HEAP_STABLE : 0);
wr->inode = oid.inode;
wr->stripe = oid.stripe;
@@ -1404,7 +1374,6 @@ int blockstore_heap_t::add_redirect_intent(object_id oid, heap_entry_t **obj_ptr
// Big-redirect intents, just like regular big writes, are written after writing data so they don't require explicit_complete
return add_entry(wr_size, modified_block, false, false, [&](heap_entry_t *wr)
{
printf("add_redir_intent %lx:%lx l%lu v%lu %u +%u loc:%lx\n", oid.inode, oid.stripe, wr->lsn, version, offset, len, location);
wr->entry_type = BS_HEAP_BIG_INTENT|BS_HEAP_STABLE;
wr->inode = oid.inode;
wr->stripe = oid.stripe;
@@ -1421,7 +1390,7 @@ int blockstore_heap_t::add_redirect_intent(object_id oid, heap_entry_t **obj_ptr
bitmap_set(wr->get_int_bitmap(this), offset, len, dsk->bitmap_granularity);
if (dsk->data_csum_type)
memset(wr->get_checksums(this), 0, get_csum_size(wr));
calc_checksums(wr, (uint8_t*)data, true, offset, len);
calc_checksums(wr, (uint8_t*)data, true);
*obj_ptr = wr;
});
}
@@ -1441,7 +1410,6 @@ int blockstore_heap_t::add_big_intent(object_id oid, heap_entry_t **obj_ptr, uin
// Big intents are written before writing data so they require explicit_complete
return add_entry(wr_size, modified_block, false, true, [&](heap_entry_t *wr)
{
printf("add_big_intent %lx:%lx l%lu v%lu %u +%u loc:%lx\n", oid.inode, oid.stripe, wr->lsn, version, offset, len, obj->big_location(this));
wr->entry_type = BS_HEAP_BIG_INTENT | BS_HEAP_STABLE;
wr->inode = oid.inode;
wr->stripe = oid.stripe;
@@ -1461,11 +1429,11 @@ int blockstore_heap_t::add_big_intent(object_id oid, heap_entry_t **obj_ptr, uin
if (dsk->data_csum_type)
{
if (checksums)
memcpy(wr->get_checksums(this), checksums, dsk->clean_entry_bitmap_size);
memcpy(wr->get_checksums(this), checksums, get_csum_size(wr));
else
{
memcpy(wr->get_checksums(this), obj->get_checksums(this), dsk->clean_entry_bitmap_size);
calc_checksums(wr, (uint8_t*)data, true, offset, len);
memcpy(wr->get_checksums(this), obj->get_checksums(this), get_csum_size(wr));
calc_checksums(wr, (uint8_t*)data, true);
}
}
else
@@ -1497,7 +1465,6 @@ int blockstore_heap_t::add_compact(heap_entry_t *obj, uint64_t compact_version,
// Compaction entry is added after copying data so it doesn't require explicit_complete
return add_entry(wr_size, modified_block, true, false, [&](heap_entry_t *new_wr)
{
printf("add_compact %lx:%lx l%lu v%lu loc:%lx\n", obj->inode, obj->stripe, compact_lsn, compact_version, compact_location);
new_wr->entry_type = BS_HEAP_BIG_WRITE|BS_HEAP_STABLE;
new_wr->inode = obj->inode;
new_wr->stripe = obj->stripe;
@@ -1587,7 +1554,7 @@ int blockstore_heap_t::add_commit(heap_entry_t *obj, uint64_t version, uint32_t
}
if (!uncommitted)
{
return EBUSY;
return 0;
}
return add_simple(obj, version, modified_block, BS_HEAP_COMMIT);
}
@@ -1597,23 +1564,32 @@ int blockstore_heap_t::add_rollback(heap_entry_t *obj, uint64_t version, uint32_
heap_entry_t *wr = obj;
bool found_uncommitted = false;
uint64_t commit_version = 0;
while (wr && !wr->is_overwrite())
uint64_t rollback_version = UINT64_MAX;
while (wr)
{
if (wr->type() == BS_HEAP_ROLLBACK)
{
auto rollback_version = wr->version;
wr = prev(wr);
while (wr->version > rollback_version)
if (wr->version <= version)
{
assert(!(wr->entry_type & BS_HEAP_STABLE));
wr = prev(wr);
// All previous writes are already rolled back, stop
break;
}
rollback_version = wr->version;
wr = prev(wr);
continue;
}
if (wr->type() == BS_HEAP_COMMIT)
{
if (commit_version < wr->version)
{
commit_version = wr->version;
}
wr = prev(wr);
continue;
}
if (wr->version > rollback_version)
{
// Already rolled back, skip
wr = prev(wr);
continue;
}
@@ -1624,14 +1600,10 @@ int blockstore_heap_t::add_rollback(heap_entry_t *obj, uint64_t version, uint32_
{
return EBUSY;
}
else if (wr->version == version)
else
{
break;
}
else if (wr->version < version)
{
return ENOENT;
}
}
else if (wr->version > version)
{
@@ -1812,9 +1784,9 @@ void blockstore_heap_t::iterate_with_stable(heap_entry_t *obj, uint64_t max_lsn,
}
else
{
// 1) 1 2 3 ROLLBACK(2) COMMIT(3) -> impossible
// 1) 1 2 3 ROLLBACK(2) COMMIT(3) -> 3 is unstable
// 2) 1 2 3 4 ROLLBACK(3) COMMIT(2) -> OK
// 3) 1 2 3 ROLLBACK(2) 3 COMMIT(3) -> first 3 shouldn't be treated as stable
// 3) 1 2 3 ROLLBACK(2) 3 COMMIT(3) -> first 3 is unstable
// 4) 1 2 3 COMMIT(3) ROLLBACK(2) -> impossible
// I.e. a rollback always has version >= previous commit
// 5) 1 2 3 4 5 ROLLBACK(4) 5 ROLLBACK(3)
@@ -2050,7 +2022,13 @@ void blockstore_heap_t::free_data(inode_t inode, uint64_t location)
inode = (INODE_POOL(inode) << POOL_ID_BITS);
assert(data_alloc->get(location / dsk->data_block_size));
data_alloc->set(location / dsk->data_block_size, false);
inode_space_stats[inode] -= dsk->data_block_size;
auto sp_it = inode_space_stats.find(inode);
if (sp_it != inode_space_stats.end())
{
sp_it->second -= dsk->data_block_size;
if (sp_it->second == 0)
inode_space_stats.erase(sp_it);
}
data_used_space -= dsk->data_block_size;
}
@@ -2333,7 +2311,7 @@ void blockstore_heap_t::set_no_inode_stats(const std::vector<uint64_t> & pool_id
{
// Recalculate if changed
if (ps.second.no_inode_stats == 2 || ps.second.no_inode_stats == 1)
recalc_inode_space_stats(ps.first, ps.second.no_inode_stats == 1);
recalc_inode_space_stats(ps.first, ps.second.no_inode_stats == 2);
ps.second.no_inode_stats &= 1;
}
}
@@ -2344,8 +2322,8 @@ void blockstore_heap_t::recalc_inode_space_stats(uint64_t pool_id, bool per_inod
auto sp_begin = inode_space_stats.lower_bound((pool_id << (64-POOL_ID_BITS)));
auto sp_end = inode_space_stats.lower_bound(((pool_id+1) << (64-POOL_ID_BITS)));
inode_space_stats.erase(sp_begin, sp_end);
uint32_t pg_count = ps.pg_count ? ps.pg_count : 1;
for (uint32_t pg_num = 1; pg_num <= pg_count; pg_num++)
uint32_t pg_count = ps.pg_count;
for (uint32_t pg_num = pg_count ? 1 : 0; pg_num <= pg_count; pg_num++)
{
auto & pg_idx = block_index[(pool_id << (64-POOL_ID_BITS)) | pg_num];
for (auto & ip: pg_idx)
+1 -4
View File
@@ -248,20 +248,17 @@ public:
void* reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit);
bool reshard_continue(void* reshard_state, uint64_t chunk_limit);
bool reshard_check(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size);
void reshard_abort(void* reshard_state);
void set_no_inode_stats(const std::vector<uint64_t> & pool_ids);
void recalc_inode_space_stats(uint64_t pool_id, bool per_inode);
// read an object entry and lock it against removal
// in the future, may become asynchronous
heap_entry_t *lock_and_read_entry(object_id oid);
// re-read a locked object entry with the given lsn (pointer may be invalidated)
heap_entry_t *read_locked_entry(object_id oid, uint64_t lsn);
// read an object entry without locking it
heap_entry_t *read_entry(object_id oid);
// unlock an entry
bool unlock_entry(object_id oid);
// set or verify checksums in a write request
bool calc_checksums(heap_entry_t *wr, uint8_t *data, bool set, uint32_t offset = 0, uint32_t len = 0);
bool calc_checksums(heap_entry_t *wr, uint8_t *data, bool set, uint32_t offset = UINT32_MAX, uint32_t len = UINT32_MAX);
// set or verify raw block checksums
bool calc_block_checksums(uint32_t *block_csums, uint8_t *data, uint8_t *bitmap, uint32_t start, uint32_t end,
bool set, std::function<void(uint32_t, uint32_t, uint32_t)> bad_block_cb);
-5
View File
@@ -406,8 +406,3 @@ bool blockstore_impl_t::reshard_continue(void *reshard_state, uint64_t chunk_lim
{
return heap->reshard_continue(reshard_state, chunk_limit);
}
void blockstore_impl_t::reshard_abort(void *reshard_state)
{
return heap->reshard_abort(reshard_state);
}
-1
View File
@@ -191,7 +191,6 @@ public:
void* reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit);
bool reshard_continue(void *reshard_state, uint64_t chunk_limit);
void reshard_abort(void *reshard_state);
// Event loop
void loop();
+1 -1
View File
@@ -57,9 +57,9 @@ int blockstore_impl_t::dequeue_stable(blockstore_op_t *op)
}
assert(res == 0);
}
resume_1:
if (priv->modified_block != UINT32_MAX && priv->modified_block2 != priv->modified_block)
{
resume_1:
BS_SUBMIT_CHECK_SQES(1);
prepare_meta_block_write(priv->modified_block);
resume_2:
+78 -172
View File
@@ -13,13 +13,10 @@ bool blockstore_impl_t::enqueue_write(blockstore_op_t *op)
return true;
}
bool blockstore_impl_t::prepare_meta_block_write(uint32_t modified_block)
void blockstore_impl_t::prepare_meta_block_write(uint32_t modified_block)
{
auto mod_it = modified_blocks.find(modified_block);
if (mod_it != modified_blocks.end())
{
return !mod_it->second.sent;
}
if (modified_blocks.find(modified_block) != modified_blocks.end())
return;
io_uring_sqe *sqe = get_sqe();
assert(sqe != NULL);
ring_data_t *data = ((ring_data_t*)sqe->user_data);
@@ -44,7 +41,6 @@ bool blockstore_impl_t::prepare_meta_block_write(uint32_t modified_block)
unsynced_meta_write_count++;
pending_modified_blocks.push_back(modified_block);
modified_blocks[modified_block] = { .sent = false, .buf = buf };
return true;
}
bool blockstore_impl_t::meta_block_is_pending(uint32_t modified_block)
@@ -125,7 +121,6 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
heap_entry_t *obj = heap->read_entry(op->oid);
if (op->opcode == BS_OP_DELETE)
{
return continue_delete(op, 0);
// Delete
if (!obj || obj->type() == BS_HEAP_DELETE)
{
@@ -138,38 +133,17 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
BS_SUBMIT_CHECK_SQES(1);
int res = heap->add_delete(obj, &PRIV(op)->modified_block);
if (res == ENOSPC)
{
goto enospc;
}
assert(res == 0);
prepare_meta_block_write(PRIV(op)->modified_block);
PRIV(op)->pending_ops++;
PRIV(op)->op_state = 5;
write_iodepth++;
resume_1:
while (!prepare_meta_block_write(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 1;
return 1;
}
rseume_2:
while (meta_block_is_pending(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 2;
return 1;
}
resume_3:
resume_4:
if (!throttle_write(op, 3))
{
return 1;
}
write_iodepth--;
ack_write(op);
return 2;
}
// FIXME: Allow to do initial writes as buffered, not redirected
// FIXME: Allow to do direct writes over holes
else if (!obj || obj->type() == BS_HEAP_DELETE || op->offset == 0 && op->len == dsk.data_block_size)
{
return continue_big_write(op, 10);
// Big (redirect) write
PRIV(op)->write_type = dsk.disable_data_fsync || op->opcode != BS_OP_WRITE_STABLE ? BS_HEAP_BIG_WRITE : _REDIRECT_INTENT;
BS_SUBMIT_CHECK_SQES(1);
@@ -189,7 +163,6 @@ enospc:
flusher->request_trim();
return 0;
}
write_iodepth++;
uint64_t loc = PRIV(op)->location;
#ifdef BLOCKSTORE_DEBUG
printf(
@@ -203,72 +176,18 @@ enospc:
data->iov = (struct iovec){ op->buf, op->len };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + loc + op->offset);
if (PRIV(op)->write_type == BS_HEAP_BIG_WRITE)
inflight_big++;
PRIV(op)->pending_ops++;
resume_10:
if (PRIV(op)->pending_ops > 0)
{
PRIV(op)->op_state = 10;
return 1;
}
write_iodepth++;
if (PRIV(op)->write_type == BS_HEAP_BIG_WRITE)
{
inflight_big--;
resume_11:
resume_12:
resume_13:
if (!fsync_big_write(op, 11))
return 1;
}
heap_entry_t *obj = heap->read_entry(op->oid);
int res = 0;
if (PRIV(op)->write_type == _REDIRECT_INTENT)
{
res = heap->add_redirect_intent(op->oid, &obj, op->version, op->offset, op->len,
PRIV(op)->location, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);
PRIV(op)->op_state = 1;
inflight_big++;
}
else
{
res = heap->add_big_write(op->oid, obj, op->opcode == BS_OP_WRITE_STABLE,
op->version, op->offset, op->len, PRIV(op)->location, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);
}
if (res == ENOSPC)
{
if (!heap->get_to_compact_count())
{
// no space
heap->free_data(op->oid.inode, PRIV(op)->location);
write_iodepth--;
op->retval = -ENOSPC;
FINISH_OP(op);
return 2;
}
PRIV(op)->wait_for = WAIT_COMPACTION;
PRIV(op)->wait_detail = heap->get_compacted_count();
flusher->request_trim();
return 0;
}
assert(res == 0);
resume_14:
while (!prepare_meta_block_write(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 14;
return 1;
}
resume_15:
while (meta_block_is_pending(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 15;
return 1;
}
write_iodepth--;
ack_write(op);
return 2;
PRIV(op)->op_state = 3;
}
else if (intent_write_allowed(op, obj))
{
return continue_intent_write(op, 20);
// Direct intent-write
BS_SUBMIT_CHECK_SQES(1);
int res = 0;
@@ -304,41 +223,13 @@ resume_15:
assert(res == 0);
PRIV(op)->lsn = obj->lsn;
}
write_iodepth++;
resume_20:
while (!prepare_meta_block_write(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 20;
return 1;
}
resume_21:
while (meta_block_is_pending(PRIV(op)->modified_block))
{
PRIV(op)->op_state = 21;
return 1;
}
// Direct intent-write
// LSN is not marked as completed so big_write won't be freed
BS_SUBMIT_GET_SQE(sqe, data);
data->iov = (struct iovec){ op->buf, op->len };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + PRIV(op)->location + op->offset);
if (dsk.use_atomic_flag)
sqe->rw_flags = RWF_ATOMIC;
prepare_meta_block_write(PRIV(op)->modified_block);
PRIV(op)->pending_ops++;
resume_22:
if (PRIV(op)->pending_ops > 0)
{
PRIV(op)->op_state = 22;
return 1;
}
write_iodepth--;
ack_write(op);
return 2;
PRIV(op)->op_state = 9;
write_iodepth++;
}
else
{
return continue_small_write(op, 30);
// Small (buffered) overwrite
// First check if there is free buffer space
PRIV(op)->write_type = BS_HEAP_SMALL_WRITE;
@@ -351,7 +242,7 @@ resume_22:
return 0;
}
// There is sufficient space. Check SQE(s)
BS_SUBMIT_CHECK_SQES(1 + (op->len > 0 ? 1 : 0)); ---> refactor too
BS_SUBMIT_CHECK_SQES(1 + (op->len > 0 ? 1 : 0));
int res = heap->add_small_write(op->oid, &obj, (BS_HEAP_SMALL_WRITE | (op->opcode == BS_OP_WRITE_STABLE ? BS_HEAP_STABLE : 0)),
op->version, op->offset, op->len, loc, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);
if (res == ENOSPC)
@@ -420,46 +311,27 @@ again:
goto again;
}
resume_2:
resume_4:
resume_6:
resume_8:
ack
return 2;
resume_10:
return 1;
}
bool blockstore_impl_t::fsync_big_write(blockstore_op_t *op, int base_state)
{
if (PRIV(op)->state == base_state)
goto resume_0;
else if (PRIV(op)->state == base_state+1)
goto resume_1;
else if (PRIV(op)->state == base_state+2)
goto resume_2;
// We must fsync all big writes to avoid complex write workflows
// It's OK for all HDDs and for server SSDs, but slightly worse for desktop SSDs
inflight_big--;
if (!dsk.disable_data_fsync)
{
// fsync data in a batch
resume_0:
resume_11:
if (inflight_big > 0)
{
PRIV(op)->op_state = base_state;
return false;
PRIV(op)->op_state = 11;
return 1;
}
if (fsyncing_data)
{
resume_1:
resume_12:
if (fsyncing_data)
{
PRIV(op)->op_state = base_state+1;
return false;
PRIV(op)->op_state = 12;
return 1;
}
return true;
goto resume_4;
}
fsyncing_data = true;
BS_SUBMIT_GET_SQE(sqe, data);
@@ -471,23 +343,47 @@ resume_1:
handle_write_event(data, op);
};
PRIV(op)->pending_ops++;
resume_2:
if (PRIV(op)->pending_ops > 0)
{
PRIV(op)->op_state = base_state+2;
return false;
}
PRIV(op)->op_state = 3;
return 1;
}
return true;
}
bool blockstore_impl_t::throttle_write(blockstore_op_t *op, int base_state)
{
// Apply throttling to not fill the journal too quickly for the SSD+HDD case
if (PRIV(op)->op_state >= base_state+1)
resume_4:
{
return true;
auto obj = heap->read_entry(op->oid);
int res = 0;
if (PRIV(op)->write_type == _REDIRECT_INTENT)
{
res = heap->add_redirect_intent(op->oid, &obj, op->version, op->offset, op->len,
PRIV(op)->location, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);
}
else
{
res = heap->add_big_write(op->oid, obj, op->opcode == BS_OP_WRITE_STABLE,
op->version, op->offset, op->len, PRIV(op)->location, op->bitmap, (uint8_t*)op->buf, &PRIV(op)->modified_block);
}
if (res == ENOSPC)
{
if (!heap->get_to_compact_count())
{
// no space
heap->free_data(op->oid.inode, PRIV(op)->location);
write_iodepth--;
op->retval = -ENOSPC;
FINISH_OP(op);
return 2;
}
PRIV(op)->wait_for = WAIT_COMPACTION;
PRIV(op)->wait_detail = heap->get_compacted_count();
flusher->request_trim();
return 0;
}
assert(res == 0);
prepare_meta_block_write(PRIV(op)->modified_block);
PRIV(op)->pending_ops++;
PRIV(op)->op_state = 5;
return 1;
}
resume_6:
// Apply throttling to not fill the journal too quickly for the SSD+HDD case
if (PRIV(op)->write_type == BS_HEAP_SMALL_WRITE && throttle_small_writes)
{
// Apply throttling
@@ -508,21 +404,17 @@ bool blockstore_impl_t::throttle_write(blockstore_op_t *op, int base_state)
if (ref_us > exec_us + throttle_threshold_us)
{
// Pause reply
PRIV(op)->op_state = base_state;
PRIV(op)->op_state = 7;
// Remember that the timer can in theory be called right here
tfd->set_timer_us(ref_us-exec_us, false, [this, op](int timer_id)
{
PRIV(op)->op_state++;
PRIV(op)->op_state = 8;
ringloop->wakeup();
});
return false;
return 1;
}
}
return true;
}
void blockstore_impl_t::ack_write(blockstore_op_t *op)
{
resume_8:
// Acknowledge write
#ifdef BLOCKSTORE_DEBUG
printf("Ack write %jx:%jx v%ju\n", op->oid.inode, op->oid.stripe, op->version);
@@ -549,7 +441,21 @@ void blockstore_impl_t::ack_write(blockstore_op_t *op)
unsynced_data_write_count++;
intent_write_counter++;
}
write_iodepth--;
FINISH_OP(op);
return 2;
resume_10:
// Direct intent-write
// LSN is not marked as completed so big_write won't be freed
BS_SUBMIT_GET_SQE(sqe, data);
data->iov = (struct iovec){ op->buf, op->len };
data->callback = [this, op](ring_data_t *data) { handle_write_event(data, op); };
io_uring_prep_writev(sqe, dsk.data_fd, &data->iov, 1, dsk.data_offset + PRIV(op)->location + op->offset);
if (dsk.use_atomic_flag)
sqe->rw_flags = RWF_ATOMIC;
PRIV(op)->pending_ops++;
PRIV(op)->op_state = 7;
return 1;
}
void blockstore_impl_t::handle_write_event(ring_data_t *data, blockstore_op_t *op)
-11
View File
@@ -480,17 +480,6 @@ resume_1:
return true;
}
void blockstore_impl_t::reshard_abort(void *reshard_state)
{
bs_reshard_state_t *st = (bs_reshard_state_t*)reshard_state;
for (auto sh_it = st->old_shards.begin(); sh_it != st->old_shards.end(); sh_it++)
{
auto & to = clean_db_shards[sh_it->first];
to.swap(sh_it->second);
}
delete st;
}
void blockstore_impl_t::process_list(blockstore_op_t *op)
{
uint32_t list_pg = op->pg_number+1;
-1
View File
@@ -290,7 +290,6 @@ public:
// Reshard database for a pool
void* reshard_start(pool_id_t pool, uint32_t pg_count, uint32_t pg_stripe_size, uint64_t chunk_limit);
bool reshard_continue(void *reshard_state, uint64_t chunk_limit);
void reshard_abort(void *reshard_state);
// Event loop
void loop();
+1 -1
View File
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor
Description: Vitastor client library
Version: 3.0.2
Version: 3.0.3
Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir}
+4 -8
View File
@@ -809,21 +809,17 @@ again:
goto again;
}
auto & pool_cfg = pool_it->second;
bool done = false;
if (pool_cfg.real_pg_count != pool_cfg.applied_pg_count ||
pool_cfg.pg_stripe_size != pool_cfg.applied_pg_stripe_size)
bool done = bs->reshard_continue(pool_cfg.reshard_state, pg_reshard_chunk_size);
if (done &&
(pool_cfg.real_pg_count != pool_cfg.applied_pg_count ||
pool_cfg.pg_stripe_size != pool_cfg.applied_pg_stripe_size))
{
// PG count changed again, reshard again
bs->reshard_abort(pool_cfg.reshard_state);
pool_cfg.applied_pg_count = pool_cfg.real_pg_count;
pool_cfg.applied_pg_stripe_size = pool_cfg.pg_stripe_size;
pool_cfg.reshard_state = bs->reshard_start(pool_id, pool_cfg.real_pg_count, pool_cfg.pg_stripe_size, pg_reshard_chunk_size);
done = !pool_cfg.reshard_state;
}
else
{
done = bs->reshard_continue(pool_cfg.reshard_state, pg_reshard_chunk_size);
}
if (done)
{
// Pool is resharded
+906 -9
View File
File diff suppressed because it is too large Load Diff