Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
926be372fd | |||
6222779b52 | |||
a4186e20aa | |||
c74a424930 | |||
32f2c4dd27 | |||
3ad16b9a1a | |||
1c2df841c2 | |||
aa5dacc7a9 | |||
affe8fc270 | |||
4fdc49bdc7 | |||
86b4682975 | |||
bdd48e4cf1 | |||
af8c3411cd | |||
9c405009f3 | |||
f9fbea25a4 | |||
2c9a10d081 | |||
150968070f | |||
cdfc74665b | |||
3f60fecd7c |
@@ -71,7 +71,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run test
|
- name: Run test
|
||||||
id: test
|
id: test
|
||||||
timeout-minutes: 3
|
timeout-minutes: 10
|
||||||
run: /root/vitastor/tests/test_add_osd.sh
|
run: /root/vitastor/tests/test_add_osd.sh
|
||||||
- name: Print logs
|
- name: Print logs
|
||||||
if: always() && steps.test.outcome == 'failure'
|
if: always() && steps.test.outcome == 'failure'
|
||||||
@@ -323,7 +323,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run test
|
- name: Run test
|
||||||
id: test
|
id: test
|
||||||
timeout-minutes: 3
|
timeout-minutes: 10
|
||||||
run: /root/vitastor/tests/test_rebalance_verify.sh
|
run: /root/vitastor/tests/test_rebalance_verify.sh
|
||||||
- name: Print logs
|
- name: Print logs
|
||||||
if: always() && steps.test.outcome == 'failure'
|
if: always() && steps.test.outcome == 'failure'
|
||||||
@@ -341,7 +341,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run test
|
- name: Run test
|
||||||
id: test
|
id: test
|
||||||
timeout-minutes: 3
|
timeout-minutes: 10
|
||||||
run: IMMEDIATE_COMMIT=1 /root/vitastor/tests/test_rebalance_verify.sh
|
run: IMMEDIATE_COMMIT=1 /root/vitastor/tests/test_rebalance_verify.sh
|
||||||
- name: Print logs
|
- name: Print logs
|
||||||
if: always() && steps.test.outcome == 'failure'
|
if: always() && steps.test.outcome == 'failure'
|
||||||
@@ -359,7 +359,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run test
|
- name: Run test
|
||||||
id: test
|
id: test
|
||||||
timeout-minutes: 3
|
timeout-minutes: 10
|
||||||
run: SCHEME=ec /root/vitastor/tests/test_rebalance_verify.sh
|
run: SCHEME=ec /root/vitastor/tests/test_rebalance_verify.sh
|
||||||
- name: Print logs
|
- name: Print logs
|
||||||
if: always() && steps.test.outcome == 'failure'
|
if: always() && steps.test.outcome == 'failure'
|
||||||
@@ -377,7 +377,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Run test
|
- name: Run test
|
||||||
id: test
|
id: test
|
||||||
timeout-minutes: 3
|
timeout-minutes: 10
|
||||||
run: SCHEME=ec IMMEDIATE_COMMIT=1 /root/vitastor/tests/test_rebalance_verify.sh
|
run: SCHEME=ec IMMEDIATE_COMMIT=1 /root/vitastor/tests/test_rebalance_verify.sh
|
||||||
- name: Print logs
|
- name: Print logs
|
||||||
if: always() && steps.test.outcome == 'failure'
|
if: always() && steps.test.outcome == 'failure'
|
||||||
|
@@ -9,7 +9,8 @@ for my $line (<>)
|
|||||||
chomp $line;
|
chomp $line;
|
||||||
my $test_name = $1;
|
my $test_name = $1;
|
||||||
my $timeout = 3;
|
my $timeout = 3;
|
||||||
if ($test_name eq 'test_etcd_fail' || $test_name eq 'test_heal' || $test_name eq 'test_interrupted_rebalance')
|
if ($test_name eq 'test_etcd_fail' || $test_name eq 'test_heal' || $test_name eq 'test_add_osd' ||
|
||||||
|
$test_name eq 'test_interrupted_rebalance' || $test_name eq 'test_rebalance_verify')
|
||||||
{
|
{
|
||||||
$timeout = 10;
|
$timeout = 10;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 2.8.12)
|
|||||||
|
|
||||||
project(vitastor)
|
project(vitastor)
|
||||||
|
|
||||||
set(VERSION "0.9.0")
|
set(VERSION "0.9.2")
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
VERSION ?= v0.9.0
|
VERSION ?= v0.9.2
|
||||||
|
|
||||||
all: build push
|
all: build push
|
||||||
|
|
||||||
|
@@ -49,7 +49,7 @@ spec:
|
|||||||
capabilities:
|
capabilities:
|
||||||
add: ["SYS_ADMIN"]
|
add: ["SYS_ADMIN"]
|
||||||
allowPrivilegeEscalation: true
|
allowPrivilegeEscalation: true
|
||||||
image: vitalif/vitastor-csi:v0.9.0
|
image: vitalif/vitastor-csi:v0.9.2
|
||||||
args:
|
args:
|
||||||
- "--node=$(NODE_ID)"
|
- "--node=$(NODE_ID)"
|
||||||
- "--endpoint=$(CSI_ENDPOINT)"
|
- "--endpoint=$(CSI_ENDPOINT)"
|
||||||
|
@@ -116,7 +116,7 @@ spec:
|
|||||||
privileged: true
|
privileged: true
|
||||||
capabilities:
|
capabilities:
|
||||||
add: ["SYS_ADMIN"]
|
add: ["SYS_ADMIN"]
|
||||||
image: vitalif/vitastor-csi:v0.9.0
|
image: vitalif/vitastor-csi:v0.9.2
|
||||||
args:
|
args:
|
||||||
- "--node=$(NODE_ID)"
|
- "--node=$(NODE_ID)"
|
||||||
- "--endpoint=$(CSI_ENDPOINT)"
|
- "--endpoint=$(CSI_ENDPOINT)"
|
||||||
|
@@ -5,7 +5,7 @@ package vitastor
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
vitastorCSIDriverName = "csi.vitastor.io"
|
vitastorCSIDriverName = "csi.vitastor.io"
|
||||||
vitastorCSIDriverVersion = "0.9.0"
|
vitastorCSIDriverVersion = "0.9.2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config struct fills the parameters of request or user input
|
// Config struct fills the parameters of request or user input
|
||||||
|
7
debian/build-vitastor-bookworm.sh
vendored
Executable file
7
debian/build-vitastor-bookworm.sh
vendored
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cat < vitastor.Dockerfile > ../Dockerfile
|
||||||
|
cd ..
|
||||||
|
mkdir -p packages
|
||||||
|
sudo podman build --build-arg REL=bookworm -v `pwd`/packages:/root/packages -f Dockerfile .
|
||||||
|
rm Dockerfile
|
4
debian/changelog
vendored
4
debian/changelog
vendored
@@ -1,10 +1,10 @@
|
|||||||
vitastor (0.9.0-1) unstable; urgency=medium
|
vitastor (0.9.2-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Bugfixes
|
* Bugfixes
|
||||||
|
|
||||||
-- Vitaliy Filippov <vitalif@yourcmc.ru> Fri, 03 Jun 2022 02:09:44 +0300
|
-- Vitaliy Filippov <vitalif@yourcmc.ru> Fri, 03 Jun 2022 02:09:44 +0300
|
||||||
|
|
||||||
vitastor (0.9.0-1) unstable; urgency=medium
|
vitastor (0.9.2-1) unstable; urgency=medium
|
||||||
|
|
||||||
* Implement NFS proxy
|
* Implement NFS proxy
|
||||||
* Add documentation
|
* Add documentation
|
||||||
|
26
debian/patched-qemu.Dockerfile
vendored
26
debian/patched-qemu.Dockerfile
vendored
@@ -1,4 +1,4 @@
|
|||||||
# Build patched QEMU for Debian Buster or Bullseye/Sid inside a container
|
# Build patched QEMU for Debian inside a container
|
||||||
# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/patched-qemu.Dockerfile .
|
# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/patched-qemu.Dockerfile .
|
||||||
|
|
||||||
ARG REL=
|
ARG REL=
|
||||||
@@ -15,17 +15,19 @@ RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" ]; then \
|
|||||||
echo 'Pin-Priority: 500' >> /etc/apt/preferences; \
|
echo 'Pin-Priority: 500' >> /etc/apt/preferences; \
|
||||||
fi; \
|
fi; \
|
||||||
grep '^deb ' /etc/apt/sources.list | perl -pe 's/^deb/deb-src/' >> /etc/apt/sources.list; \
|
grep '^deb ' /etc/apt/sources.list | perl -pe 's/^deb/deb-src/' >> /etc/apt/sources.list; \
|
||||||
|
perl -i -pe 's/Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/debian.sources || true; \
|
||||||
echo 'APT::Install-Recommends false;' >> /etc/apt/apt.conf; \
|
echo 'APT::Install-Recommends false;' >> /etc/apt/apt.conf; \
|
||||||
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
||||||
|
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get -y install qemu fio liburing1 liburing-dev libgoogle-perftools-dev devscripts
|
RUN apt-get -y install qemu fio liburing-dev libgoogle-perftools-dev devscripts
|
||||||
RUN apt-get -y build-dep qemu
|
RUN apt-get -y build-dep qemu
|
||||||
# To build a custom version
|
# To build a custom version
|
||||||
#RUN cp /root/packages/qemu-orig/* /root
|
#RUN cp /root/packages/qemu-orig/* /root
|
||||||
RUN apt-get --download-only source qemu
|
RUN apt-get --download-only source qemu
|
||||||
|
|
||||||
ADD patches/qemu-5.0-vitastor.patch patches/qemu-5.1-vitastor.patch patches/qemu-6.1-vitastor.patch src/qemu_driver.c /root/vitastor/patches/
|
ADD patches /root/vitastor/patches
|
||||||
|
ADD src/qemu_driver.c /root/vitastor/src/qemu_driver.c
|
||||||
RUN set -e; \
|
RUN set -e; \
|
||||||
apt-get install -y wget; \
|
apt-get install -y wget; \
|
||||||
wget -q -O /etc/apt/trusted.gpg.d/vitastor.gpg https://vitastor.io/debian/pubkey.gpg; \
|
wget -q -O /etc/apt/trusted.gpg.d/vitastor.gpg https://vitastor.io/debian/pubkey.gpg; \
|
||||||
@@ -37,23 +39,13 @@ RUN set -e; \
|
|||||||
rm -rf /root/packages/qemu-$REL/*; \
|
rm -rf /root/packages/qemu-$REL/*; \
|
||||||
cd /root/packages/qemu-$REL; \
|
cd /root/packages/qemu-$REL; \
|
||||||
dpkg-source -x /root/qemu*.dsc; \
|
dpkg-source -x /root/qemu*.dsc; \
|
||||||
if ls -d /root/packages/qemu-$REL/qemu-5.0*; then \
|
QEMU_VER=$(ls -d qemu*/ | perl -pe 's!^.*(\d+\.\d+).*!$1!'); \
|
||||||
D=$(ls -d /root/packages/qemu-$REL/qemu-5.0*); \
|
cp /root/vitastor/patches/qemu-$QEMU_VER-vitastor.patch qemu-*/debian/patches; \
|
||||||
cp /root/vitastor/patches/qemu-5.0-vitastor.patch $D/debian/patches; \
|
echo qemu-$QEMU_VER-vitastor.patch >> qemu-*/debian/patches/series; \
|
||||||
echo qemu-5.0-vitastor.patch >> $D/debian/patches/series; \
|
|
||||||
elif ls /root/packages/qemu-$REL/qemu-6.1*; then \
|
|
||||||
D=$(ls -d /root/packages/qemu-$REL/qemu-6.1*); \
|
|
||||||
cp /root/vitastor/patches/qemu-6.1-vitastor.patch $D/debian/patches; \
|
|
||||||
echo qemu-6.1-vitastor.patch >> $D/debian/patches/series; \
|
|
||||||
else \
|
|
||||||
cp /root/vitastor/patches/qemu-5.1-vitastor.patch /root/packages/qemu-$REL/qemu-*/debian/patches; \
|
|
||||||
P=`ls -d /root/packages/qemu-$REL/qemu-*/debian/patches`; \
|
|
||||||
echo qemu-5.1-vitastor.patch >> $P/series; \
|
|
||||||
fi; \
|
|
||||||
cd /root/packages/qemu-$REL/qemu-*/; \
|
cd /root/packages/qemu-$REL/qemu-*/; \
|
||||||
quilt push -a; \
|
quilt push -a; \
|
||||||
quilt add block/vitastor.c; \
|
quilt add block/vitastor.c; \
|
||||||
cp /root/vitastor/patches/qemu_driver.c block/vitastor.c; \
|
cp /root/vitastor/src/qemu_driver.c block/vitastor.c; \
|
||||||
quilt refresh; \
|
quilt refresh; \
|
||||||
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)(~bpo[\d\+]*)?\).*$/$1/')+vitastor1; \
|
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)(~bpo[\d\+]*)?\).*$/$1/')+vitastor1; \
|
||||||
DEBEMAIL="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v $V 'Plug Vitastor block driver'; \
|
DEBEMAIL="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v $V 'Plug Vitastor block driver'; \
|
||||||
|
13
debian/vitastor.Dockerfile
vendored
13
debian/vitastor.Dockerfile
vendored
@@ -1,4 +1,4 @@
|
|||||||
# Build Vitastor packages for Debian Buster or Bullseye/Sid inside a container
|
# Build Vitastor packages for Debian inside a container
|
||||||
# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/vitastor.Dockerfile .
|
# cd ..; podman build --build-arg REL=bullseye -v `pwd`/packages:/root/packages -f debian/vitastor.Dockerfile .
|
||||||
|
|
||||||
ARG REL=
|
ARG REL=
|
||||||
@@ -15,11 +15,12 @@ RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" ]; then \
|
|||||||
echo 'Pin-Priority: 500' >> /etc/apt/preferences; \
|
echo 'Pin-Priority: 500' >> /etc/apt/preferences; \
|
||||||
fi; \
|
fi; \
|
||||||
grep '^deb ' /etc/apt/sources.list | perl -pe 's/^deb/deb-src/' >> /etc/apt/sources.list; \
|
grep '^deb ' /etc/apt/sources.list | perl -pe 's/^deb/deb-src/' >> /etc/apt/sources.list; \
|
||||||
|
perl -i -pe 's/Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/debian.sources || true; \
|
||||||
echo 'APT::Install-Recommends false;' >> /etc/apt/apt.conf; \
|
echo 'APT::Install-Recommends false;' >> /etc/apt/apt.conf; \
|
||||||
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
echo 'APT::Install-Suggests false;' >> /etc/apt/apt.conf
|
||||||
|
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get -y install fio liburing1 liburing-dev libgoogle-perftools-dev devscripts
|
RUN apt-get -y install fio liburing-dev libgoogle-perftools-dev devscripts
|
||||||
RUN apt-get -y build-dep fio
|
RUN apt-get -y build-dep fio
|
||||||
RUN apt-get --download-only source fio
|
RUN apt-get --download-only source fio
|
||||||
RUN apt-get update && apt-get -y install libjerasure-dev cmake libibverbs-dev libisal-dev
|
RUN apt-get update && apt-get -y install libjerasure-dev cmake libibverbs-dev libisal-dev
|
||||||
@@ -34,8 +35,8 @@ RUN set -e -x; \
|
|||||||
mkdir -p /root/packages/vitastor-$REL; \
|
mkdir -p /root/packages/vitastor-$REL; \
|
||||||
rm -rf /root/packages/vitastor-$REL/*; \
|
rm -rf /root/packages/vitastor-$REL/*; \
|
||||||
cd /root/packages/vitastor-$REL; \
|
cd /root/packages/vitastor-$REL; \
|
||||||
cp -r /root/vitastor vitastor-0.9.0; \
|
cp -r /root/vitastor vitastor-0.9.2; \
|
||||||
cd vitastor-0.9.0; \
|
cd vitastor-0.9.2; \
|
||||||
ln -s /root/fio-build/fio-*/ ./fio; \
|
ln -s /root/fio-build/fio-*/ ./fio; \
|
||||||
FIO=$(head -n1 fio/debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$1/'); \
|
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; \
|
ls /usr/include/linux/raw.h || cp ./debian/raw.h /usr/include/linux/raw.h; \
|
||||||
@@ -48,8 +49,8 @@ RUN set -e -x; \
|
|||||||
rm -rf a b; \
|
rm -rf a b; \
|
||||||
echo "dep:fio=$FIO" > debian/fio_version; \
|
echo "dep:fio=$FIO" > debian/fio_version; \
|
||||||
cd /root/packages/vitastor-$REL; \
|
cd /root/packages/vitastor-$REL; \
|
||||||
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.9.0.orig.tar.xz vitastor-0.9.0; \
|
tar --sort=name --mtime='2020-01-01' --owner=0 --group=0 --exclude=debian -cJf vitastor_0.9.2.orig.tar.xz vitastor-0.9.2; \
|
||||||
cd vitastor-0.9.0; \
|
cd vitastor-0.9.2; \
|
||||||
V=$(head -n1 debian/changelog | perl -pe 's/^.*\((.*?)\).*$/$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"; \
|
DEBFULLNAME="Vitaliy Filippov <vitalif@yourcmc.ru>" dch -D $REL -v "$V""$REL" "Rebuild for $REL"; \
|
||||||
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \
|
DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage --jobs=auto -sa; \
|
||||||
|
@@ -430,7 +430,7 @@ Flusher - это микро-поток (корутина), которая коп
|
|||||||
Находить и автоматически восстанавливать "лучшие версии" объектов с
|
Находить и автоматически восстанавливать "лучшие версии" объектов с
|
||||||
несовпадающими копиями/частями. При использовании репликации "лучшая"
|
несовпадающими копиями/частями. При использовании репликации "лучшая"
|
||||||
версия - версия, доступная в большем числе экземпляров, чем другие. При
|
версия - версия, доступная в большем числе экземпляров, чем другие. При
|
||||||
использовании кодов коррекции ошибок "лучшая" весрия - это подмножество
|
использовании кодов коррекции ошибок "лучшая" версия - это подмножество
|
||||||
частей данных и чётности, полностью соответствующих друг другу.
|
частей данных и чётности, полностью соответствующих друг другу.
|
||||||
|
|
||||||
Гипотетическая ситуация, в которой вы можете захотеть отключить этот
|
Гипотетическая ситуация, в которой вы можете захотеть отключить этот
|
||||||
|
@@ -474,7 +474,7 @@
|
|||||||
Находить и автоматически восстанавливать "лучшие версии" объектов с
|
Находить и автоматически восстанавливать "лучшие версии" объектов с
|
||||||
несовпадающими копиями/частями. При использовании репликации "лучшая"
|
несовпадающими копиями/частями. При использовании репликации "лучшая"
|
||||||
версия - версия, доступная в большем числе экземпляров, чем другие. При
|
версия - версия, доступная в большем числе экземпляров, чем другие. При
|
||||||
использовании кодов коррекции ошибок "лучшая" весрия - это подмножество
|
использовании кодов коррекции ошибок "лучшая" версия - это подмножество
|
||||||
частей данных и чётности, полностью соответствующих друг другу.
|
частей данных и чётности, полностью соответствующих друг другу.
|
||||||
|
|
||||||
Гипотетическая ситуация, в которой вы можете захотеть отключить этот
|
Гипотетическая ситуация, в которой вы можете захотеть отключить этот
|
||||||
|
121
mon/mon.js
121
mon/mon.js
@@ -391,6 +391,7 @@ class Mon
|
|||||||
this.etcd_start_timeout = (config.etcd_start_timeout || 5) * 1000;
|
this.etcd_start_timeout = (config.etcd_start_timeout || 5) * 1000;
|
||||||
this.state = JSON.parse(JSON.stringify(this.constructor.etcd_tree));
|
this.state = JSON.parse(JSON.stringify(this.constructor.etcd_tree));
|
||||||
this.signals_set = false;
|
this.signals_set = false;
|
||||||
|
this.stat_time = Date.now();
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.ws_alive = false;
|
this.ws_alive = false;
|
||||||
this.ws_keepalive_timer = null;
|
this.ws_keepalive_timer = null;
|
||||||
@@ -1410,65 +1411,75 @@ class Mon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
derive_osd_stats(st, prev)
|
||||||
|
{
|
||||||
|
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: {} };
|
||||||
|
if (!st || !st.time || prev && (prev.time || this.stat_time/1000) >= st.time)
|
||||||
|
{
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
const timediff = BigInt(st.time*1000 - (prev && prev.time*1000 || this.stat_time));
|
||||||
|
for (const op in st.op_stats||{})
|
||||||
|
{
|
||||||
|
const pr = prev && prev.op_stats && prev.op_stats[op];
|
||||||
|
let c = st.op_stats[op];
|
||||||
|
c = { bytes: BigInt(c.bytes||0), usec: BigInt(c.usec||0), count: BigInt(c.count||0) };
|
||||||
|
const b = c.bytes - BigInt(pr && pr.bytes||0);
|
||||||
|
const us = c.usec - BigInt(pr && pr.usec||0);
|
||||||
|
const n = c.count - BigInt(pr && pr.count||0);
|
||||||
|
if (n > 0)
|
||||||
|
diff.op_stats[op] = { ...c, bps: b*1000n/timediff, iops: n*1000n/timediff, lat: us/n };
|
||||||
|
}
|
||||||
|
for (const op in st.subop_stats||{})
|
||||||
|
{
|
||||||
|
const pr = prev && prev.subop_stats && prev.subop_stats[op];
|
||||||
|
let c = st.subop_stats[op];
|
||||||
|
c = { usec: BigInt(c.usec||0), count: BigInt(c.count||0) };
|
||||||
|
const us = c.usec - BigInt(pr && pr.usec||0);
|
||||||
|
const n = c.count - BigInt(pr && pr.count||0);
|
||||||
|
if (n > 0)
|
||||||
|
diff.subop_stats[op] = { ...c, iops: n*1000n/timediff, lat: us/n };
|
||||||
|
}
|
||||||
|
for (const op in st.recovery_stats||{})
|
||||||
|
{
|
||||||
|
const pr = prev && prev.recovery_stats && prev.recovery_stats[op];
|
||||||
|
let c = st.recovery_stats[op];
|
||||||
|
c = { bytes: BigInt(c.bytes||0), count: BigInt(c.count||0) };
|
||||||
|
const b = c.bytes - BigInt(pr && pr.bytes||0);
|
||||||
|
const n = c.count - BigInt(pr && pr.count||0);
|
||||||
|
if (n > 0)
|
||||||
|
diff.recovery_stats[op] = { ...c, bps: b*1000n/timediff, iops: n*1000n/timediff };
|
||||||
|
}
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
sum_op_stats(timestamp, prev_stats)
|
sum_op_stats(timestamp, prev_stats)
|
||||||
{
|
{
|
||||||
const op_stats = {}, subop_stats = {}, recovery_stats = {};
|
const sum_diff = { op_stats: {}, subop_stats: {}, recovery_stats: {} };
|
||||||
|
if (!prev_stats || prev_stats.timestamp >= timestamp)
|
||||||
|
{
|
||||||
|
return sum_diff;
|
||||||
|
}
|
||||||
|
const tm = BigInt(timestamp - (prev_stats.timestamp || 0));
|
||||||
|
// Sum derived values instead of deriving summed
|
||||||
for (const osd in this.state.osd.stats)
|
for (const osd in this.state.osd.stats)
|
||||||
{
|
{
|
||||||
const st = this.state.osd.stats[osd]||{};
|
const derived = this.derive_osd_stats(this.state.osd.stats[osd],
|
||||||
for (const op in st.op_stats||{})
|
this.prev_stats && this.prev_stats.osd_stats && this.prev_stats.osd_stats[osd]);
|
||||||
|
for (const type in derived)
|
||||||
{
|
{
|
||||||
op_stats[op] = op_stats[op] || { count: 0n, usec: 0n, bytes: 0n };
|
for (const op in derived[type])
|
||||||
op_stats[op].count += BigInt(st.op_stats[op].count||0);
|
{
|
||||||
op_stats[op].usec += BigInt(st.op_stats[op].usec||0);
|
for (const k in derived[type][op])
|
||||||
op_stats[op].bytes += BigInt(st.op_stats[op].bytes||0);
|
{
|
||||||
}
|
sum_diff[type][op] = sum_diff[type][op] || {};
|
||||||
for (const op in st.subop_stats||{})
|
sum_diff[type][op][k] = (sum_diff[type][op][k] || 0n) + derived[type][op][k];
|
||||||
{
|
}
|
||||||
subop_stats[op] = subop_stats[op] || { count: 0n, usec: 0n };
|
}
|
||||||
subop_stats[op].count += BigInt(st.subop_stats[op].count||0);
|
|
||||||
subop_stats[op].usec += BigInt(st.subop_stats[op].usec||0);
|
|
||||||
}
|
|
||||||
for (const op in st.recovery_stats||{})
|
|
||||||
{
|
|
||||||
recovery_stats[op] = recovery_stats[op] || { count: 0n, bytes: 0n };
|
|
||||||
recovery_stats[op].count += BigInt(st.recovery_stats[op].count||0);
|
|
||||||
recovery_stats[op].bytes += BigInt(st.recovery_stats[op].bytes||0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev_stats && prev_stats.timestamp >= timestamp)
|
return sum_diff;
|
||||||
{
|
|
||||||
prev_stats = null;
|
|
||||||
}
|
|
||||||
const tm = prev_stats ? BigInt(timestamp - prev_stats.timestamp) : 0;
|
|
||||||
for (const op in op_stats)
|
|
||||||
{
|
|
||||||
if (prev_stats && prev_stats.op_stats && prev_stats.op_stats[op])
|
|
||||||
{
|
|
||||||
op_stats[op].bps = (op_stats[op].bytes - prev_stats.op_stats[op].bytes) * 1000n / tm;
|
|
||||||
op_stats[op].iops = (op_stats[op].count - prev_stats.op_stats[op].count) * 1000n / tm;
|
|
||||||
op_stats[op].lat = (op_stats[op].usec - prev_stats.op_stats[op].usec)
|
|
||||||
/ ((op_stats[op].count - prev_stats.op_stats[op].count) || 1n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const op in subop_stats)
|
|
||||||
{
|
|
||||||
if (prev_stats && prev_stats.subop_stats && prev_stats.subop_stats[op])
|
|
||||||
{
|
|
||||||
subop_stats[op].iops = (subop_stats[op].count - prev_stats.subop_stats[op].count) * 1000n / tm;
|
|
||||||
subop_stats[op].lat = (subop_stats[op].usec - prev_stats.subop_stats[op].usec)
|
|
||||||
/ ((subop_stats[op].count - prev_stats.subop_stats[op].count) || 1n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const op in recovery_stats)
|
|
||||||
{
|
|
||||||
if (prev_stats && prev_stats.recovery_stats && prev_stats.recovery_stats[op])
|
|
||||||
{
|
|
||||||
recovery_stats[op].bps = (recovery_stats[op].bytes - prev_stats.recovery_stats[op].bytes) * 1000n / tm;
|
|
||||||
recovery_stats[op].iops = (recovery_stats[op].count - prev_stats.recovery_stats[op].count) * 1000n / tm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { op_stats, subop_stats, recovery_stats };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sum_object_counts()
|
sum_object_counts()
|
||||||
@@ -1627,7 +1638,8 @@ class Mon
|
|||||||
this.prev_stats ? this.prev_stats.inode_stats : null,
|
this.prev_stats ? this.prev_stats.inode_stats : null,
|
||||||
timestamp, this.prev_stats ? this.prev_stats.timestamp : null
|
timestamp, this.prev_stats ? this.prev_stats.timestamp : null
|
||||||
);
|
);
|
||||||
this.prev_stats = { timestamp, ...stats, inode_stats };
|
this.prev_stats = { timestamp, inode_stats, osd_stats: { ...this.state.osd.stats } };
|
||||||
|
this.stat_time = Date.now();
|
||||||
stats.object_counts = object_counts;
|
stats.object_counts = object_counts;
|
||||||
stats.object_bytes = object_bytes;
|
stats.object_bytes = object_bytes;
|
||||||
stats = this.serialize_bigints(stats);
|
stats = this.serialize_bigints(stats);
|
||||||
@@ -1743,13 +1755,14 @@ class Mon
|
|||||||
else if (key_parts[0] === 'osd' && key_parts[1] === 'stats')
|
else if (key_parts[0] === 'osd' && key_parts[1] === 'stats')
|
||||||
{
|
{
|
||||||
// Recheck OSD tree on OSD addition/deletion
|
// Recheck OSD tree on OSD addition/deletion
|
||||||
|
const osd_num = key_parts[2];
|
||||||
if ((!old) != (!kv.value) || old && kv.value && old.size != kv.value.size)
|
if ((!old) != (!kv.value) || old && kv.value && old.size != kv.value.size)
|
||||||
{
|
{
|
||||||
this.schedule_recheck();
|
this.schedule_recheck();
|
||||||
}
|
}
|
||||||
// Recheck PGs <osd_out_time> after last OSD statistics report
|
// Recheck PGs <osd_out_time> after last OSD statistics report
|
||||||
this.schedule_next_recheck_at(
|
this.schedule_next_recheck_at(
|
||||||
!this.state.osd.stats[key[2]] ? 0 : this.state.osd.stats[key[2]].time+this.config.osd_out_time
|
!this.state.osd.stats[osd_num] ? 0 : this.state.osd.stats[osd_num].time+this.config.osd_out_time
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -388,8 +388,6 @@ sub unmap_volume
|
|||||||
my ($class, $storeid, $scfg, $volname, $snapname) = @_;
|
my ($class, $storeid, $scfg, $volname, $snapname) = @_;
|
||||||
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
my $prefix = defined $scfg->{vitastor_prefix} ? $scfg->{vitastor_prefix} : 'pve/';
|
||||||
|
|
||||||
return 1 if !$scfg->{vitastor_nbd};
|
|
||||||
|
|
||||||
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
|
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
|
||||||
$name .= '@'.$snapname if $snapname;
|
$name .= '@'.$snapname if $snapname;
|
||||||
|
|
||||||
@@ -413,7 +411,7 @@ sub activate_volume
|
|||||||
sub deactivate_volume
|
sub deactivate_volume
|
||||||
{
|
{
|
||||||
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
|
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
|
||||||
$class->unmap_volume($storeid, $scfg, $volname, $snapname);
|
$class->unmap_volume($storeid, $scfg, $volname, $snapname) if $scfg->{vitastor_nbd};
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -50,7 +50,7 @@ from cinder.volume import configuration
|
|||||||
from cinder.volume import driver
|
from cinder.volume import driver
|
||||||
from cinder.volume import volume_utils
|
from cinder.volume import volume_utils
|
||||||
|
|
||||||
VERSION = '0.9.0'
|
VERSION = '0.9.2'
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@@ -24,4 +24,4 @@ rm fio
|
|||||||
mv fio-copy 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"; }'`
|
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
|
perl -i -pe 's/(Requires:\s*fio)([^\n]+)?/$1 = '$FIO'/' $VITASTOR/rpm/vitastor-el$EL.spec
|
||||||
tar --transform 's#^#vitastor-0.9.0/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.9.0$(rpm --eval '%dist').tar.gz *
|
tar --transform 's#^#vitastor-0.9.2/#' --exclude 'rpm/*.rpm' -czf $VITASTOR/../vitastor-0.9.2$(rpm --eval '%dist').tar.gz *
|
||||||
|
@@ -35,7 +35,7 @@ ADD . /root/vitastor
|
|||||||
RUN set -e; \
|
RUN set -e; \
|
||||||
cd /root/vitastor/rpm; \
|
cd /root/vitastor/rpm; \
|
||||||
sh build-tarball.sh; \
|
sh build-tarball.sh; \
|
||||||
cp /root/vitastor-0.9.0.el7.tar.gz ~/rpmbuild/SOURCES; \
|
cp /root/vitastor-0.9.2.el7.tar.gz ~/rpmbuild/SOURCES; \
|
||||||
cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
cp vitastor-el7.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
||||||
cd ~/rpmbuild/SPECS/; \
|
cd ~/rpmbuild/SPECS/; \
|
||||||
rpmbuild -ba vitastor.spec; \
|
rpmbuild -ba vitastor.spec; \
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 0.9.0
|
Version: 0.9.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Vitastor, a fast software-defined clustered block storage
|
Summary: Vitastor, a fast software-defined clustered block storage
|
||||||
|
|
||||||
License: Vitastor Network Public License 1.1
|
License: Vitastor Network Public License 1.1
|
||||||
URL: https://vitastor.io/
|
URL: https://vitastor.io/
|
||||||
Source0: vitastor-0.9.0.el7.tar.gz
|
Source0: vitastor-0.9.2.el7.tar.gz
|
||||||
|
|
||||||
BuildRequires: liburing-devel >= 0.6
|
BuildRequires: liburing-devel >= 0.6
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
|
@@ -35,7 +35,7 @@ ADD . /root/vitastor
|
|||||||
RUN set -e; \
|
RUN set -e; \
|
||||||
cd /root/vitastor/rpm; \
|
cd /root/vitastor/rpm; \
|
||||||
sh build-tarball.sh; \
|
sh build-tarball.sh; \
|
||||||
cp /root/vitastor-0.9.0.el8.tar.gz ~/rpmbuild/SOURCES; \
|
cp /root/vitastor-0.9.2.el8.tar.gz ~/rpmbuild/SOURCES; \
|
||||||
cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
cp vitastor-el8.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
||||||
cd ~/rpmbuild/SPECS/; \
|
cd ~/rpmbuild/SPECS/; \
|
||||||
rpmbuild -ba vitastor.spec; \
|
rpmbuild -ba vitastor.spec; \
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 0.9.0
|
Version: 0.9.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Vitastor, a fast software-defined clustered block storage
|
Summary: Vitastor, a fast software-defined clustered block storage
|
||||||
|
|
||||||
License: Vitastor Network Public License 1.1
|
License: Vitastor Network Public License 1.1
|
||||||
URL: https://vitastor.io/
|
URL: https://vitastor.io/
|
||||||
Source0: vitastor-0.9.0.el8.tar.gz
|
Source0: vitastor-0.9.2.el8.tar.gz
|
||||||
|
|
||||||
BuildRequires: liburing-devel >= 0.6
|
BuildRequires: liburing-devel >= 0.6
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
|
@@ -18,7 +18,7 @@ ADD . /root/vitastor
|
|||||||
RUN set -e; \
|
RUN set -e; \
|
||||||
cd /root/vitastor/rpm; \
|
cd /root/vitastor/rpm; \
|
||||||
sh build-tarball.sh; \
|
sh build-tarball.sh; \
|
||||||
cp /root/vitastor-0.9.0.el9.tar.gz ~/rpmbuild/SOURCES; \
|
cp /root/vitastor-0.9.2.el9.tar.gz ~/rpmbuild/SOURCES; \
|
||||||
cp vitastor-el9.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
cp vitastor-el9.spec ~/rpmbuild/SPECS/vitastor.spec; \
|
||||||
cd ~/rpmbuild/SPECS/; \
|
cd ~/rpmbuild/SPECS/; \
|
||||||
rpmbuild -ba vitastor.spec; \
|
rpmbuild -ba vitastor.spec; \
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
Name: vitastor
|
Name: vitastor
|
||||||
Version: 0.9.0
|
Version: 0.9.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: Vitastor, a fast software-defined clustered block storage
|
Summary: Vitastor, a fast software-defined clustered block storage
|
||||||
|
|
||||||
License: Vitastor Network Public License 1.1
|
License: Vitastor Network Public License 1.1
|
||||||
URL: https://vitastor.io/
|
URL: https://vitastor.io/
|
||||||
Source0: vitastor-0.9.0.el9.tar.gz
|
Source0: vitastor-0.9.2.el9.tar.gz
|
||||||
|
|
||||||
BuildRequires: liburing-devel >= 0.6
|
BuildRequires: liburing-devel >= 0.6
|
||||||
BuildRequires: gperftools-devel
|
BuildRequires: gperftools-devel
|
||||||
|
@@ -16,7 +16,7 @@ if("${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/local/?$")
|
|||||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DVERSION="0.9.0")
|
add_definitions(-DVERSION="0.9.2")
|
||||||
add_definitions(-Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -I ${CMAKE_SOURCE_DIR}/src)
|
add_definitions(-Wall -Wno-sign-compare -Wno-comment -Wno-parentheses -Wno-pointer-arith -fdiagnostics-color=always -I ${CMAKE_SOURCE_DIR}/src)
|
||||||
if (${WITH_ASAN})
|
if (${WITH_ASAN})
|
||||||
add_definitions(-fsanitize=address -fno-omit-frame-pointer)
|
add_definitions(-fsanitize=address -fno-omit-frame-pointer)
|
||||||
|
@@ -536,14 +536,27 @@ resume_1:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// zero out old metadata entry
|
// zero out old metadata entry
|
||||||
|
{
|
||||||
|
clean_disk_entry *old_entry = (clean_disk_entry*)((uint8_t*)meta_old.buf + meta_old.pos*bs->dsk.clean_entry_size);
|
||||||
|
if (old_entry->oid.inode != 0 && old_entry->oid != cur.oid)
|
||||||
|
{
|
||||||
|
printf("Fatal error (metadata corruption or bug): tried to wipe metadata entry %lu (%lx:%lx v%lu) as old location of %lx:%lx\n",
|
||||||
|
old_clean_loc >> bs->dsk.block_order, old_entry->oid.inode, old_entry->oid.stripe,
|
||||||
|
old_entry->version, cur.oid.inode, cur.oid.stripe);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
memset((uint8_t*)meta_old.buf + meta_old.pos*bs->dsk.clean_entry_size, 0, bs->dsk.clean_entry_size);
|
memset((uint8_t*)meta_old.buf + meta_old.pos*bs->dsk.clean_entry_size, 0, bs->dsk.clean_entry_size);
|
||||||
await_sqe(15);
|
if (meta_old.sector != meta_new.sector)
|
||||||
data->iov = (struct iovec){ meta_old.buf, bs->dsk.meta_block_size };
|
{
|
||||||
data->callback = simple_callback_w;
|
await_sqe(15);
|
||||||
my_uring_prep_writev(
|
data->iov = (struct iovec){ meta_old.buf, bs->dsk.meta_block_size };
|
||||||
sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + meta_old.sector
|
data->callback = simple_callback_w;
|
||||||
);
|
my_uring_prep_writev(
|
||||||
wait_count++;
|
sqe, bs->dsk.meta_fd, &data->iov, 1, bs->dsk.meta_offset + bs->dsk.meta_block_size + meta_old.sector
|
||||||
|
);
|
||||||
|
wait_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (has_delete)
|
if (has_delete)
|
||||||
{
|
{
|
||||||
@@ -662,53 +675,58 @@ resume_1:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
flusher->trimming = true;
|
flusher->trimming = true;
|
||||||
// First update journal "superblock" and only then update <used_start> in memory
|
// Recheck the position with the "lock" taken
|
||||||
await_sqe(12);
|
new_trim_pos = bs->journal.get_trim_pos();
|
||||||
*((journal_entry_start*)flusher->journal_superblock) = {
|
if (new_trim_pos != bs->journal.used_start)
|
||||||
.crc32 = 0,
|
|
||||||
.magic = JOURNAL_MAGIC,
|
|
||||||
.type = JE_START,
|
|
||||||
.size = sizeof(journal_entry_start),
|
|
||||||
.reserved = 0,
|
|
||||||
.journal_start = new_trim_pos,
|
|
||||||
.version = JOURNAL_VERSION,
|
|
||||||
};
|
|
||||||
((journal_entry_start*)flusher->journal_superblock)->crc32 = je_crc32((journal_entry*)flusher->journal_superblock);
|
|
||||||
data->iov = (struct iovec){ flusher->journal_superblock, bs->dsk.journal_block_size };
|
|
||||||
data->callback = simple_callback_w;
|
|
||||||
my_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset);
|
|
||||||
wait_count++;
|
|
||||||
resume_13:
|
|
||||||
if (wait_count > 0)
|
|
||||||
{
|
{
|
||||||
wait_state = 13;
|
// First update journal "superblock" and only then update <used_start> in memory
|
||||||
return false;
|
await_sqe(12);
|
||||||
}
|
*((journal_entry_start*)flusher->journal_superblock) = {
|
||||||
if (!bs->disable_journal_fsync)
|
.crc32 = 0,
|
||||||
{
|
.magic = JOURNAL_MAGIC,
|
||||||
await_sqe(20);
|
.type = JE_START,
|
||||||
my_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC);
|
.size = sizeof(journal_entry_start),
|
||||||
data->iov = { 0 };
|
.reserved = 0,
|
||||||
|
.journal_start = new_trim_pos,
|
||||||
|
.version = JOURNAL_VERSION,
|
||||||
|
};
|
||||||
|
((journal_entry_start*)flusher->journal_superblock)->crc32 = je_crc32((journal_entry*)flusher->journal_superblock);
|
||||||
|
data->iov = (struct iovec){ flusher->journal_superblock, bs->dsk.journal_block_size };
|
||||||
data->callback = simple_callback_w;
|
data->callback = simple_callback_w;
|
||||||
resume_21:
|
my_uring_prep_writev(sqe, bs->dsk.journal_fd, &data->iov, 1, bs->journal.offset);
|
||||||
|
wait_count++;
|
||||||
|
resume_13:
|
||||||
if (wait_count > 0)
|
if (wait_count > 0)
|
||||||
{
|
{
|
||||||
wait_state = 21;
|
wait_state = 13;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
if (!bs->disable_journal_fsync)
|
||||||
bs->journal.used_start = new_trim_pos;
|
{
|
||||||
|
await_sqe(20);
|
||||||
|
my_uring_prep_fsync(sqe, bs->dsk.journal_fd, IORING_FSYNC_DATASYNC);
|
||||||
|
data->iov = { 0 };
|
||||||
|
data->callback = simple_callback_w;
|
||||||
|
resume_21:
|
||||||
|
if (wait_count > 0)
|
||||||
|
{
|
||||||
|
wait_state = 21;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bs->journal.used_start = new_trim_pos;
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
printf("Journal trimmed to %08lx (next_free=%08lx)\n", bs->journal.used_start, bs->journal.next_free);
|
printf("Journal trimmed to %08lx (next_free=%08lx)\n", bs->journal.used_start, bs->journal.next_free);
|
||||||
#endif
|
#endif
|
||||||
|
if (bs->journal.flush_journal && !flusher->flush_queue.size())
|
||||||
|
{
|
||||||
|
assert(bs->journal.used_start == bs->journal.next_free);
|
||||||
|
printf("Journal flushed\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
flusher->trimming = false;
|
flusher->trimming = false;
|
||||||
}
|
}
|
||||||
if (bs->journal.flush_journal && !flusher->flush_queue.size())
|
|
||||||
{
|
|
||||||
assert(bs->journal.used_start == bs->journal.next_free);
|
|
||||||
printf("Journal flushed\n");
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// All done
|
// All done
|
||||||
flusher->active_flushers--;
|
flusher->active_flushers--;
|
||||||
|
@@ -236,14 +236,6 @@ journal_t::~journal_t()
|
|||||||
uint64_t journal_t::get_trim_pos()
|
uint64_t journal_t::get_trim_pos()
|
||||||
{
|
{
|
||||||
auto journal_used_it = used_sectors.lower_bound(used_start);
|
auto journal_used_it = used_sectors.lower_bound(used_start);
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
|
||||||
printf(
|
|
||||||
"Trimming journal (used_start=%08lx, next_free=%08lx, dirty_start=%08lx, new_start=%08lx, new_refcount=%ld)\n",
|
|
||||||
used_start, next_free, dirty_start,
|
|
||||||
journal_used_it == used_sectors.end() ? 0 : journal_used_it->first,
|
|
||||||
journal_used_it == used_sectors.end() ? 0 : journal_used_it->second
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
if (journal_used_it == used_sectors.end())
|
if (journal_used_it == used_sectors.end())
|
||||||
{
|
{
|
||||||
// Journal is cleared to its end, restart from the beginning
|
// Journal is cleared to its end, restart from the beginning
|
||||||
@@ -256,12 +248,26 @@ uint64_t journal_t::get_trim_pos()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// next_free does not need updating during trim
|
// next_free does not need updating during trim
|
||||||
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
|
printf(
|
||||||
|
"Trimming journal (used_start=%08lx, next_free=%08lx, dirty_start=%08lx, new_start=%08lx, new_refcount=%ld)\n",
|
||||||
|
used_start, next_free, dirty_start,
|
||||||
|
journal_used_it->first, journal_used_it->second
|
||||||
|
);
|
||||||
|
#endif
|
||||||
return journal_used_it->first;
|
return journal_used_it->first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (journal_used_it->first > used_start)
|
else if (journal_used_it->first > used_start)
|
||||||
{
|
{
|
||||||
// Journal is cleared up to <journal_used_it>
|
// Journal is cleared up to <journal_used_it>
|
||||||
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
|
printf(
|
||||||
|
"Trimming journal (used_start=%08lx, next_free=%08lx, dirty_start=%08lx, new_start=%08lx, new_refcount=%ld)\n",
|
||||||
|
used_start, next_free, dirty_start,
|
||||||
|
journal_used_it->first, journal_used_it->second
|
||||||
|
);
|
||||||
|
#endif
|
||||||
return journal_used_it->first;
|
return journal_used_it->first;
|
||||||
}
|
}
|
||||||
// Can't trim journal
|
// Can't trim journal
|
||||||
|
@@ -138,10 +138,6 @@ int blockstore_impl_t::dequeue_read(blockstore_op_t *read_op)
|
|||||||
{
|
{
|
||||||
dirty_entry& dirty = dirty_it->second;
|
dirty_entry& dirty = dirty_it->second;
|
||||||
bool version_ok = !IS_IN_FLIGHT(dirty.state) && read_op->version >= dirty_it->first.version;
|
bool version_ok = !IS_IN_FLIGHT(dirty.state) && read_op->version >= dirty_it->first.version;
|
||||||
if (IS_SYNCED(dirty.state))
|
|
||||||
{
|
|
||||||
version_ok = true;
|
|
||||||
}
|
|
||||||
if (version_ok)
|
if (version_ok)
|
||||||
{
|
{
|
||||||
if (IS_DELETE(dirty.state))
|
if (IS_DELETE(dirty.state))
|
||||||
|
@@ -179,7 +179,7 @@ void blockstore_impl_t::erase_dirty(blockstore_dirty_db_t::iterator dirty_start,
|
|||||||
{
|
{
|
||||||
object_id oid = dirty_it->first.oid;
|
object_id oid = dirty_it->first.oid;
|
||||||
#ifdef BLOCKSTORE_DEBUG
|
#ifdef BLOCKSTORE_DEBUG
|
||||||
printf("Unblock writes-after-delete %lx:%lx v%lx\n", oid.inode, oid.stripe, dirty_it->first.version);
|
printf("Unblock writes-after-delete %lx:%lx v%lu\n", oid.inode, oid.stripe, dirty_it->first.version);
|
||||||
#endif
|
#endif
|
||||||
dirty_it = dirty_end;
|
dirty_it = dirty_end;
|
||||||
// Unblock operations blocked by delete flushing
|
// Unblock operations blocked by delete flushing
|
||||||
|
@@ -458,6 +458,16 @@ void blockstore_impl_t::mark_stable(const obj_ver_id & v, bool forget_dirty)
|
|||||||
big_to_flush++;
|
big_to_flush++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (IS_IN_FLIGHT(dirty_it->second.state))
|
||||||
|
{
|
||||||
|
// mark_stable should never be called for in-flight or submitted writes
|
||||||
|
printf(
|
||||||
|
"BUG: Attempt to mark_stable object %lx:%lx v%lu state of which is %x\n",
|
||||||
|
dirty_it->first.oid.inode, dirty_it->first.oid.stripe, dirty_it->first.version,
|
||||||
|
dirty_it->second.state
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (forget_dirty && (IS_BIG_WRITE(dirty_it->second.state) ||
|
if (forget_dirty && (IS_BIG_WRITE(dirty_it->second.state) ||
|
||||||
IS_DELETE(dirty_it->second.state)))
|
IS_DELETE(dirty_it->second.state)))
|
||||||
{
|
{
|
||||||
|
@@ -409,7 +409,23 @@ int blockstore_impl_t::dequeue_write(blockstore_op_t *op)
|
|||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
// Figure out where data will be
|
// Figure out where data will be
|
||||||
journal.next_free = (journal.next_free + op->len) <= journal.len ? journal.next_free : dsk.journal_block_size;
|
auto next_next_free = (journal.next_free + op->len) <= journal.len ? journal.next_free : dsk.journal_block_size;
|
||||||
|
if (op->len > 0)
|
||||||
|
{
|
||||||
|
auto journal_used_it = journal.used_sectors.lower_bound(next_next_free);
|
||||||
|
if (journal_used_it != journal.used_sectors.end() &&
|
||||||
|
journal_used_it->first < next_next_free + op->len)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"BUG: Attempt to overwrite used offset (%lx, %lu refs) of the journal with the object %lx:%lx v%lu: data at %lx, len %x!"
|
||||||
|
" Journal used_start=%08lx (%lu refs), next_free=%08lx, dirty_start=%08lx\n",
|
||||||
|
journal_used_it->first, journal_used_it->second, op->oid.inode, op->oid.stripe, op->version, next_next_free, op->len,
|
||||||
|
journal.used_start, journal.used_sectors[journal.used_start], journal.next_free, journal.dirty_start
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
journal.next_free = next_next_free;
|
||||||
je->oid = op->oid;
|
je->oid = op->oid;
|
||||||
je->version = op->version;
|
je->version = op->version;
|
||||||
je->offset = op->offset;
|
je->offset = op->offset;
|
||||||
|
@@ -12,7 +12,7 @@ static const char *obj_states[] = { "clean", "misplaced", "degraded", "incomplet
|
|||||||
// Print cluster status:
|
// Print cluster status:
|
||||||
// etcd, mon, osd states
|
// etcd, mon, osd states
|
||||||
// raw/used space, object states, pool states, pg states
|
// raw/used space, object states, pool states, pg states
|
||||||
// client io, recovery io, rebalance io
|
// client io, recovery io, rebalance io, scrub io
|
||||||
struct status_printer_t
|
struct status_printer_t
|
||||||
{
|
{
|
||||||
cli_tool_t *parent;
|
cli_tool_t *parent;
|
||||||
@@ -252,18 +252,25 @@ resume_2:
|
|||||||
}
|
}
|
||||||
more_states.resize(more_states.size()-2);
|
more_states.resize(more_states.size()-2);
|
||||||
std::string recovery_io;
|
std::string recovery_io;
|
||||||
|
int io_indent = 0;
|
||||||
{
|
{
|
||||||
uint64_t deg_bps = agg_stats["recovery_stats"]["degraded"]["bps"].uint64_value();
|
uint64_t deg_bps = agg_stats["recovery_stats"]["degraded"]["bps"].uint64_value();
|
||||||
uint64_t deg_iops = agg_stats["recovery_stats"]["degraded"]["iops"].uint64_value();
|
uint64_t deg_iops = agg_stats["recovery_stats"]["degraded"]["iops"].uint64_value();
|
||||||
uint64_t misp_bps = agg_stats["recovery_stats"]["misplaced"]["bps"].uint64_value();
|
uint64_t misp_bps = agg_stats["recovery_stats"]["misplaced"]["bps"].uint64_value();
|
||||||
uint64_t misp_iops = agg_stats["recovery_stats"]["misplaced"]["iops"].uint64_value();
|
uint64_t misp_iops = agg_stats["recovery_stats"]["misplaced"]["iops"].uint64_value();
|
||||||
|
uint64_t scrub_bps = agg_stats["op_stats"]["scrub"]["bps"].uint64_value();
|
||||||
|
uint64_t scrub_iops = agg_stats["op_stats"]["scrub"]["iops"].uint64_value();
|
||||||
|
if (misp_iops > 0 || misp_bps > 0 || no_rebalance)
|
||||||
|
io_indent = 3;
|
||||||
|
else if (deg_iops > 0 || deg_bps > 0 || no_recovery)
|
||||||
|
io_indent = 2;
|
||||||
if (deg_iops > 0 || deg_bps > 0)
|
if (deg_iops > 0 || deg_bps > 0)
|
||||||
{
|
{
|
||||||
recovery_io += " recovery: "+std::string(no_recovery ? "disabled, " : "")+
|
recovery_io += " recovery: "+str_repeat(" ", io_indent-2)+std::string(no_recovery ? "disabled, " : "")+
|
||||||
format_size(deg_bps)+"/s, "+format_size(deg_iops, true)+" op/s\n";
|
format_size(deg_bps)+"/s, "+format_size(deg_iops, true)+" op/s\n";
|
||||||
}
|
}
|
||||||
else if (no_recovery)
|
else if (no_recovery)
|
||||||
recovery_io += " recovery: disabled\n";
|
recovery_io += " recovery: disabled\n";
|
||||||
if (misp_iops > 0 || misp_bps > 0)
|
if (misp_iops > 0 || misp_bps > 0)
|
||||||
{
|
{
|
||||||
recovery_io += " rebalance: "+std::string(no_rebalance ? "disabled, " : "")+
|
recovery_io += " rebalance: "+std::string(no_rebalance ? "disabled, " : "")+
|
||||||
@@ -271,6 +278,13 @@ resume_2:
|
|||||||
}
|
}
|
||||||
else if (no_rebalance)
|
else if (no_rebalance)
|
||||||
recovery_io += " rebalance: disabled\n";
|
recovery_io += " rebalance: disabled\n";
|
||||||
|
if (scrub_iops > 0 || scrub_bps > 0)
|
||||||
|
{
|
||||||
|
recovery_io += " scrub: "+str_repeat(" ", io_indent+1)+std::string(no_scrub ? "disabled, " : "")+
|
||||||
|
format_size(scrub_bps)+"/s, "+format_size(scrub_iops, true)+" op/s\n";
|
||||||
|
}
|
||||||
|
else if (no_scrub)
|
||||||
|
recovery_io += " scrub: "+str_repeat(" ", io_indent+1)+"disabled\n";
|
||||||
}
|
}
|
||||||
printf(
|
printf(
|
||||||
" cluster:\n"
|
" cluster:\n"
|
||||||
@@ -298,7 +312,7 @@ resume_2:
|
|||||||
pools_active, pool_count,
|
pools_active, pool_count,
|
||||||
pgs_by_state_str.c_str(),
|
pgs_by_state_str.c_str(),
|
||||||
readonly ? " (read-only mode)" : "",
|
readonly ? " (read-only mode)" : "",
|
||||||
recovery_io.size() > 0 ? " " : "",
|
str_repeat(" ", io_indent).c_str(),
|
||||||
format_size(agg_stats["op_stats"]["primary_read"]["bps"].uint64_value()).c_str(),
|
format_size(agg_stats["op_stats"]["primary_read"]["bps"].uint64_value()).c_str(),
|
||||||
format_size(agg_stats["op_stats"]["primary_read"]["iops"].uint64_value(), true).c_str(),
|
format_size(agg_stats["op_stats"]["primary_read"]["iops"].uint64_value(), true).c_str(),
|
||||||
format_size(agg_stats["op_stats"]["primary_write"]["bps"].uint64_value()).c_str(),
|
format_size(agg_stats["op_stats"]["primary_write"]["bps"].uint64_value()).c_str(),
|
||||||
|
@@ -251,6 +251,10 @@ void osd_messenger_t::try_connect_peer_addr(osd_num_t peer_osd, const char *peer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clients[peer_fd] = new osd_client_t();
|
clients[peer_fd] = new osd_client_t();
|
||||||
|
if (log_level > 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Connecting to OSD %lu at %s:%d (client %d)\n", peer_osd, peer_host, peer_port, peer_fd);
|
||||||
|
}
|
||||||
clients[peer_fd]->peer_addr = addr;
|
clients[peer_fd]->peer_addr = addr;
|
||||||
clients[peer_fd]->peer_port = peer_port;
|
clients[peer_fd]->peer_port = peer_port;
|
||||||
clients[peer_fd]->peer_fd = peer_fd;
|
clients[peer_fd]->peer_fd = peer_fd;
|
||||||
@@ -313,7 +317,10 @@ void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
|||||||
if (epoll_events & EPOLLRDHUP)
|
if (epoll_events & EPOLLRDHUP)
|
||||||
{
|
{
|
||||||
// Stop client
|
// Stop client
|
||||||
fprintf(stderr, "[OSD %lu] client %d disconnected\n", this->osd_num, peer_fd);
|
if (log_level > 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "[OSD %lu] client %d disconnected\n", this->osd_num, peer_fd);
|
||||||
|
}
|
||||||
stop_client(peer_fd, true);
|
stop_client(peer_fd, true);
|
||||||
}
|
}
|
||||||
else if (epoll_events & EPOLLIN)
|
else if (epoll_events & EPOLLIN)
|
||||||
|
@@ -50,7 +50,7 @@ struct osd_client_t
|
|||||||
|
|
||||||
sockaddr_storage peer_addr;
|
sockaddr_storage peer_addr;
|
||||||
int peer_port;
|
int peer_port;
|
||||||
int peer_fd;
|
int peer_fd = -1;
|
||||||
int peer_state;
|
int peer_state;
|
||||||
int connect_timeout_id = -1;
|
int connect_timeout_id = -1;
|
||||||
int ping_time_remaining = 0;
|
int ping_time_remaining = 0;
|
||||||
@@ -87,11 +87,7 @@ struct osd_client_t
|
|||||||
std::vector<iovec> send_list, next_send_list;
|
std::vector<iovec> send_list, next_send_list;
|
||||||
std::vector<msgr_sendp_t> outbox, next_outbox;
|
std::vector<msgr_sendp_t> outbox, next_outbox;
|
||||||
|
|
||||||
~osd_client_t()
|
~osd_client_t();
|
||||||
{
|
|
||||||
free(in_buf);
|
|
||||||
in_buf = NULL;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct osd_wanted_peer_t
|
struct osd_wanted_peer_t
|
||||||
@@ -177,6 +173,8 @@ public:
|
|||||||
bool connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg);
|
bool connect_rdma(int peer_fd, std::string rdma_address, uint64_t client_max_msg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void measure_exec(osd_op_t *cur_op);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void try_connect_peer(uint64_t osd_num);
|
void try_connect_peer(uint64_t osd_num);
|
||||||
void try_connect_peer_addr(osd_num_t peer_osd, const char *peer_host, int peer_port);
|
void try_connect_peer_addr(osd_num_t peer_osd, const char *peer_host, int peer_port);
|
||||||
@@ -188,7 +186,6 @@ protected:
|
|||||||
void cancel_op(osd_op_t *op);
|
void cancel_op(osd_op_t *op);
|
||||||
|
|
||||||
bool try_send(osd_client_t *cl);
|
bool try_send(osd_client_t *cl);
|
||||||
void measure_exec(osd_op_t *cur_op);
|
|
||||||
void handle_send(int result, osd_client_t *cl);
|
void handle_send(int result, osd_client_t *cl);
|
||||||
|
|
||||||
bool handle_read(int result, osd_client_t *cl);
|
bool handle_read(int result, osd_client_t *cl);
|
||||||
|
@@ -150,8 +150,10 @@ void osd_messenger_t::measure_exec(osd_op_t *cur_op)
|
|||||||
(cur_op->tv_end.tv_nsec - cur_op->tv_begin.tv_nsec)/1000
|
(cur_op->tv_end.tv_nsec - cur_op->tv_begin.tv_nsec)/1000
|
||||||
);
|
);
|
||||||
if (cur_op->req.hdr.opcode == OSD_OP_READ ||
|
if (cur_op->req.hdr.opcode == OSD_OP_READ ||
|
||||||
cur_op->req.hdr.opcode == OSD_OP_WRITE)
|
cur_op->req.hdr.opcode == OSD_OP_WRITE ||
|
||||||
|
cur_op->req.hdr.opcode == OSD_OP_SCRUB)
|
||||||
{
|
{
|
||||||
|
// req.rw.len is internally set to the full object size for scrubs
|
||||||
stats.op_stat_bytes[cur_op->req.hdr.opcode] += cur_op->req.rw.len;
|
stats.op_stat_bytes[cur_op->req.hdr.opcode] += cur_op->req.rw.len;
|
||||||
}
|
}
|
||||||
else if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ ||
|
else if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ ||
|
||||||
|
@@ -122,17 +122,6 @@ void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
|||||||
// Cancel outbound operations
|
// Cancel outbound operations
|
||||||
cancel_osd_ops(cl);
|
cancel_osd_ops(cl);
|
||||||
}
|
}
|
||||||
#ifndef __MOCK__
|
|
||||||
// And close the FD only when everything is done
|
|
||||||
// ...because peer_fd number can get reused after close()
|
|
||||||
close(peer_fd);
|
|
||||||
#ifdef WITH_RDMA
|
|
||||||
if (cl->rdma_conn)
|
|
||||||
{
|
|
||||||
delete cl->rdma_conn;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
// Find the item again because it can be invalidated at this point
|
// Find the item again because it can be invalidated at this point
|
||||||
it = clients.find(peer_fd);
|
it = clients.find(peer_fd);
|
||||||
if (it != clients.end())
|
if (it != clients.end())
|
||||||
@@ -145,3 +134,25 @@ void osd_messenger_t::stop_client(int peer_fd, bool force, bool force_delete)
|
|||||||
delete cl;
|
delete cl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osd_client_t::~osd_client_t()
|
||||||
|
{
|
||||||
|
free(in_buf);
|
||||||
|
in_buf = NULL;
|
||||||
|
if (peer_fd >= 0)
|
||||||
|
{
|
||||||
|
// Close the FD only when the client is actually destroyed
|
||||||
|
// Which only happens when all references are cleared
|
||||||
|
close(peer_fd);
|
||||||
|
peer_fd = -1;
|
||||||
|
}
|
||||||
|
#ifndef __MOCK__
|
||||||
|
#ifdef WITH_RDMA
|
||||||
|
if (rdma_conn)
|
||||||
|
{
|
||||||
|
delete rdma_conn;
|
||||||
|
rdma_conn = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -305,7 +305,7 @@ void osd_t::submit_recovery_op(osd_recovery_op_t *op)
|
|||||||
};
|
};
|
||||||
if (log_level > 2)
|
if (log_level > 2)
|
||||||
{
|
{
|
||||||
printf("Submitting recovery operation for %lx:%lx\n", op->oid.inode, op->oid.stripe);
|
printf("Submitting recovery operation for %lx:%lx (%s)\n", op->oid.inode, op->oid.stripe, op->degraded ? "degraded" : "misplaced");
|
||||||
}
|
}
|
||||||
op->osd_op->peer_fd = -1;
|
op->osd_op->peer_fd = -1;
|
||||||
op->osd_op->callback = [this, op](osd_op_t *osd_op)
|
op->osd_op->callback = [this, op](osd_op_t *osd_op)
|
||||||
|
@@ -240,21 +240,20 @@ void osd_t::start_pg_peering(pg_t & pg)
|
|||||||
// (PG history is kept up to the latest active+clean state)
|
// (PG history is kept up to the latest active+clean state)
|
||||||
for (auto & history_set: pg.target_history)
|
for (auto & history_set: pg.target_history)
|
||||||
{
|
{
|
||||||
bool found = true;
|
int nonzero = 0, found = 0;
|
||||||
for (auto history_osd: history_set)
|
for (auto history_osd: history_set)
|
||||||
{
|
{
|
||||||
if (history_osd != 0)
|
if (history_osd != 0)
|
||||||
{
|
{
|
||||||
found = false;
|
nonzero++;
|
||||||
if (history_osd == this->osd_num ||
|
if (history_osd == this->osd_num ||
|
||||||
msgr.osd_peer_fds.find(history_osd) != msgr.osd_peer_fds.end())
|
msgr.osd_peer_fds.find(history_osd) != msgr.osd_peer_fds.end())
|
||||||
{
|
{
|
||||||
found = true;
|
found++;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
if (found < (nonzero >= pg.pg_data_size ? pg.pg_data_size : 1))
|
||||||
{
|
{
|
||||||
pg.state = PG_INCOMPLETE;
|
pg.state = PG_INCOMPLETE;
|
||||||
report_pg_state(pg);
|
report_pg_state(pg);
|
||||||
@@ -486,6 +485,10 @@ void osd_t::report_pg_state(pg_t & pg)
|
|||||||
{
|
{
|
||||||
pg.print_state();
|
pg.print_state();
|
||||||
this->pg_state_dirty.insert({ .pool_id = pg.pool_id, .pg_num = pg.pg_num });
|
this->pg_state_dirty.insert({ .pool_id = pg.pool_id, .pg_num = pg.pg_num });
|
||||||
|
if (pg.state & PG_ACTIVE)
|
||||||
|
{
|
||||||
|
plan_scrub(pg, false);
|
||||||
|
}
|
||||||
if (pg.state == PG_ACTIVE && (pg.target_history.size() > 0 || pg.all_peers.size() > pg.target_set.size()))
|
if (pg.state == PG_ACTIVE && (pg.target_history.size() > 0 || pg.all_peers.size() > pg.target_set.size()))
|
||||||
{
|
{
|
||||||
// Clear history of active+clean PGs
|
// Clear history of active+clean PGs
|
||||||
@@ -494,7 +497,6 @@ void osd_t::report_pg_state(pg_t & pg)
|
|||||||
pg.all_peers = pg.target_set;
|
pg.all_peers = pg.target_set;
|
||||||
std::sort(pg.all_peers.begin(), pg.all_peers.end());
|
std::sort(pg.all_peers.begin(), pg.all_peers.end());
|
||||||
pg.cur_peers = pg.target_set;
|
pg.cur_peers = pg.target_set;
|
||||||
plan_scrub(pg, false);
|
|
||||||
// Change pg_config at the same time, otherwise our PG reconciling loop may try to apply the old metadata
|
// Change pg_config at the same time, otherwise our PG reconciling loop may try to apply the old metadata
|
||||||
auto & pg_cfg = st_cli.pool_config[pg.pool_id].pg_config[pg.pg_num];
|
auto & pg_cfg = st_cli.pool_config[pg.pool_id].pg_config[pg.pg_num];
|
||||||
pg_cfg.target_history = pg.target_history;
|
pg_cfg.target_history = pg.target_history;
|
||||||
@@ -538,7 +540,6 @@ void osd_t::report_pg_state(pg_t & pg)
|
|||||||
pg.cur_peers.push_back(pg_osd);
|
pg.cur_peers.push_back(pg_osd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
plan_scrub(pg, false);
|
|
||||||
auto & pg_cfg = st_cli.pool_config[pg.pool_id].pg_config[pg.pg_num];
|
auto & pg_cfg = st_cli.pool_config[pg.pool_id].pg_config[pg.pg_num];
|
||||||
pg_cfg.target_history = pg.target_history;
|
pg_cfg.target_history = pg.target_history;
|
||||||
pg_cfg.all_peers = pg.all_peers;
|
pg_cfg.all_peers = pg.all_peers;
|
||||||
|
@@ -255,7 +255,7 @@ void pg_obj_state_check_t::finish_object()
|
|||||||
}
|
}
|
||||||
else if (n_mismatched > 0)
|
else if (n_mismatched > 0)
|
||||||
{
|
{
|
||||||
if (log_level > 2 && (replicated || n_roles >= pg->pg_cursize))
|
if (log_level > 2)
|
||||||
{
|
{
|
||||||
printf("Object is misplaced: %lx:%lx version=%lu/%lu\n", oid.inode, oid.stripe, target_ver, max_ver);
|
printf("Object is misplaced: %lx:%lx version=%lu/%lu\n", oid.inode, oid.stripe, target_ver, max_ver);
|
||||||
}
|
}
|
||||||
|
@@ -87,6 +87,7 @@ void osd_t::finish_op(osd_op_t *cur_op, int retval)
|
|||||||
cur_op->reply.hdr.retval = retval;
|
cur_op->reply.hdr.retval = retval;
|
||||||
if (cur_op->peer_fd == -1)
|
if (cur_op->peer_fd == -1)
|
||||||
{
|
{
|
||||||
|
msgr.measure_exec(cur_op);
|
||||||
// Copy lambda to be unaffected by `delete op`
|
// Copy lambda to be unaffected by `delete op`
|
||||||
std::function<void(osd_op_t*)>(cur_op->callback)(cur_op);
|
std::function<void(osd_op_t*)>(cur_op->callback)(cur_op);
|
||||||
}
|
}
|
||||||
@@ -357,7 +358,7 @@ void osd_t::handle_primary_subop(osd_op_t *subop, osd_op_t *cur_op)
|
|||||||
#ifdef OSD_DEBUG
|
#ifdef OSD_DEBUG
|
||||||
uint64_t peer_osd = msgr.clients.find(subop->peer_fd) != msgr.clients.end()
|
uint64_t peer_osd = msgr.clients.find(subop->peer_fd) != msgr.clients.end()
|
||||||
? msgr.clients[subop->peer_fd]->osd_num : osd_num;
|
? msgr.clients[subop->peer_fd]->osd_num : osd_num;
|
||||||
printf("subop %lu from osd %lu: version = %lu\n", opcode, peer_osd, version);
|
printf("subop %s %lx:%lx from osd %lu: version = %lu\n", osd_op_names[opcode], subop->req.sec_rw.oid.inode, subop->req.sec_rw.oid.stripe, peer_osd, version);
|
||||||
#endif
|
#endif
|
||||||
if (op_data->fact_ver != UINT64_MAX)
|
if (op_data->fact_ver != UINT64_MAX)
|
||||||
{
|
{
|
||||||
|
@@ -115,6 +115,10 @@ int osd_t::pick_next_scrub(object_id & next_oid)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (scrub_list_op)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
timespec tv_now;
|
timespec tv_now;
|
||||||
clock_gettime(CLOCK_REALTIME, &tv_now);
|
clock_gettime(CLOCK_REALTIME, &tv_now);
|
||||||
bool rescan = scrub_last_pg.pool_id != 0 || scrub_last_pg.pg_num != 0;
|
bool rescan = scrub_last_pg.pool_id != 0 || scrub_last_pg.pg_num != 0;
|
||||||
@@ -127,7 +131,7 @@ int osd_t::pick_next_scrub(object_id & next_oid)
|
|||||||
}
|
}
|
||||||
while (pg_it != pgs.end())
|
while (pg_it != pgs.end())
|
||||||
{
|
{
|
||||||
if ((pg_it->second.state & PG_ACTIVE) && pg_it->second.next_scrub && pg_it->second.next_scrub < tv_now.tv_sec)
|
if ((pg_it->second.state & PG_ACTIVE) && pg_it->second.next_scrub && pg_it->second.next_scrub <= tv_now.tv_sec)
|
||||||
{
|
{
|
||||||
// Continue scrubbing from the next object
|
// Continue scrubbing from the next object
|
||||||
if (scrub_last_pg == pg_it->first)
|
if (scrub_last_pg == pg_it->first)
|
||||||
@@ -346,7 +350,7 @@ void osd_t::schedule_scrub(pg_t & pg)
|
|||||||
tfd->clear_timer(scrub_timer_id);
|
tfd->clear_timer(scrub_timer_id);
|
||||||
scrub_timer_id = -1;
|
scrub_timer_id = -1;
|
||||||
}
|
}
|
||||||
if (tv_now.tv_sec > scrub_nearest_ts)
|
if (tv_now.tv_sec >= scrub_nearest_ts)
|
||||||
{
|
{
|
||||||
scrub_nearest_ts = 0;
|
scrub_nearest_ts = 0;
|
||||||
peering_state = peering_state | OSD_SCRUBBING;
|
peering_state = peering_state | OSD_SCRUBBING;
|
||||||
@@ -376,6 +380,7 @@ void osd_t::continue_primary_scrub(osd_op_t *cur_op)
|
|||||||
goto resume_2;
|
goto resume_2;
|
||||||
{
|
{
|
||||||
auto & pg = pgs.at({ .pool_id = INODE_POOL(op_data->oid.inode), .pg_num = op_data->pg_num });
|
auto & pg = pgs.at({ .pool_id = INODE_POOL(op_data->oid.inode), .pg_num = op_data->pg_num });
|
||||||
|
cur_op->req.rw.len = bs_block_size * pg.pg_data_size;
|
||||||
// Determine version
|
// Determine version
|
||||||
auto vo_it = pg.ver_override.find(op_data->oid);
|
auto vo_it = pg.ver_override.find(op_data->oid);
|
||||||
op_data->target_ver = vo_it != pg.ver_override.end() ? vo_it->second : UINT64_MAX;
|
op_data->target_ver = vo_it != pg.ver_override.end() ? vo_it->second : UINT64_MAX;
|
||||||
|
@@ -300,3 +300,11 @@ std::string read_all_fd(int fd)
|
|||||||
res.resize(res_size);
|
res.resize(res_size);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string str_repeat(const std::string & str, int times)
|
||||||
|
{
|
||||||
|
std::string r;
|
||||||
|
for (int i = 0; i < times; i++)
|
||||||
|
r += str;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
@@ -17,3 +17,4 @@ std::string format_size(uint64_t size, bool nobytes = false);
|
|||||||
void print_help(const char *help_text, std::string exe_name, std::string cmd, bool all);
|
void print_help(const char *help_text, std::string exe_name, std::string cmd, bool all);
|
||||||
uint64_t parse_time(std::string time_str, bool *ok = NULL);
|
uint64_t parse_time(std::string time_str, bool *ok = NULL);
|
||||||
std::string read_all_fd(int fd);
|
std::string read_all_fd(int fd);
|
||||||
|
std::string str_repeat(const std::string & str, int times);
|
||||||
|
@@ -6,7 +6,7 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
|||||||
|
|
||||||
Name: Vitastor
|
Name: Vitastor
|
||||||
Description: Vitastor client library
|
Description: Vitastor client library
|
||||||
Version: 0.9.0
|
Version: 0.9.2
|
||||||
Libs: -L${libdir} -lvitastor_client
|
Libs: -L${libdir} -lvitastor_client
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|
||||||
|
@@ -85,7 +85,7 @@ try_change 16
|
|||||||
|
|
||||||
# Monitor should report non-zero overall statistics at least once
|
# Monitor should report non-zero overall statistics at least once
|
||||||
|
|
||||||
if ! (grep /vitastor/stats ./testdata/mon.log | jq -s -e '[ .[] | select((.kv.value.op_stats.primary_write.count | tonumber) > 0) ] | length > 0'); then
|
if ! (grep /vitastor/stats ./testdata/mon.log | jq -s -e '[ .[] | select((.kv.value.op_stats.primary_write.count // 0 | tonumber) > 0) ] | length > 0'); then
|
||||||
format_error "FAILED: monitor doesn't aggregate stats"
|
format_error "FAILED: monitor doesn't aggregate stats"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -46,8 +46,8 @@ kill_osds()
|
|||||||
kill_osds &
|
kill_osds &
|
||||||
|
|
||||||
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
LD_PRELOAD="build/src/libfio_vitastor.so" \
|
||||||
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bs=4k -direct=1 -iodepth=16 -fsync=256 -rw=randwrite \
|
fio -thread -name=test -ioengine=build/src/libfio_vitastor.so -bsrange=4k-128k -direct=1 -iodepth=32 -fsync=256 -rw=randrw \
|
||||||
-mirror_file=./testdata/mirror.bin -etcd=$ETCD_URL -image=testimg -loops=10 -runtime=120
|
-randrepeat=0 -refill_buffers=1 -mirror_file=./testdata/mirror.bin -etcd=$ETCD_URL -image=testimg -loops=10 -runtime=120
|
||||||
|
|
||||||
qemu-img convert -S 4096 -p \
|
qemu-img convert -S 4096 -p \
|
||||||
-f raw "vitastor:etcd_host=127.0.0.1\:$ETCD_PORT/v3:image=testimg" \
|
-f raw "vitastor:etcd_host=127.0.0.1\:$ETCD_PORT/v3:image=testimg" \
|
||||||
|
Reference in New Issue
Block a user