// // DISCLAIMER // // Copyright 2018-2021 ArangoDB GmbH, Cologne, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Copyright holder is ArangoDB GmbH, Cologne, Germany // // Author Ewout Prangsma // Author Tomasz Mielech // package driver import ( "context" "errors" "path" "strconv" "sync/atomic" "time" ) // Content of the create batch resp type batchMetadata struct { // ID of the batch ID string `json:"id"` // Last Tick reported by the server LastTickInt Tick `json:"lastTick,omitempty"` cl *client serverID int64 database string closed int32 } // ErrBatchClosed occurs when there is an attempt closing or prolonging closed batch var ErrBatchClosed = errors.New("Batch already closed") // CreateBatch creates a "batch" to prevent WAL file removal and to take a snapshot func (c *client) CreateBatch(ctx context.Context, db Database, serverID int64, ttl time.Duration) (Batch, error) { req, err := c.conn.NewRequest("POST", path.Join("_db", db.Name(), "_api/replication/batch")) if err != nil { return nil, WithStack(err) } req = req.SetQuery("serverId", strconv.FormatInt(serverID, 10)) params := struct { TTL float64 `json:"ttl"` }{TTL: ttl.Seconds()} // just use a default ttl value req, err = req.SetBody(params) if err != nil { return nil, WithStack(err) } resp, err := c.conn.Do(ctx, req) if err != nil { return nil, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return nil, WithStack(err) } var batch batchMetadata if err := resp.ParseBody("", &batch); err != nil { return nil, WithStack(err) } batch.cl = c batch.serverID = serverID batch.database = db.Name() return &batch, nil } // Get the inventory of a server containing all collections (with entire details) of a database. func (c *client) DatabaseInventory(ctx context.Context, db Database) (DatabaseInventory, error) { req, err := c.conn.NewRequest("GET", path.Join("_db", db.Name(), "_api/replication/inventory")) if err != nil { return DatabaseInventory{}, WithStack(err) } applyContextSettings(ctx, req) resp, err := c.conn.Do(ctx, req) if err != nil { return DatabaseInventory{}, WithStack(err) } if err := resp.CheckStatus(200); err != nil { return DatabaseInventory{}, WithStack(err) } var result DatabaseInventory if err := resp.ParseBody("", &result); err != nil { return DatabaseInventory{}, WithStack(err) } return result, nil } // BatchID reported by the server // The receiver is pointer because this struct contains the field `closed` and it can not be copied // because race detector will complain. func (b *batchMetadata) BatchID() string { return b.ID } // LastTick reported by the server for this batch // The receiver is pointer because this struct contains the field `closed` and it can not be copied // because race detector will complain. func (b *batchMetadata) LastTick() Tick { return b.LastTickInt } // Extend the lifetime of an existing batch on the server func (b *batchMetadata) Extend(ctx context.Context, ttl time.Duration) error { if !atomic.CompareAndSwapInt32(&b.closed, 0, 0) { return WithStack(ErrBatchClosed) } req, err := b.cl.conn.NewRequest("PUT", path.Join("_db", b.database, "_api/replication/batch", b.ID)) if err != nil { return WithStack(err) } req = req.SetQuery("serverId", strconv.FormatInt(b.serverID, 10)) input := struct { TTL int64 `json:"ttl"` }{ TTL: int64(ttl.Seconds()), } req, err = req.SetBody(input) if err != nil { return WithStack(err) } resp, err := b.cl.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(204); err != nil { return WithStack(err) } return nil } // Delete an existing dump batch func (b *batchMetadata) Delete(ctx context.Context) error { if !atomic.CompareAndSwapInt32(&b.closed, 0, 1) { return WithStack(ErrBatchClosed) } req, err := b.cl.conn.NewRequest("DELETE", path.Join("_db", b.database, "_api/replication/batch", b.ID)) if err != nil { return WithStack(err) } resp, err := b.cl.conn.Do(ctx, req) if err != nil { return WithStack(err) } if err := resp.CheckStatus(204); err != nil { return WithStack(err) } return nil }