1
2
3
4
5
6
7
8
9
10
11
12
13 package couchdb
14
15 import (
16 "bytes"
17 "context"
18 "encoding/json"
19 "net/http"
20
21 "github.com/go-kivik/kivik/v4/couchdb/chttp"
22 "github.com/go-kivik/kivik/v4/driver"
23 )
24
25 type dbStats struct {
26 driver.DBStats
27 Sizes struct {
28 File int64 `json:"file"`
29 External int64 `json:"external"`
30 Active int64 `json:"active"`
31 } `json:"sizes"`
32 UpdateSeq json.RawMessage `json:"update_seq"`
33 rawBody json.RawMessage
34 }
35
36 func (s *dbStats) UnmarshalJSON(p []byte) error {
37 type dbStatsClone dbStats
38 c := dbStatsClone(*s)
39 if err := json.Unmarshal(p, &c); err != nil {
40 return err
41 }
42 *s = dbStats(c)
43 s.rawBody = p
44 return nil
45 }
46
47 func (s *dbStats) driverStats() *driver.DBStats {
48 stats := &s.DBStats
49 if s.Sizes.File > 0 {
50 stats.DiskSize = s.Sizes.File
51 }
52 if s.Sizes.External > 0 {
53 stats.ExternalSize = s.Sizes.External
54 }
55 if s.Sizes.Active > 0 {
56 stats.ActiveSize = s.Sizes.Active
57 }
58 stats.UpdateSeq = string(bytes.Trim(s.UpdateSeq, `"`))
59 stats.RawResponse = s.rawBody
60 return stats
61 }
62
63 func (d *db) Stats(ctx context.Context) (*driver.DBStats, error) {
64 result := dbStats{}
65 if err := d.Client.DoJSON(ctx, http.MethodGet, d.dbName, nil, &result); err != nil {
66 return nil, err
67 }
68 return result.driverStats(), nil
69 }
70
71 type dbsInfoRequest struct {
72 Keys []string `json:"keys"`
73 }
74
75 type dbsInfoResponse struct {
76 Key string `json:"key"`
77 DBInfo dbStats `json:"info"`
78 Error string `json:"error"`
79 }
80
81 func (c *client) DBsStats(_ context.Context, dbnames []string) ([]*driver.DBStats, error) {
82 opts := &chttp.Options{
83 GetBody: chttp.BodyEncoder(dbsInfoRequest{Keys: dbnames}),
84 Header: http.Header{
85 chttp.HeaderIdempotencyKey: []string{},
86 },
87 }
88 result := []dbsInfoResponse{}
89 err := c.DoJSON(context.Background(), http.MethodPost, "/_dbs_info", opts, &result)
90 if err != nil {
91 return nil, err
92 }
93 stats := make([]*driver.DBStats, len(result))
94 for i := range result {
95 if result[i].Error == "" {
96 stats[i] = result[i].DBInfo.driverStats()
97 }
98 }
99 return stats, nil
100 }
101
102 func (c *client) AllDBsStats(ctx context.Context, options driver.Options) ([]*driver.DBStats, error) {
103 opts := map[string]interface{}{}
104 options.Apply(opts)
105 chttpOpts := &chttp.Options{
106 Header: http.Header{
107 chttp.HeaderIdempotencyKey: []string{},
108 },
109 }
110 var err error
111 chttpOpts.Query, err = optionsToParams(opts)
112 if err != nil {
113 return nil, err
114 }
115 result := []dbsInfoResponse{}
116 if err := c.DoJSON(ctx, http.MethodGet, "/_dbs_info", chttpOpts, &result); err != nil {
117 return nil, err
118 }
119 stats := make([]*driver.DBStats, len(result))
120 for i := range result {
121 stats[i] = result[i].DBInfo.driverStats()
122 }
123 return stats, nil
124 }
125
126 type partitionStats struct {
127 DBName string `json:"db_name"`
128 DocCount int64 `json:"doc_count"`
129 DocDelCount int64 `json:"doc_del_count"`
130 Partition string `json:"partition"`
131 Sizes struct {
132 Active int64 `json:"active"`
133 External int64 `json:"external"`
134 }
135 rawBody json.RawMessage
136 }
137
138 func (s *partitionStats) UnmarshalJSON(p []byte) error {
139 c := struct {
140 partitionStats
141 UnmarshalJSON struct{}
142 }{}
143 if err := json.Unmarshal(p, &c); err != nil {
144 return err
145 }
146 *s = c.partitionStats
147 s.rawBody = p
148 return nil
149 }
150
151 func (d *db) PartitionStats(ctx context.Context, name string) (*driver.PartitionStats, error) {
152 result := partitionStats{}
153 if err := d.Client.DoJSON(ctx, http.MethodGet, d.path("_partition/"+name), nil, &result); err != nil {
154 return nil, err
155 }
156 return &driver.PartitionStats{
157 DBName: result.DBName,
158 DocCount: result.DocCount,
159 DeletedDocCount: result.DocDelCount,
160 Partition: result.Partition,
161 ActiveSize: result.Sizes.Active,
162 ExternalSize: result.Sizes.External,
163 RawResponse: result.rawBody,
164 }, nil
165 }
166
View as plain text