Merge branch '3.x' into HEAD

This commit is contained in:
Sveta Smirnova
2025-03-13 02:24:07 +03:00
15 changed files with 312 additions and 113 deletions

View File

@@ -36,7 +36,7 @@ jobs:
vuln-type: 'os,library'
severity: 'CRITICAL,HIGH'
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4.6.0
uses: actions/upload-artifact@v4.6.1
with:
name: binaries
path: bin/*

View File

@@ -9912,7 +9912,7 @@ sub main {
);
}
if ( my $alter = $o->get('alter') ) {
if ( (my $alter = $o->get('alter')) && !$o->get('resume') ) {
print "Altering new table...\n";
my $sql = "ALTER TABLE $new_tbl->{name} $alter";
print $sql, "\n" if $o->get('print');

View File

@@ -19,7 +19,14 @@ Were always excited to connect and improve everyone's experience.
Work with a Percona Expert
==============================
`Percona experts <https://www.percona.com/services/consulting>`_ bring years of experience in tackling tough database performance issues and design challenges. We understand your challenges when managing complex database environments. That's why we offer various services to help you simplify your operations and achieve your goals.
Percona experts bring years of experience in tackling tough database performance issues and design challenges.
.. raw:: html
<div data-tf-live="01JKGY9435F75X6DHG92DJZB26"></div>
<script src="//embed.typeform.com/next/embed.js"></script>
We understand your challenges when managing complex database environments. That's why we offer various services to help you simplify your operations and achieve your goals.
+----------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Service | Description |

20
go.mod
View File

@@ -7,11 +7,11 @@ require (
github.com/Ladicle/tabwriter v1.0.0
github.com/Masterminds/semver v1.5.0
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/kong v1.6.1
github.com/alecthomas/kong v1.8.1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-ini/ini v1.67.0
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.6.0
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/hashicorp/go-version v1.7.0
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef
@@ -26,12 +26,12 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
github.com/xlab/treeprint v1.2.0
go.mongodb.org/mongo-driver v1.17.2
golang.org/x/crypto v0.32.0
go.mongodb.org/mongo-driver v1.17.3
golang.org/x/crypto v0.36.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.32.1
k8s.io/api v0.32.2
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
)
@@ -61,13 +61,13 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.32.1 // indirect
k8s.io/apimachinery v0.32.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect

40
go.sum
View File

@@ -8,8 +8,8 @@ github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8v
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/kong v1.6.1 h1:/7bVimARU3uxPD0hbryPE8qWrS3Oz3kPQoxA/H2NKG8=
github.com/alecthomas/kong v1.6.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/kong v1.8.1 h1:6aamvWBE/REnR/BCq10EcozmcpUPc5aGI1lPAWdB0EE=
github.com/alecthomas/kong v1.8.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@@ -38,8 +38,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -125,14 +125,14 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -153,8 +153,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -170,18 +170,18 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -205,10 +205,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=

View File

@@ -14,8 +14,8 @@ sphinxcontrib-srclinks
sphinx-tabs
certifi>=2024.7.4 # not directly required, pinned by Snyk to avoid a vulnerability
jinja2>=3.1.4 # not directly required, pinned by Snyk to avoid a vulnerability
jinja2>=3.1.6 # not directly required, pinned by Snyk to avoid a vulnerability
pygments>=2.15.0 # not directly required, pinned by Snyk to avoid a vulnerability
requests>=2.31.0 # not directly required, pinned by Snyk to avoid a vulnerability
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
setuptools>=70.0.0 # not directly required, pinned by Snyk to avoid a vulnerability
idna>=3.7 # not directly required, pinned by Snyk to avoid a vulnerability

View File

@@ -10,11 +10,12 @@ import (
"strings"
"testing"
"github.com/percona/percona-toolkit/src/go/lib/tutil"
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson"
"github.com/percona/percona-toolkit/src/go/lib/tutil"
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
)
const (
@@ -33,7 +34,8 @@ func TestMain(m *testing.M) {
log.Printf("cannot get root path: %s", err.Error())
os.Exit(1)
}
os.Exit(m.Run())
code := m.Run()
os.Exit(code)
}
func TestSingleFingerprint(t *testing.T) {

View File

@@ -7,14 +7,15 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson/primitive"
tu "github.com/percona/percona-toolkit/src/go/internal/testutils"
"github.com/percona/percona-toolkit/src/go/lib/tutil"
"github.com/percona/percona-toolkit/src/go/mongolib/fingerprinter"
"github.com/percona/percona-toolkit/src/go/mongolib/stats"
"github.com/percona/percona-toolkit/src/go/pt-mongodb-query-digest/filter"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
@@ -38,7 +39,8 @@ func TestMain(m *testing.M) {
log.Printf("cannot get root path: %s", err.Error())
os.Exit(1)
}
os.Exit(m.Run())
code := m.Run()
os.Exit(code)
}
func TestRegularIterator(t *testing.T) {

View File

@@ -13,8 +13,6 @@ type SystemProfile struct {
AllUsers []interface{} `bson:"allUsers"`
Client string `bson:"client"`
CursorExhausted bool `bson:"cursorExhausted"`
DocsExamined int `bson:"docsExamined"`
NscannedObjects int `bson:"nscannedObjects"`
ExecStats struct {
Advanced int `bson:"advanced"`
ExecutionTimeMillisEstimate int `bson:"executionTimeMillisEstimate"`
@@ -48,28 +46,37 @@ type SystemProfile struct {
SaveState int `bson:"saveState"`
Stage string `bson:"stage"`
Works int `bson:"works"`
DocsExamined int `bson:"docsExamined"`
} `bson:"execStats"`
KeyUpdates int `bson:"keyUpdates"`
KeysExamined int `bson:"keysExamined"`
Locks struct {
Collection struct {
AcquireCount struct {
R int `bson:"R"`
Read int `bson:"R"`
ReadShared int `bson:"r"`
} `bson:"acquireCount"`
} `bson:"Collection"`
Database struct {
AcquireCount struct {
R int `bson:"r"`
ReadShared int `bson:"r"`
} `bson:"acquireCount"`
AcquireWaitCount struct {
ReadShared int `bson:"r"`
} `bson:"acquireWaitCount"`
TimeAcquiringMicros struct {
ReadShared int64 `bson:"r"`
} `bson:"timeAcquiringMicros"`
} `bson:"Database"`
Global struct {
AcquireCount struct {
R int `bson:"r"`
ReadShared int `bson:"r"`
WriteShared int `bson:"w"`
} `bson:"acquireCount"`
} `bson:"Global"`
MMAPV1Journal struct {
AcquireCount struct {
R int `bson:"r"`
ReadShared int `bson:"r"`
} `bson:"acquireCount"`
} `bson:"MMAPV1Journal"`
} `bson:"locks"`
@@ -78,6 +85,7 @@ type SystemProfile struct {
Ns string `bson:"ns"`
NumYield int `bson:"numYield"`
Op string `bson:"op"`
PlanSummary string `bson:"planSummary"`
Protocol string `bson:"protocol"`
Query bson.D `bson:"query"`
UpdateObj bson.D `bson:"updateobj"`
@@ -87,6 +95,16 @@ type SystemProfile struct {
Ts time.Time `bson:"ts"`
User string `bson:"user"`
WriteConflicts int `bson:"writeConflicts"`
DocsExamined int `bson:"docsExamined"`
QueryHash string `bson:"queryHash"`
Storage struct {
Data struct {
BytesRead int64 `bson:"bytesRead"`
TimeReadingMicros int64 `bson:"timeReadingMicros"`
} `bson:"data"`
} `bson:"storage"`
AppName string `bson:"appName"`
Comments string `bson:"comments"`
}
func NewExampleQuery(doc SystemProfile) ExampleQuery {

View File

@@ -4,6 +4,7 @@ import (
"crypto/md5"
"fmt"
"sort"
"strings"
"sync"
"time"
@@ -13,6 +14,11 @@ import (
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
)
const (
planSummaryCollScan = "COLLSCAN"
planSummaryIXScan = "IXSCAN"
)
type StatsError struct {
error
}
@@ -86,18 +92,24 @@ func (s *Stats) Add(doc proto.SystemProfile) error {
Namespace: fp.Namespace,
TableScan: false,
Query: string(queryBson),
PlanSummary: doc.PlanSummary,
QueryHash: doc.QueryHash,
AppName: doc.AppName,
Client: doc.Client,
User: strings.Split(doc.User, "@")[0],
Comments: doc.Comments,
}
s.setQueryInfoAndCounters(key, qiac)
}
qiac.Count++
// docsExamined is renamed from nscannedObjects in 3.2.0.
// https://docs.mongodb.com/manual/reference/database-profiler/#system.profile.docsExamined
s.Lock()
if doc.NscannedObjects > 0 {
qiac.NScanned = append(qiac.NScanned, float64(doc.NscannedObjects))
} else {
qiac.NScanned = append(qiac.NScanned, float64(doc.DocsExamined))
if qiac.PlanSummary == planSummaryCollScan {
qiac.CollScanCount++
}
if strings.HasPrefix(qiac.PlanSummary, planSummaryIXScan) {
qiac.PlanSummary = planSummaryIXScan
}
qiac.NReturned = append(qiac.NReturned, float64(doc.Nreturned))
qiac.QueryTime = append(qiac.QueryTime, float64(doc.Millis))
qiac.ResponseLength = append(qiac.ResponseLength, float64(doc.ResponseLength))
@@ -107,6 +119,42 @@ func (s *Stats) Add(doc proto.SystemProfile) error {
if qiac.LastSeen.IsZero() || qiac.LastSeen.Before(doc.Ts) {
qiac.LastSeen = doc.Ts
}
if doc.DocsExamined > 0 {
qiac.DocsExamined = append(qiac.DocsExamined, float64(doc.DocsExamined))
}
if doc.KeysExamined > 0 {
qiac.KeysExamined = append(qiac.KeysExamined, float64(doc.KeysExamined))
}
if doc.Locks.Global.AcquireCount.ReadShared > 0 {
qiac.LocksGlobalAcquireCountReadSharedCount++
qiac.LocksGlobalAcquireCountReadShared += doc.Locks.Global.AcquireCount.ReadShared
}
if doc.Locks.Global.AcquireCount.WriteShared > 0 {
qiac.LocksGlobalAcquireCountWriteSharedCount++
qiac.LocksGlobalAcquireCountWriteShared += doc.Locks.Global.AcquireCount.WriteShared
}
if doc.Locks.Database.AcquireCount.ReadShared > 0 {
qiac.LocksDatabaseAcquireCountReadSharedCount++
qiac.LocksDatabaseAcquireCountReadShared += doc.Locks.Database.AcquireCount.ReadShared
}
if doc.Locks.Database.AcquireWaitCount.ReadShared > 0 {
qiac.LocksDatabaseAcquireWaitCountReadSharedCount++
qiac.LocksDatabaseAcquireWaitCountReadShared += doc.Locks.Database.AcquireWaitCount.ReadShared
}
if doc.Locks.Database.TimeAcquiringMicros.ReadShared > 0 {
qiac.LocksDatabaseTimeAcquiringMicrosReadShared = append(qiac.LocksDatabaseTimeAcquiringMicrosReadShared, float64(doc.Locks.Database.TimeAcquiringMicros.ReadShared))
}
if doc.Locks.Collection.AcquireCount.ReadShared > 0 {
qiac.LocksCollectionAcquireCountReadSharedCount++
qiac.LocksCollectionAcquireCountReadShared += doc.Locks.Collection.AcquireCount.ReadShared
}
if doc.Storage.Data.BytesRead > 0 {
qiac.StorageBytesRead = append(qiac.StorageBytesRead, float64(doc.Storage.Data.BytesRead))
}
if doc.Storage.Data.TimeReadingMicros > 0 {
qiac.StorageTimeReadingMicros = append(qiac.StorageTimeReadingMicros, float64(doc.Storage.Data.TimeReadingMicros))
}
s.Unlock()
return nil
@@ -185,9 +233,34 @@ type QueryInfoAndCounters struct {
BlockedTime Times
LockTime Times
NReturned []float64
NScanned []float64
QueryTime []float64 // in milliseconds
ResponseLength []float64
PlanSummary string
CollScanCount int
DocsExamined []float64
KeysExamined []float64
QueryHash string
AppName string
Client string
User string
Comments string
LocksGlobalAcquireCountReadSharedCount int
LocksGlobalAcquireCountReadShared int
LocksGlobalAcquireCountWriteSharedCount int
LocksGlobalAcquireCountWriteShared int
LocksDatabaseAcquireCountReadSharedCount int
LocksDatabaseAcquireCountReadShared int
LocksDatabaseAcquireWaitCountReadSharedCount int
LocksDatabaseAcquireWaitCountReadShared int
LocksDatabaseTimeAcquiringMicrosReadShared []float64 // in microseconds
LocksCollectionAcquireCountReadSharedCount int
LocksCollectionAcquireCountReadShared int
StorageBytesRead []float64
StorageTimeReadingMicros []float64 // in microseconds
}
// times is an array of time.Time that implements the Sorter interface
@@ -214,11 +287,15 @@ func (g GroupKey) String() string {
}
type totalCounters struct {
Count int
Scanned float64
Returned float64
QueryTime float64
Bytes float64
Count int
Returned float64
QueryTime float64
Bytes float64
DocsExamined float64
KeysExamined float64
LocksDatabaseTimeAcquiringMicrosReadShared float64
StorageBytesRead float64
StorageTimeReadingMicros float64
}
type QueryStats struct {
@@ -230,14 +307,44 @@ type QueryStats struct {
FirstSeen time.Time
LastSeen time.Time
Count int
QPS float64
Rank int
Ratio float64
QueryTime Statistics
ResponseLength Statistics
Returned Statistics
Scanned Statistics
Count int
QPS float64
Rank int
Ratio float64
QueryTime Statistics
ResponseLengthCount int
ResponseLength Statistics
Returned Statistics
PlanSummary string
CollScanCount int
DocsExaminedCount int
DocsExamined Statistics
KeysExaminedCount int
KeysExamined Statistics
QueryHash string
AppName string
Client string
User string
Comments string
LocksGlobalAcquireCountReadSharedCount int
LocksGlobalAcquireCountReadShared int
LocksGlobalAcquireCountWriteSharedCount int
LocksGlobalAcquireCountWriteShared int
LocksDatabaseAcquireCountReadSharedCount int
LocksDatabaseAcquireCountReadShared int
LocksDatabaseAcquireWaitCountReadSharedCount int
LocksDatabaseAcquireWaitCountReadShared int
LocksDatabaseTimeAcquiringMicrosReadSharedCount int
LocksDatabaseTimeAcquiringMicrosReadShared Statistics // in microseconds
LocksCollectionAcquireCountReadSharedCount int
LocksCollectionAcquireCountReadShared int
StorageBytesReadCount int
StorageBytesRead Statistics
StorageTimeReadingMicrosCount int
StorageTimeReadingMicros Statistics // in microseconds
}
type Statistics struct {
@@ -254,22 +361,46 @@ type Statistics struct {
func countersToStats(query QueryInfoAndCounters, uptime int64, tc totalCounters) QueryStats {
queryStats := QueryStats{
Count: query.Count,
ID: query.ID,
Operation: query.Operation,
Query: query.Query,
Fingerprint: query.Fingerprint,
Scanned: calcStats(query.NScanned),
Returned: calcStats(query.NReturned),
QueryTime: calcStats(query.QueryTime),
ResponseLength: calcStats(query.ResponseLength),
FirstSeen: query.FirstSeen,
LastSeen: query.LastSeen,
Namespace: query.Namespace,
QPS: float64(query.Count) / float64(uptime),
}
if tc.Scanned > 0 {
queryStats.Scanned.Pct = queryStats.Scanned.Total * 100 / tc.Scanned
Count: query.Count,
ID: query.ID,
Operation: query.Operation,
Query: query.Query,
Fingerprint: query.Fingerprint,
Returned: calcStats(query.NReturned),
QueryTime: calcStats(query.QueryTime),
FirstSeen: query.FirstSeen,
LastSeen: query.LastSeen,
Namespace: query.Namespace,
QPS: float64(query.Count) / float64(uptime),
PlanSummary: query.PlanSummary,
CollScanCount: query.CollScanCount,
ResponseLengthCount: len(query.ResponseLength),
ResponseLength: calcStats(query.ResponseLength),
DocsExaminedCount: len(query.DocsExamined),
DocsExamined: calcStats(query.DocsExamined),
KeysExaminedCount: len(query.KeysExamined),
KeysExamined: calcStats(query.KeysExamined),
QueryHash: query.QueryHash,
AppName: query.AppName,
Client: query.Client,
User: query.User,
Comments: query.Comments,
LocksGlobalAcquireCountReadSharedCount: query.LocksGlobalAcquireCountReadSharedCount,
LocksGlobalAcquireCountReadShared: query.LocksGlobalAcquireCountReadShared,
LocksGlobalAcquireCountWriteSharedCount: query.LocksGlobalAcquireCountWriteSharedCount,
LocksGlobalAcquireCountWriteShared: query.LocksGlobalAcquireCountWriteShared,
LocksDatabaseAcquireCountReadSharedCount: query.LocksDatabaseAcquireCountReadSharedCount,
LocksDatabaseAcquireCountReadShared: query.LocksDatabaseAcquireCountReadShared,
LocksDatabaseAcquireWaitCountReadSharedCount: query.LocksDatabaseAcquireWaitCountReadSharedCount,
LocksDatabaseAcquireWaitCountReadShared: query.LocksDatabaseAcquireWaitCountReadShared,
LocksDatabaseTimeAcquiringMicrosReadSharedCount: len(query.LocksDatabaseTimeAcquiringMicrosReadShared),
LocksDatabaseTimeAcquiringMicrosReadShared: calcStats(query.LocksDatabaseTimeAcquiringMicrosReadShared),
LocksCollectionAcquireCountReadSharedCount: query.LocksCollectionAcquireCountReadSharedCount,
LocksCollectionAcquireCountReadShared: query.LocksCollectionAcquireCountReadShared,
StorageBytesReadCount: len(query.StorageBytesRead),
StorageBytesRead: calcStats(query.StorageBytesRead),
StorageTimeReadingMicrosCount: len(query.StorageTimeReadingMicros),
StorageTimeReadingMicros: calcStats(query.StorageTimeReadingMicros),
}
if tc.Returned > 0 {
queryStats.Returned.Pct = queryStats.Returned.Total * 100 / tc.Returned
@@ -281,7 +412,22 @@ func countersToStats(query QueryInfoAndCounters, uptime int64, tc totalCounters)
queryStats.ResponseLength.Pct = queryStats.ResponseLength.Total * 100 / tc.Bytes
}
if queryStats.Returned.Total > 0 {
queryStats.Ratio = queryStats.Scanned.Total / queryStats.Returned.Total
queryStats.Ratio = queryStats.DocsExamined.Total / queryStats.Returned.Total
}
if tc.DocsExamined > 0 {
queryStats.DocsExamined.Pct = queryStats.DocsExamined.Total * 100 / tc.DocsExamined
}
if tc.KeysExamined > 0 {
queryStats.KeysExamined.Pct = queryStats.KeysExamined.Total * 100 / tc.KeysExamined
}
if tc.LocksDatabaseTimeAcquiringMicrosReadShared > 0 {
queryStats.LocksDatabaseTimeAcquiringMicrosReadShared.Pct = queryStats.LocksDatabaseTimeAcquiringMicrosReadShared.Total * 100 / tc.LocksDatabaseTimeAcquiringMicrosReadShared
}
if tc.StorageBytesRead > 0 {
queryStats.StorageBytesRead.Pct = queryStats.StorageBytesRead.Total * 100 / tc.StorageBytesRead
}
if tc.StorageTimeReadingMicros > 0 {
queryStats.StorageTimeReadingMicros.Pct = queryStats.StorageTimeReadingMicros.Total * 100 / tc.StorageTimeReadingMicros
}
return queryStats
@@ -291,10 +437,14 @@ func aggregateCounters(queries []QueryInfoAndCounters) QueryInfoAndCounters {
qt := QueryInfoAndCounters{}
for _, query := range queries {
qt.Count += query.Count
qt.NScanned = append(qt.NScanned, query.NScanned...)
qt.NReturned = append(qt.NReturned, query.NReturned...)
qt.QueryTime = append(qt.QueryTime, query.QueryTime...)
qt.ResponseLength = append(qt.ResponseLength, query.ResponseLength...)
qt.DocsExamined = append(qt.DocsExamined, query.DocsExamined...)
qt.KeysExamined = append(qt.KeysExamined, query.KeysExamined...)
qt.LocksDatabaseTimeAcquiringMicrosReadShared = append(qt.LocksDatabaseTimeAcquiringMicrosReadShared, query.LocksDatabaseTimeAcquiringMicrosReadShared...)
qt.StorageBytesRead = append(qt.StorageBytesRead, query.StorageBytesRead...)
qt.StorageTimeReadingMicros = append(qt.StorageTimeReadingMicros, query.StorageTimeReadingMicros...)
}
return qt
}
@@ -305,9 +455,6 @@ func calcTotalCounters(queries []QueryInfoAndCounters) totalCounters {
for _, query := range queries {
tc.Count += query.Count
scanned, _ := stats.Sum(query.NScanned)
tc.Scanned += scanned
returned, _ := stats.Sum(query.NReturned)
tc.Returned += returned
@@ -316,11 +463,30 @@ func calcTotalCounters(queries []QueryInfoAndCounters) totalCounters {
bytes, _ := stats.Sum(query.ResponseLength)
tc.Bytes += bytes
docsExamined, _ := stats.Sum(query.DocsExamined)
tc.DocsExamined += docsExamined
keysExamined, _ := stats.Sum(query.KeysExamined)
tc.KeysExamined += keysExamined
locksDatabaseTimeAcquiringMicrosReadShared, _ := stats.Sum(query.LocksDatabaseTimeAcquiringMicrosReadShared)
tc.LocksDatabaseTimeAcquiringMicrosReadShared += locksDatabaseTimeAcquiringMicrosReadShared
storageBytesRead, _ := stats.Sum(query.StorageBytesRead)
tc.StorageBytesRead += storageBytesRead
storageTimeReadingMicros, _ := stats.Sum(query.StorageTimeReadingMicros)
tc.StorageTimeReadingMicros += storageTimeReadingMicros
}
return tc
}
func calcStats(samples []float64) Statistics {
if len(samples) == 0 {
return Statistics{}
}
var s Statistics
s.Total, _ = stats.Sum(samples)
s.Min, _ = stats.Min(samples)

View File

@@ -14,6 +14,7 @@ import (
"time"
"github.com/golang/mock/gomock"
"github.com/percona/percona-toolkit/src/go/lib/tutil"
"github.com/percona/percona-toolkit/src/go/mongolib/fingerprinter"
"github.com/percona/percona-toolkit/src/go/mongolib/proto"
@@ -40,8 +41,8 @@ func TestMain(m *testing.M) {
log.Printf("cannot get root path: %s", err.Error())
os.Exit(1)
}
// TODO: Review with the new sandbox
// os.Exit(m.Run())
code := m.Run()
os.Exit(code)
}
func TestTimesLen(t *testing.T) {
@@ -158,9 +159,9 @@ func TestStats(t *testing.T) {
BlockedTime: nil,
LockTime: nil,
NReturned: []float64{0},
NScanned: []float64{10000},
QueryTime: []float64{7},
ResponseLength: []float64{215},
DocsExamined: []float64{10000},
}
want := Queries{

View File

@@ -54,7 +54,7 @@ Options
``-o``, ``--order-by``
Specifies the sorting order using fields:
``count``, ``ratio``, ``query-time``, ``docs-scanned``, ``docs-returned``.
``count``, ``ratio``, ``query-time``, ``docs-examined``, ``docs-returned``.
Adding a hyphen (``-``) in front of a field denotes reverse order.
For example: ``--order-by="count,-ratio"``.
@@ -94,13 +94,13 @@ Output Example
.. code-block:: none
# Query 3: 0.06 QPS, ID 0b906bd86148def663d11b402f3e41fa
# Ratio 1.00 (docs scanned/returned)
# Ratio 1.00 (docs examined/returned)
# Time range: 2017-02-03 16:01:37.484 -0300 ART to 2017-02-03 16:02:08.43 -0300 ART
# Attribute pct total min max avg 95% stddev median
# ================== === ======== ======== ======== ======== ======== ======= ========
# Count (docs) 100
# Exec Time ms 2 3 0 1 0 0 0 0
# Docs Scanned 5 7.50K 75.00 75.00 75.00 75.00 0.00 75.00
# Docs Examined 5 7.50K 75.00 75.00 75.00 75.00 0.00 75.00
# Docs Returned 92 7.50K 75.00 75.00 75.00 75.00 0.00 75.00
# Bytes recv 1 106.12M 1.06M 1.06M 1.06M 1.06M 0.00 1.06M
# String:

View File

@@ -497,23 +497,23 @@ func sortQueries(queries []stats.QueryStats, orderby []string) []stats.QueryStat
}
//
case "docs-scanned":
case "docs-examined":
f = func(c1, c2 *stats.QueryStats) bool {
return c1.Scanned.Max < c2.Scanned.Max
return c1.DocsExamined.Max < c2.DocsExamined.Max
}
case "-docs-scanned":
case "-docs-examined":
f = func(c1, c2 *stats.QueryStats) bool {
return c1.Scanned.Max > c2.Scanned.Max
return c1.DocsExamined.Max > c2.DocsExamined.Max
}
//
case "docs-returned":
f = func(c1, c2 *stats.QueryStats) bool {
return c1.Returned.Max < c2.Scanned.Max
return c1.Returned.Max < c2.DocsExamined.Max
}
case "-docs-returned":
f = func(c1, c2 *stats.QueryStats) bool {
return c1.Returned.Max > c2.Scanned.Max
return c1.Returned.Max > c2.DocsExamined.Max
}
}
// count,query-time,docs-scanned, docs-returned. - in front of the field name denotes reverse order.")

View File

@@ -32,7 +32,8 @@ var logger = logrus.New()
func TestMain(m *testing.M) {
logger.SetLevel(logrus.WarnLevel)
os.Exit(m.Run())
code := m.Run()
os.Exit(code)
}
func TestConnection(t *testing.T) {

View File

@@ -137,7 +137,7 @@ set_delay();
# We need to sleep, otherwise pt-osc can finish before replica is delayed
sleep($max_lag);
my $args = "$source_dsn,D=test,t=pt1717 --execute --chunk-size ${chunk_size} --max-lag $max_lag --alter 'engine=INNODB' --pid $tmp_file_name --progress time,5 --no-drop-new-table --no-drop-triggers --history";
my $args = "$source_dsn,D=test,t=pt1717 --execute --chunk-size ${chunk_size} --max-lag $max_lag --alter 'ADD COLUMN foo varchar(32)' --pid $tmp_file_name --progress time,5 --no-drop-new-table --no-drop-triggers --history";
$output = run_broken_job($args);
@@ -165,7 +165,7 @@ my @args = (qw(--execute --chunk-size=10 --history));
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=INNODB', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-index=f2'
) }
);
@@ -186,7 +186,7 @@ like(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--max-lag', $max_lag,
'--resume', $job_id,
'--alter', 'engine=INNODB',
'--alter', 'ADD COLUMN foo varchar(32)',
'--plugin', "$plugin/pt-1717.pm",
),
},
@@ -208,8 +208,10 @@ ok(
'All rows copied correctly'
) or diag("New table checksum: '${new_table_checksum}', original content checksum: '${old_table_checksum}'");
diag(`/tmp/12345/use test -N -e "ALTER TABLE pt1717 DROP COLUMN foo"`);
# Tests for chunk-index and chunk-index-columns options
$args = "$source_dsn,D=test,t=pt1717 --alter engine=innodb --execute --history --chunk-size=10 --no-drop-new-table --no-drop-triggers --reverse-triggers --chunk-index=f2";
$args = "$source_dsn,D=test,t=pt1717 --alter 'ADD COLUMN foo varchar(32)' --execute --history --chunk-size=10 --no-drop-new-table --no-drop-triggers --reverse-triggers --chunk-index=f2";
set_delay();
$output = run_broken_job($args);
@@ -220,7 +222,7 @@ $job_id = $1;
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
) }
);
@@ -238,7 +240,7 @@ like(
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-index=f1'
) }
);
@@ -257,7 +259,7 @@ like(
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-index=f2', '--chunk-index-columns=1'
) }
);
@@ -288,7 +290,7 @@ is(
$output + 0,
3,
'Triggers were not dropped'
);
) or diag($output);
$output = `/tmp/12345/use -N -e "select count(*) from information_schema.triggers where TRIGGER_SCHEMA='test' AND EVENT_OBJECT_TABLE like '%pt1717%_new' AND trigger_name LIKE 'rt_%'"`;
@@ -300,7 +302,7 @@ is(
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-size=4',
'--chunk-index=f2'
) }
@@ -348,7 +350,7 @@ ok(
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-size=4',
'--chunk-index=f2'
) }
@@ -372,7 +374,7 @@ $output =~ /New table `test`.`([_]+pt1717_new)` not found, restart operation fro
($output, $exit) = full_output(
sub { pt_online_schema_change::main(@args, "$source_dsn,D=test,t=pt1717",
'--alter', 'engine=innodb', '--execute', "--resume=${job_id}",
'--alter', 'ADD COLUMN foo varchar(32)', '--execute', "--resume=${job_id}",
'--chunk-size=4',
'--chunk-index=f2'
) }