mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-28 12:03:33 +00:00
96 lines
3.0 KiB
Go
96 lines
3.0 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/psviderski/uncloud/pkg/distlock"
|
|
distlockgrpc "github.com/psviderski/uncloud/pkg/distlock/grpc"
|
|
"google.golang.org/protobuf/types/known/durationpb"
|
|
)
|
|
|
|
// NewLocker creates a distlock.Locker that acquires automatically renewed distributed leases over the machines
|
|
// in the cluster. The Locker uses the client's connection, so callers must release its active leases before closing
|
|
// the client.
|
|
func (cli *Client) NewLocker(config distlock.Config) (*distlock.Locker, error) {
|
|
return distlock.New(&lockCluster{client: cli}, config)
|
|
}
|
|
|
|
type lockCluster struct {
|
|
client *Client
|
|
}
|
|
|
|
var _ distlock.Cluster = (*lockCluster)(nil)
|
|
|
|
// Nodes returns a point-in-time snapshot of the registered machines in the cluster, including temporarily unavailable
|
|
// ones. The Locker calls Nodes at the start of each Acquire and retains the returned snapshot across acquisition
|
|
// retries and for the lifetime of any acquired lease.
|
|
//
|
|
// Adding or removing machines, combined with eventual replication of the machine list, can cause different
|
|
// acquisitions to use different snapshots while active leases continue using older ones. This adapter does not
|
|
// version snapshots or coordinate membership transitions. If old and new snapshots allow disjoint quorums, two
|
|
// clients can acquire leases for the same resource. Membership changes must preserve quorum overlap while leases from
|
|
// older snapshots may remain valid.
|
|
func (c *lockCluster) Nodes(ctx context.Context) ([]distlock.Node, error) {
|
|
machines, err := c.client.ListMachines(ctx, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list machines: %w", err)
|
|
}
|
|
|
|
nodes := make([]distlock.Node, 0, len(machines))
|
|
for _, m := range machines {
|
|
nodes = append(nodes, &lockNode{
|
|
id: m.Machine.Id,
|
|
leases: c.client.leases,
|
|
})
|
|
}
|
|
return nodes, nil
|
|
}
|
|
|
|
type lockNode struct {
|
|
id string
|
|
leases distlockgrpc.LeaseClient
|
|
}
|
|
|
|
var _ distlock.Node = (*lockNode)(nil)
|
|
|
|
func (n *lockNode) Acquire(
|
|
ctx context.Context, resource string, token []byte, ttl time.Duration,
|
|
) (bool, error) {
|
|
resp, err := n.leases.Acquire(ProxySingleMachineContext(ctx, n.id), &distlockgrpc.AcquireLeaseRequest{
|
|
Resource: resource,
|
|
Token: token,
|
|
Ttl: durationpb.New(ttl),
|
|
})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Acquired, nil
|
|
}
|
|
|
|
func (n *lockNode) Renew(
|
|
ctx context.Context, resource string, token []byte, ttl time.Duration,
|
|
) (bool, error) {
|
|
resp, err := n.leases.Renew(ProxySingleMachineContext(ctx, n.id), &distlockgrpc.RenewLeaseRequest{
|
|
Resource: resource,
|
|
Token: token,
|
|
Ttl: durationpb.New(ttl),
|
|
})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Renewed, nil
|
|
}
|
|
|
|
func (n *lockNode) Release(ctx context.Context, resource string, token []byte) (bool, error) {
|
|
resp, err := n.leases.Release(ProxySingleMachineContext(ctx, n.id), &distlockgrpc.ReleaseLeaseRequest{
|
|
Resource: resource,
|
|
Token: token,
|
|
})
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return resp.Released, nil
|
|
}
|