Compare commits

...
13 Commits
Author SHA1 Message Date
Vitaliy Filippov 9301c857b1 Release 1.6.1
A bunch of monitor fixes

- Add noout flag for OSDs (/vitastor/config/osd/xx)
- Fix "effective" size of degraded PGs (and thus "used space") calculation in monitor
- Fix monitor not clearing PGs of deleted pools
- Fix incorrect PG generation with hosts with 0 OSDs
- Fix monitor crashing during primary OSD recheck when pool has no PGs
- Fix monitor crashing when node_placement included non-existing OSDs
- Fix possible data movement after removing OSDs reweighted to 0
- Remove extra empty keys from pool configurations created by vitastor-cli create-pool
- Fix 32-bit build
2024-04-22 02:01:29 +03:00
Vitaliy Filippov 3094358ec2 Fix autovivification leading to extra empty keys in pool-create 2024-04-20 02:04:09 +03:00
Vitaliy Filippov 87f666d2a2 Filter out OSDs reweighted to 0 2024-04-20 02:03:53 +03:00
Vitaliy Filippov bd7fe4ef8f Filter out non-existing OSDs added in node_placement 2024-04-20 02:03:36 +03:00
Vitaliy Filippov 1b3f9a1416 Do not set non-existing OSD weight to 0, we'll remove them instead 2024-04-20 02:03:11 +03:00
Vitaliy Filippov a7b7354f38 Do not recheck primary distribution when pool has no PGs 2024-04-20 02:02:47 +03:00
Vitaliy Filippov 765befa22f Remove empty nodes from tree because PG DSL expects that all leaf nodes are OSDs 2024-04-20 02:02:28 +03:00
Vitaliy Filippov 87b3ab94fe Do not disable require-atomic-updates and no-unused-vars 2024-04-20 02:02:13 +03:00
Vitaliy Filippov 2c0801f6e4 Configure ESLint and add it to CI 2024-04-16 02:39:31 +03:00
Vitaliy Filippov fd83fef1d9 Fix pool deletion 2024-04-16 02:20:26 +03:00
Vitaliy Filippov 8d1067971b Fix pg_effsize (and thus "used space") calculation in monitor 2024-04-16 02:20:18 +03:00
Vitaliy Filippov ae5af04fde Add noout flag for OSDs 2024-04-16 02:19:55 +03:00
Vitaliy Filippov 266d038b11 Fix 32-bit build warnings and one error again :-) 2024-04-11 22:49:33 +03:00
37 changed files with 236 additions and 108 deletions
+7
View File
@@ -64,6 +64,13 @@ jobs:
# leak sanitizer sometimes crashes
- run: cd /root/vitastor/build && ASAN_OPTIONS=detect_leaks=0 make -j16 test
npm_lint:
runs-on: ubuntu-latest
needs: build
container: ${{env.TEST_IMAGE}}:${{github.sha}}
steps:
- run: cd /root/vitastor/mon && npm run lint
test_add_osd:
runs-on: ubuntu-latest
needs: build
+1 -1
View File
@@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8.12)
project(vitastor)
set(VERSION "1.6.0")
set(VERSION "1.6.1")
add_subdirectory(src)
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION ?= v1.6.0
VERSION ?= v1.6.1
all: build push
+1 -1
View File
@@ -49,7 +49,7 @@ spec:
capabilities:
add: ["SYS_ADMIN"]
allowPrivilegeEscalation: true
image: vitalif/vitastor-csi:v1.6.0
image: vitalif/vitastor-csi:v1.6.1
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:v1.6.0
image: vitalif/vitastor-csi:v1.6.1
args:
- "--node=$(NODE_ID)"
- "--endpoint=$(CSI_ENDPOINT)"
+1 -1
View File
@@ -5,7 +5,7 @@ package vitastor
const (
vitastorCSIDriverName = "csi.vitastor.io"
vitastorCSIDriverVersion = "1.6.0"
vitastorCSIDriverVersion = "1.6.1"
)
// Config struct fills the parameters of request or user input
+1 -1
View File
@@ -1,4 +1,4 @@
vitastor (1.6.0-1) unstable; urgency=medium
vitastor (1.6.1-1) unstable; urgency=medium
* Bugfixes
+4 -4
View File
@@ -37,8 +37,8 @@ RUN set -e -x; \
mkdir -p /root/packages/vitastor-$REL; \
rm -rf /root/packages/vitastor-$REL/*; \
cd /root/packages/vitastor-$REL; \
cp -r /root/vitastor vitastor-1.6.0; \
cd vitastor-1.6.0; \
cp -r /root/vitastor vitastor-1.6.1; \
cd vitastor-1.6.1; \
ln -s /root/fio-build/fio-*/ ./fio; \
FIO=$(head -n1 fio/debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
ls /usr/include/linux/raw.h || cp ./debian/raw.h /usr/include/linux/raw.h; \
@@ -51,8 +51,8 @@ RUN set -e -x; \
rm -rf a b; \
echo "dep:fio=$FIO" > debian/fio_version; \
cd /root/packages/vitastor-$REL; \
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_1.6.0.orig.tar.xz vitastor-1.6.0; \
cd vitastor-1.6.0; \
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_1.6.1.orig.tar.xz vitastor-1.6.1; \
cd vitastor-1.6.1; \
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
DEBFULLNAME="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v "$V""$REL" "Rebuild for $REL"; \
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \
+13 -1
View File
@@ -86,7 +86,11 @@ Parent node reference is required for intermediate tree nodes.
Separate OSD settings are set in etc keys `/vitastor/config/osd/<number>`
in JSON format `{"<key>":<value>}`.
As of now, two settings are supported:
As of now, the following settings are supported:
- [reweight](#reweight)
- [tags](#tags)
- [noout](#noout)
## reweight
@@ -109,6 +113,14 @@ subsets and then use a specific subset for pool instead of all OSDs.
For example you can mark SSD OSDs with tag "ssd" and HDD OSDs with "hdd" and
such tags will work as device classes.
## noout
- Type: boolean
- Default: false
If set to true, [osd_out_time](monitor.en.md#osd_out_time) is ignored for this
OSD and it's never removed from data distribution by the monitor.
# Pool parameters
## name
+10 -1
View File
@@ -85,10 +85,11 @@
Настройки отдельных OSD задаются в ключах etcd `/vitastor/config/osd/<number>`
в JSON-формате `{"<key>":<value>}`.
На данный момент поддерживаются две настройки:
На данный момент поддерживаются следующие настройки:
- [reweight](#reweight)
- [tags](#tags)
- [noout](#noout)
## reweight
@@ -112,6 +113,14 @@
всех. Можно, например, пометить SSD OSD тегом "ssd", а HDD тегом "hdd", в
этом смысле теги работают аналогично классам устройств.
## noout
- Тип: булево (да/нет)
- Значение по умолчанию: false
Если установлено в true, то [osd_out_time](monitor.ru.md#osd_out_time) для этого
OSD игнорируется и OSD не удаляется из распределения данных монитором.
# Параметры
## name
+49
View File
@@ -0,0 +1,49 @@
module.exports = {
"env": {
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:node/recommended"
],
"parserOptions": {
"ecmaVersion": 2020
},
"plugins": [
],
"rules": {
"indent": [
"error",
4
],
"brace-style": [
"error",
"allman",
{ "allowSingleLine": true }
],
"linebreak-style": [
"error",
"unix"
],
"semi": [
"error",
"always"
],
"no-useless-escape": [
"off"
],
"no-control-regex": [
"off"
],
"no-empty": [
"off"
],
"no-process-exit": [
"off"
],
"node/shebang": [
"off"
]
}
};
-1
View File
@@ -97,7 +97,6 @@ function scale_pg_history(prev_pg_history, prev_pgs, new_pgs)
function scale_pg_count(prev_pgs, new_pg_count)
{
const old_pg_count = prev_pgs.length;
// Just for the lp_solve optimizer - pick a "previous" PG for each "new" one
if (prev_pgs.length < new_pg_count)
{
+1
View File
@@ -152,6 +152,7 @@ function parse_pg_dsl(text)
else if (rule[2] === '(')
{
rule[2] = [];
// eslint-disable-next-line no-constant-condition
while (true)
{
if (i > tokens.length-1)
+3 -3
View File
@@ -77,7 +77,7 @@ async function optimize_initial({ osd_weights, combinator, pg_count, pg_size = 3
{
if (osd !== NO_OSD)
{
let osd_pg_count = (osd_weights[osd]||0)/total_weight*pg_effsize*pg_count;
let osd_pg_count = osd_weights[osd]/total_weight*pg_effsize*pg_count;
lp += pg_per_osd[osd].join(' + ')+' <= '+osd_pg_count+';\n';
}
}
@@ -215,7 +215,7 @@ function calc_intersect_weights(old_pg_size, pg_size, pg_count, prev_weights, al
{
const intersect_count = ordered
? pg.reduce((a, osd, i) => a + (prev_hash[osd] == 1+i ? 1 : 0), 0)
: pg.reduce((a, osd, i) => a + (prev_hash[osd] ? 1 : 0), 0);
: pg.reduce((a, osd) => a + (prev_hash[osd] ? 1 : 0), 0);
if (max_int < intersect_count)
{
max_int = intersect_count;
@@ -299,7 +299,7 @@ async function optimize_change({ prev_pgs: prev_int_pgs, osd_weights, combinator
)).join(' + ');
const rm_osd_pg_count = (prev_pg_per_osd[osd]||[])
.reduce((a, [ old_pg_name, space ]) => (a + (all_pgs_hash[old_pg_name] ? space : 0)), 0);
const osd_pg_count = (osd_weights[osd]||0)*pg_effsize/total_weight*pg_count - rm_osd_pg_count;
const osd_pg_count = osd_weights[osd]*pg_effsize/total_weight*pg_count - rm_osd_pg_count;
lp += osd_sum + ' <= ' + osd_pg_count + ';\n';
}
}
+70 -33
View File
@@ -215,7 +215,7 @@ const etcd_tree = {
}, */
pools: {},
osd: {
/* <id>: { reweight?: 1, tags?: [ 'nvme', ... ] }, ... */
/* <id>: { reweight?: 1, tags?: [ 'nvme', ... ], noout?: true }, ... */
},
/* pgs: {
hash: string,
@@ -585,7 +585,7 @@ class Mon
now = Date.now();
}
tried[base] = now;
const ok = await new Promise((ok, no) =>
const ok = await new Promise(ok =>
{
const timer_id = setTimeout(() =>
{
@@ -747,6 +747,7 @@ class Mon
this.save_last_clean_running = true;
// last_clean_pgs is used to avoid extra data move when observing a series of changes in the cluster
const new_clean_pgs = { items: {} };
// eslint-disable-next-line indent
next_pool:
for (const pool_id in this.state.config.pools)
{
@@ -829,6 +830,7 @@ class Mon
async become_master()
{
const state = { ...this.get_mon_state(), id: ''+this.etcd_lease_id };
// eslint-disable-next-line no-constant-condition
while (1)
{
const res = await this.etcd_call('/kv/txn', {
@@ -873,32 +875,19 @@ class Mon
levels.osd = levels.osd || 101;
const tree = {};
let up_osds = {};
for (const node_id in this.state.config.node_placement||{})
{
const node_cfg = this.state.config.node_placement[node_id];
if (/^\d+$/.exec(node_id))
{
node_cfg.level = 'osd';
}
if (!node_id || !node_cfg.level || !levels[node_cfg.level])
{
// All nodes must have non-empty IDs and valid levels
continue;
}
tree[node_id] = { id: node_id, level: node_cfg.level, parent: node_cfg.parent, children: [] };
}
// This requires monitor system time to be in sync with OSD system times (at least to some extent)
const down_time = Date.now()/1000 - this.config.osd_out_time;
for (const osd_num of this.all_osds().sort((a, b) => a - b))
{
const stat = this.state.osd.stats[osd_num];
if (stat && stat.size && (this.state.osd.state[osd_num] || Number(stat.time) >= down_time))
const osd_cfg = this.state.config.osd[osd_num];
let reweight = osd_cfg == null ? 1 : Number(osd_cfg.reweight);
if (reweight < 0 || isNaN(reweight))
reweight = 1;
if (stat && stat.size && reweight && (this.state.osd.state[osd_num] || Number(stat.time) >= down_time ||
osd_cfg && osd_cfg.noout))
{
// Numeric IDs are reserved for OSDs
const osd_cfg = this.state.config.osd[osd_num];
let reweight = osd_cfg == null ? 1 : Number(osd_cfg.reweight);
if (reweight < 0 || isNaN(reweight))
reweight = 1;
if (this.state.osd.state[osd_num] && reweight > 0)
{
// React to down OSDs immediately
@@ -926,6 +915,29 @@ class Mon
}
}
}
for (const node_id in this.state.config.node_placement||{})
{
const node_cfg = this.state.config.node_placement[node_id];
if (/^\d+$/.exec(node_id))
{
node_cfg.level = 'osd';
}
if (!node_id || !node_cfg.level || !levels[node_cfg.level] ||
node_cfg.level === 'osd' && !tree[node_id])
{
// All nodes must have non-empty IDs and valid levels
// OSDs have to actually exist
continue;
}
tree[node_id] = tree[node_id] || {};
tree[node_id].id = node_id;
tree[node_id].level = node_cfg.level;
tree[node_id].parent = node_cfg.parent;
if (node_cfg.level !== 'osd')
{
tree[node_id].children = [];
}
}
return { up_osds, levels, osd_tree: tree };
}
@@ -955,6 +967,25 @@ class Mon
const parent = parent_level && parent_level < node_level ? node_cfg.parent : '';
tree[parent].children.push(tree[node_id]);
}
// Delete empty nodes
let deleted = 0;
do
{
deleted = 0;
for (const node_id in tree)
{
if (tree[node_id].level !== 'osd' && (!tree[node_id].children || !tree[node_id].children.length))
{
const parent = tree[node_id].parent;
if (parent)
{
tree[parent].children = tree[parent].children.filter(c => c != tree[node_id]);
}
deleted++;
delete tree[node_id];
}
}
} while (deleted > 0);
return tree;
}
@@ -991,7 +1022,7 @@ class Mon
const key = b64(this.etcd_prefix+'/osd/state/'+osd_num);
checks.push({ key, target: 'MOD', result: 'LESS', mod_revision: ''+this.etcd_watch_revision });
}
const res = await this.etcd_call('/kv/txn', {
await this.etcd_call('/kv/txn', {
compare: [
{ key: b64(this.etcd_prefix+'/mon/master'), target: 'LEASE', lease: ''+this.etcd_lease_id },
{ key: b64(this.etcd_prefix+'/config/pgs'), target: 'MOD', mod_revision: ''+this.etcd_watch_revision, result: 'LESS' },
@@ -1315,7 +1346,7 @@ class Mon
for (const k in rules)
{
if (!levels[k] || typeof rules[k] !== 'string' &&
(!rules[k] instanceof Array ||
(!(rules[k] instanceof Array) ||
rules[k].filter(s => typeof s !== 'string' && typeof s !== 'number').length > 0))
{
if (warn)
@@ -1429,7 +1460,15 @@ class Mon
}
console.log(`Pool ${pool_id} (${pool_cfg.name || 'unnamed'}):`);
LPOptimizer.print_change_stats(optimize_result);
const pg_effsize = Math.min(pool_cfg.pg_size, Object.keys(pool_tree).length);
let pg_effsize = pool_cfg.pg_size;
for (const pg of optimize_result.int_pgs)
{
const this_pg_size = pg.filter(osd => osd != LPOptimizer.NO_OSD).length;
if (this_pg_size && this_pg_size < pg_effsize)
{
pg_effsize = this_pg_size;
}
}
return {
pool_id,
pgs: optimize_result.int_pgs,
@@ -1511,11 +1550,14 @@ class Mon
{
continue;
}
const replicated = pool_cfg.scheme === 'replicated';
const aff_osds = this.get_affinity_osds(pool_cfg, up_osds, osd_tree);
this.reset_rng();
for (let pg_num = 1; pg_num <= pool_cfg.pg_count; pg_num++)
{
if (!this.state.config.pgs.items[pool_id])
{
continue;
}
const pg_cfg = this.state.config.pgs.items[pool_id][pg_num];
if (pg_cfg)
{
@@ -1553,10 +1595,6 @@ class Mon
async apply_pool_pgs(results, up_osds, osd_tree, tree_hash)
{
if (!results.length)
{
return true;
}
for (const pool_id in (this.state.config.pgs||{}).items||{})
{
// We should stop all PGs when deleting a pool or changing its PG count
@@ -1689,7 +1727,6 @@ class Mon
derive_osd_stats(st, prev, prev_diff)
{
const zero_stats = { op: { bps: 0n, iops: 0n, lat: 0n }, subop: { iops: 0n, lat: 0n }, recovery: { bps: 0n, iops: 0n } };
const diff = { op_stats: {}, subop_stats: {}, recovery_stats: {}, inode_stats: {} };
if (!st || !st.time || !prev || !prev.time || prev.time >= st.time)
{
@@ -1729,7 +1766,7 @@ class Mon
}
for (const pool_id in st.inode_stats||{})
{
const pool_diff = diff.inode_stats[pool_id] = {};
diff.inode_stats[pool_id] = {};
for (const inode_num in st.inode_stats[pool_id])
{
const inode_diff = diff.inode_stats[pool_id][inode_num] = {};
@@ -2147,7 +2184,7 @@ class Mon
_die(err, code)
{
// In fact we can just try to rejoin
console.error(new Error(err || 'Cluster connection failed'));
console.error(err instanceof Error ? err : new Error(err || 'Cluster connection failed'));
process.exit(code || 2);
}
@@ -2171,7 +2208,7 @@ class Mon
function POST(url, body, timeout)
{
return new Promise((ok, no) =>
return new Promise(ok =>
{
const body_text = Buffer.from(JSON.stringify(body));
let timer_id = timeout > 0 ? setTimeout(() =>
+11 -1
View File
@@ -1,6 +1,6 @@
{
"name": "vitastor-mon",
"version": "1.6.0",
"version": "1.6.1",
"description": "Vitastor SDS monitor service",
"main": "mon-main.js",
"scripts": {
@@ -11,5 +11,15 @@
"dependencies": {
"sprintf-js": "^1.1.2",
"ws": "^7.2.5"
},
"devDependencies": {
"eslint": "^8.0.0",
"eslint-plugin-node": "^11.1.0"
},
"engines": {
"node": ">=12.0.0"
},
"scripts": {
"lint": "eslint *.js"
}
}
+2 -2
View File
@@ -38,7 +38,7 @@ async function run()
const st = await fs.stat(options.device);
options.device_block_size = st.blksize;
if (st.isBlockDevice())
device_size = Number(await system("/sbin/blockdev --getsize64 "+options.device))
device_size = Number(await system("/sbin/blockdev --getsize64 "+options.device));
else
device_size = st.size;
}
@@ -91,7 +91,7 @@ async function run()
function system(cmd)
{
return new Promise((ok, no) => child_process.exec(cmd, { maxBuffer: 64*1024*1024 }, (err, stdout, stderr) => (err ? no(err.message) : ok(stdout))));
return new Promise((ok, no) => child_process.exec(cmd, { maxBuffer: 64*1024*1024 }, (err, stdout/*, stderr*/) => (err ? no(err.message) : ok(stdout))));
}
run().catch(err => { console.error(err); process.exit(1); });
+1 -1
View File
@@ -198,7 +198,6 @@ function all_combinations(osd_tree, pg_size, ordered, count)
function check_combinations(osd_tree, pgs)
{
const hosts = Object.keys(osd_tree).sort();
const host_per_osd = {};
for (const host in osd_tree)
{
@@ -235,6 +234,7 @@ function compat(params)
module.exports = {
flatten_tree,
all_combinations,
SimpleCombinator,
compat,
NO_OSD,
+1 -1
View File
@@ -20,7 +20,7 @@ const osd_tree = {
},
500: {
4: 3.58498,
// 8: 3.58589,
/*8: 3.58589,*/
9: 3.63869,
},
600: {
+1 -1
View File
@@ -50,7 +50,7 @@ from cinder.volume import configuration
from cinder.volume import driver
from cinder.volume import volume_utils
VERSION = '1.6.0'
VERSION = '1.6.1'
LOG = logging.getLogger(__name__)
+1 -1
View File
@@ -24,4 +24,4 @@ rm fio
mv fio-copy fio
FIO=`rpm -qi fio | perl -e 'while(<>) { /^Epoch[\s:]+(\S+)/ && print "$1:"; /^Version[\s:]+(\S+)/ && print $1; /^Release[\s:]+(\S+)/ && print "-$1"; }'`
perl -i -pe 's/(Requires:\s*fio)([^\n]+)?/$1 = '$FIO'/' $VITASTOR/rpm/vitastor-el$EL.spec
tar --transform 's#^#vitastor-1.6.0/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-1.6.0$(rpm --eval '%dist').tar.gz *
tar --transform 's#^#vitastor-1.6.1/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-1.6.1$(rpm --eval '%dist').tar.gz *
+1 -1
View File
@@ -36,7 +36,7 @@ ADD . /root/vitastor
RUN set -e; \
cd /root/vitastor/rpm; \
sh build-tarball.sh; \
cp /root/vitastor-1.6.0.el7.tar.gz ~/rpmbuild/SOURCES; \
cp /root/vitastor-1.6.1.el7.tar.gz ~/rpmbuild/SOURCES; \
cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \
cd ~/rpmbuild/SPECS/; \
rpmbuild -ba vitastor.spec; \
+3 -3
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 1.6.0
Version: 1.6.1
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-1.6.0.el7.tar.gz
Source0: vitastor-1.6.1.el7.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel
@@ -104,7 +104,7 @@ rm -rf $RPM_BUILD_ROOT
%make_install
. /opt/rh/rh-nodejs12/enable
cd mon
npm install
npm install --production
cd ..
mkdir -p %buildroot/usr/lib/vitastor
cp -r mon %buildroot/usr/lib/vitastor
+1 -1
View File
@@ -35,7 +35,7 @@ ADD . /root/vitastor
RUN set -e; \
cd /root/vitastor/rpm; \
sh build-tarball.sh; \
cp /root/vitastor-1.6.0.el8.tar.gz ~/rpmbuild/SOURCES; \
cp /root/vitastor-1.6.1.el8.tar.gz ~/rpmbuild/SOURCES; \
cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \
cd ~/rpmbuild/SPECS/; \
rpmbuild -ba vitastor.spec; \
+3 -3
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 1.6.0
Version: 1.6.1
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-1.6.0.el8.tar.gz
Source0: vitastor-1.6.1.el8.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel
@@ -101,7 +101,7 @@ Vitastor fio drivers for benchmarking.
rm -rf $RPM_BUILD_ROOT
%make_install
cd mon
npm install
npm install --production
cd ..
mkdir -p %buildroot/usr/lib/vitastor
cp -r mon %buildroot/usr/lib/vitastor
+1 -1
View File
@@ -18,7 +18,7 @@ ADD . /root/vitastor
RUN set -e; \
cd /root/vitastor/rpm; \
sh build-tarball.sh; \
cp /root/vitastor-1.6.0.el9.tar.gz ~/rpmbuild/SOURCES; \
cp /root/vitastor-1.6.1.el9.tar.gz ~/rpmbuild/SOURCES; \
cp vitastor-el9.spec ~/rpmbuild/SPECS/vitastor.spec; \
cd ~/rpmbuild/SPECS/; \
rpmbuild -ba vitastor.spec; \
+3 -3
View File
@@ -1,11 +1,11 @@
Name: vitastor
Version: 1.6.0
Version: 1.6.1
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-1.6.0.el9.tar.gz
Source0: vitastor-1.6.1.el9.tar.gz
BuildRequires: liburing-devel >= 0.6
BuildRequires: gperftools-devel
@@ -94,7 +94,7 @@ Vitastor fio drivers for benchmarking.
rm -rf $RPM_BUILD_ROOT
%cmake_install
cd mon
npm install
npm install --production
cd ..
mkdir -p %buildroot/usr/lib/vitastor
cp -r mon %buildroot/usr/lib/vitastor
+1 -1
View File
@@ -19,7 +19,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
add_definitions(-DVERSION="1.6.0")
add_definitions(-DVERSION="1.6.1")
add_definitions(-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 -I ${CMAKE_SOURCE_DIR}/src)
add_link_options(-fno-omit-frame-pointer)
if (${WITH_ASAN})
+8 -4
View File
@@ -14,7 +14,7 @@
struct pool_creator_t
{
cli_tool_t *parent;
json11::Json::object cfg;
json11::Json cfg;
bool force = false;
bool wait = false;
@@ -55,8 +55,12 @@ struct pool_creator_t
goto resume_8;
// Validate pool parameters
result.text = validate_pool_config(cfg, json11::Json(), parent->cli->st_cli.global_block_size,
parent->cli->st_cli.global_bitmap_granularity, force);
{
auto new_cfg = cfg.object_items();
result.text = validate_pool_config(new_cfg, json11::Json(), parent->cli->st_cli.global_block_size,
parent->cli->st_cli.global_bitmap_granularity, force);
cfg = new_cfg;
}
if (result.text != "")
{
result.err = EINVAL;
@@ -605,7 +609,7 @@ std::function<bool(cli_result_t &)> cli_tool_t::start_pool_create(json11::Json c
{
auto pool_creator = new pool_creator_t();
pool_creator->parent = this;
pool_creator->cfg = cfg.object_items();
pool_creator->cfg = cfg;
pool_creator->force = cfg["force"].bool_value();
pool_creator->wait = cfg["wait"].bool_value();
return [pool_creator](cli_result_t & result)
+1 -1
View File
@@ -205,7 +205,7 @@ resume_1:
{ "raw_to_usable", pool_stats[pool_cfg.id]["raw_to_usable"].number_value() },
{ "space_efficiency", pool_stats[pool_cfg.id]["space_efficiency"].number_value() },
{ "pg_real_size", pool_stats[pool_cfg.id]["pg_real_size"].uint64_value() },
{ "osd_count", pg_per_osd.size() },
{ "osd_count", (uint64_t)pg_per_osd.size() },
};
}
// Include full pool config
+2 -2
View File
@@ -452,7 +452,7 @@ void kv_cli_t::handle_cmd(const std::vector<std::string> & cmd, std::function<vo
auto name = cmd.size() > 1 ? cmd[1] : "";
uint64_t pool_id = 0;
inode_t inode_id = 0;
int scanned = sscanf(name.c_str(), "%lu %lu", &pool_id, &inode_id);
int scanned = sscanf(name.c_str(), "%ju %ju", &pool_id, &inode_id);
if (scanned < 2 || !pool_id || !inode_id)
{
inode_id = 0;
@@ -483,7 +483,7 @@ void kv_cli_t::handle_cmd(const std::vector<std::string> & cmd, std::function<vo
else
{
opened = true;
fprintf(interactive ? stdout : stderr, "Index opened. Current size: %lu bytes\n", db->get_size());
fprintf(interactive ? stdout : stderr, "Index opened. Current size: %ju bytes\n", db->get_size());
}
cb(res);
});
+26 -26
View File
@@ -250,14 +250,14 @@ int kv_block_t::parse(uint64_t offset, uint8_t *data, int size)
{
// empty block
if (offset != 0)
fprintf(stderr, "K/V: Block %lu is %s\n", offset, blk->magic == 0 ? "empty" : "cleared");
fprintf(stderr, "K/V: Block %ju is %s\n", offset, blk->magic == 0 ? "empty" : "cleared");
return -ENOTBLK;
}
if (blk->magic != KV_BLOCK_MAGIC || blk->block_size != size ||
!blk->type || blk->type > KV_EMPTY || blk->items > KV_BLOCK_MAX_ITEMS)
{
// invalid block
fprintf(stderr, "K/V: Invalid block %lu magic, size, type or item count\n", offset);
fprintf(stderr, "K/V: Invalid block %ju magic, size, type or item count\n", offset);
return -EILSEQ;
}
assert(!this->type);
@@ -266,13 +266,13 @@ int kv_block_t::parse(uint64_t offset, uint8_t *data, int size)
this->key_ge = read_string(data, size, &pos);
if (pos < 0)
{
fprintf(stderr, "K/V: Invalid block %lu left bound\n", offset);
fprintf(stderr, "K/V: Invalid block %ju left bound\n", offset);
return -EILSEQ;
}
this->key_lt = read_string(data, size, &pos);
if (pos < 0)
{
fprintf(stderr, "K/V: Invalid block %lu right bound\n", offset);
fprintf(stderr, "K/V: Invalid block %ju right bound\n", offset);
return -EILSEQ;
}
if (this->type == KV_INT_SPLIT || this->type == KV_LEAF_SPLIT)
@@ -280,12 +280,12 @@ int kv_block_t::parse(uint64_t offset, uint8_t *data, int size)
this->right_half = read_string(data, size, &pos);
if (pos < 0)
{
fprintf(stderr, "K/V: Invalid block %lu split bound\n", offset);
fprintf(stderr, "K/V: Invalid block %ju split bound\n", offset);
return -EILSEQ;
}
if (pos+8 > size)
{
fprintf(stderr, "K/V: Invalid block %lu split block ref\n", offset);
fprintf(stderr, "K/V: Invalid block %ju split block ref\n", offset);
return -EILSEQ;
}
this->right_half_block = *(uint64_t*)(data+pos);
@@ -296,13 +296,13 @@ int kv_block_t::parse(uint64_t offset, uint8_t *data, int size)
auto key = read_string(data, size, &pos);
if (pos < 0)
{
fprintf(stderr, "K/V: Invalid block %lu key %d\n", offset, i);
fprintf(stderr, "K/V: Invalid block %ju key %d\n", offset, i);
return -EILSEQ;
}
auto value = read_string(data, size, &pos);
if (pos < 0)
{
fprintf(stderr, "K/V: Invalid block %lu value %d\n", offset, i);
fprintf(stderr, "K/V: Invalid block %ju value %d\n", offset, i);
return -EILSEQ;
}
this->data[key] = value;
@@ -470,7 +470,7 @@ static void dump_str(const std::string & str)
void kv_block_t::dump(int base_level)
{
printf(
"{\n \"block\": %lu,\n \"level\": %d,\n \"type\": \"%s\",\n \"range\": [",
"{\n \"block\": %ju,\n \"level\": %d,\n \"type\": \"%s\",\n \"range\": [",
offset, base_level+level,
type < sizeof(block_type_names)/sizeof(block_type_names[0]) ? block_type_names[type] : "unknown"
);
@@ -482,7 +482,7 @@ void kv_block_t::dump(int base_level)
{
printf(" \"right_half\": { ");
dump_str(right_half);
printf(": %lu },\n", right_half_block);
printf(": %ju },\n", right_half_block);
}
printf(" \"data\": {\n");
for (auto & kv: data)
@@ -493,7 +493,7 @@ void kv_block_t::dump(int base_level)
if (type == KV_LEAF || type == KV_LEAF_SPLIT || kv.second.size() != 8)
dump_str(kv.second);
else
printf("%lu", *(uint64_t*)kv.second.c_str());
printf("%ju", *(uint64_t*)kv.second.c_str());
printf(",\n");
}
printf(" }\n}\n");
@@ -1037,7 +1037,7 @@ void kv_op_t::get()
{
if (cur_block != 0)
{
fprintf(stderr, "K/V: Hit empty block %lu while searching\n", cur_block);
fprintf(stderr, "K/V: Hit empty block %ju while searching\n", cur_block);
finish(-EILSEQ);
}
else
@@ -1095,7 +1095,7 @@ int kv_op_t::handle_block(int res, int refresh, bool stop_on_split)
bool fatal = !this->updating_on_path && this->retry > 0;
if (fatal || db->log_level > 0)
{
fprintf(stderr, "K/V: %sgot unrelated block %lu: key=%s range=[%s, %s) from=[%s, %s)\n",
fprintf(stderr, "K/V: %sgot unrelated block %ju: key=%s range=[%s, %s) from=[%s, %s)\n",
fatal ? "Error: " : "Warning: read/update collision: ",
cur_block, key.c_str(), blk->key_ge.c_str(), blk->key_lt.c_str(), prev_key_ge.c_str(), prev_key_lt.c_str());
if (fatal)
@@ -1160,7 +1160,7 @@ int kv_op_t::handle_block(int res, int refresh, bool stop_on_split)
auto child_it = blk->data.upper_bound(key);
if (child_it == blk->data.begin())
{
fprintf(stderr, "K/V: Internal block %lu misses boundary for %s\n", cur_block, key.c_str());
fprintf(stderr, "K/V: Internal block %ju misses boundary for %s\n", cur_block, key.c_str());
return -EILSEQ;
}
auto m = child_it == blk->data.end()
@@ -1169,7 +1169,7 @@ int kv_op_t::handle_block(int res, int refresh, bool stop_on_split)
child_it--;
if (child_it->second.size() != sizeof(uint64_t))
{
fprintf(stderr, "K/V: Internal block %lu reference is not 8 byte long\n", cur_block);
fprintf(stderr, "K/V: Internal block %ju reference is not 8 byte long\n", cur_block);
blk->dump(db->base_block_level);
return -EILSEQ;
}
@@ -1246,7 +1246,7 @@ static void write_block(kv_db_t *db, kv_block_t *blk, std::function<void(int)> c
blk->dump(db->base_block_level);
uint64_t old_size = blk->data_size;
blk->set_data_size();
fprintf(stderr, "K/V: block %lu (ptr=%lx) grew too large: tracked %lu, but real is %u bytes\n",
fprintf(stderr, "K/V: block %ju (ptr=%jx) grew too large: tracked %ju, but real is %u bytes\n",
blk->offset, (uint64_t)blk, old_size, blk->data_size);
abort();
return;
@@ -1479,7 +1479,7 @@ void kv_op_t::update_find()
else if (cur_block == 0)
finish(-ENOENT);
else
fprintf(stderr, "K/V: Hit empty block %lu while searching\n", cur_block);
fprintf(stderr, "K/V: Hit empty block %ju while searching\n", cur_block);
}
else if (res == -ECHILD)
{
@@ -1506,7 +1506,7 @@ void kv_op_t::create_root()
// if a referenced non-root block is empty, we just return an error.
if (cur_block != 0 || db->next_free != 0)
{
fprintf(stderr, "K/V: create_root called with non-empty DB (cur_block=%lu)\n", cur_block);
fprintf(stderr, "K/V: create_root called with non-empty DB (cur_block=%ju)\n", cur_block);
finish(-EILSEQ);
return;
}
@@ -1551,7 +1551,7 @@ void kv_op_t::resume_split()
if (path.size() == 1)
{
// It shouldn't be the root block because we don't split it via INT_SPLIT/LEAF_SPLIT
fprintf(stderr, "K/V: resume_split at root item (cur_block=%lu)\n", cur_block);
fprintf(stderr, "K/V: resume_split at root item (cur_block=%ju)\n", cur_block);
finish(-EILSEQ);
return;
}
@@ -1638,7 +1638,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
{
blk->dump(0);
// Should not happen - we should have resumed the split
fprintf(stderr, "K/V: attempt to write into block %lu instead of resuming the split (got here from %s..%s)\n",
fprintf(stderr, "K/V: attempt to write into block %ju instead of resuming the split (got here from %s..%s)\n",
blk->offset, prev_key_ge.c_str(), prev_key_lt.c_str());
abort();
}
@@ -1650,7 +1650,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
// No need to split the block => just modify and write it
if ((blk->type == KV_LEAF_SPLIT || blk->type == KV_INT_SPLIT) && key >= blk->right_half)
{
fprintf(stderr, "K/V: attempt to modify %s in unrelated split block %lu [%s..%s..%s)\n",
fprintf(stderr, "K/V: attempt to modify %s in unrelated split block %ju [%s..%s..%s)\n",
key.c_str(), blk->offset, blk->key_ge.c_str(), blk->right_half.c_str(), blk->key_lt.c_str());
blk->dump(db->base_block_level);
abort();
@@ -1753,11 +1753,11 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
clear_block(db, left_blk, 0, [=, left_offset = left_blk->offset](int res)
{
if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", left_offset, strerror(-res), res);
fprintf(stderr, "Failed to clear unreferenced block %ju: %s (code %d)\n", left_offset, strerror(-res), res);
clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res)
{
if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res);
fprintf(stderr, "Failed to clear unreferenced block %ju: %s (code %d)\n", right_offset, strerror(-res), res);
// CAS failure - zero garbage left_blk and right_blk and retry from the beginning
if (write_res == -EINTR)
update();
@@ -1784,7 +1784,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
if (path_pos == 0)
{
// Block number zero should always be the root block
fprintf(stderr, "K/V: root block is not 0, but %lu\n", cur_block);
fprintf(stderr, "K/V: root block is not 0, but %ju\n", cur_block);
cb(-EILSEQ);
return;
}
@@ -1809,7 +1809,7 @@ void kv_op_t::update_block(int path_pos, bool is_delete, const std::string & key
clear_block(db, right_blk, 0, [=, right_offset = right_blk->offset](int res)
{
if (res < 0)
fprintf(stderr, "Failed to clear unreferenced block %lu: %s (code %d)\n", right_offset, strerror(-res), res);
fprintf(stderr, "Failed to clear unreferenced block %ju: %s (code %d)\n", right_offset, strerror(-res), res);
// CAS failure - zero garbage right_blk and retry from the beginning
if (write_res == -EINTR)
update();
@@ -1860,7 +1860,7 @@ void kv_op_t::next_handle_block(int res, int refresh)
finish(-ENOENT);
else
{
fprintf(stderr, "K/V: Hit empty block %lu while searching\n", cur_block);
fprintf(stderr, "K/V: Hit empty block %ju while searching\n", cur_block);
finish(-EILSEQ);
}
}
+2 -2
View File
@@ -632,7 +632,7 @@ void kv_test_t::print_stats(kv_test_stat_t & prev_stat, timespec & prev_stat_tim
char buf[128] = { 0 };
for (int i = 0; i < sizeof(lats)/sizeof(lats[0]); i++)
{
snprintf(buf, sizeof(buf)-1, "%.1f %s/s (%lu us)", (lats[i]->count-prev[i]->count)*1000000.0/usec,
snprintf(buf, sizeof(buf)-1, "%.1f %s/s (%ju us)", (lats[i]->count-prev[i]->count)*1000000.0/usec,
lats[i]->name, (lats[i]->usec-prev[i]->usec)/(lats[i]->count-prev[i]->count > 0 ? lats[i]->count-prev[i]->count : 1));
int k;
for (k = strlen(buf); k < strlen(lats[i]->name)+21; k++)
@@ -652,7 +652,7 @@ void kv_test_t::print_stats(kv_test_stat_t & prev_stat, timespec & prev_stat_tim
if (lats[i]->count > prev[i]->count)
{
printf(
",\"%s\":{\"avg\":{\"iops\":%.1f,\"usec\":%lu},\"total\":{\"count\":%lu,\"usec\":%lu}}",
",\"%s\":{\"avg\":{\"iops\":%.1f,\"usec\":%ju},\"total\":{\"count\":%ju,\"usec\":%ju}}",
lats[i]->name, (lats[i]->count-prev[i]->count)*1000000.0/usec,
(lats[i]->usec-prev[i]->usec)/(lats[i]->count-prev[i]->count),
lats[i]->count, lats[i]->usec
+1 -1
View File
@@ -497,7 +497,7 @@ static void extend_inode(nfs_client_t *self, uint64_t inode, uint64_t new_size)
auto & ext = self->parent->blockfs->extends[inode];
if (r.err)
{
fprintf(stderr, "Error extending inode %lu to %lu bytes: %s\n", inode, new_size, r.text.c_str());
fprintf(stderr, "Error extending inode %ju to %ju bytes: %s\n", inode, new_size, r.text.c_str());
}
if (r.err == EAGAIN || ext.next_extend > ext.cur_extend)
{
+1 -1
View File
@@ -258,7 +258,7 @@ resume_3:
auto name = kv_direntry_filename(st->cur_key);
if (st->self->parent->trace)
{
fprintf(stderr, "[%d] READDIR %ju %lu %s\n",
fprintf(stderr, "[%d] READDIR %ju %ju %s\n",
st->self->nfs_fd, st->dir_ino, st->offset, name.c_str());
}
auto fh = kv_fh(ino);
+1 -1
View File
@@ -608,7 +608,7 @@ static void nfs_kv_extend_inode(nfs_kv_write_state *st, int state, int base_stat
auto ientry = json11::Json::parse(old_value, err).object_items();
if (err != "")
{
fprintf(stderr, "Invalid JSON in inode %lu = %s: %s\n", st->ino, old_value.c_str(), err.c_str());
fprintf(stderr, "Invalid JSON in inode %ju = %s: %s\n", st->ino, old_value.c_str(), err.c_str());
st->res2 = -EINVAL;
return false;
}
+1 -1
View File
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: Vitastor
Description: Vitastor client library
Version: 1.6.0
Version: 1.6.1
Libs: -L${libdir} -lvitastor_client
Cflags: -I${includedir}