blob: 86c6019f35245b73b2ad5f8d8d4b634d4fef86fc [file] [log] [blame]
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05301/*
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05002 * Copyright 2020-2023 Open Networking Foundation (ONF) and the ONF Contributors
Himani Chawla2ba1c9c2020-10-07 13:19:03 +05303
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package transientstate
18
19import (
20 "context"
21 "fmt"
22 "sync"
23
khenaidood948f772021-08-11 17:49:24 -040024 "github.com/opencord/voltha-protos/v5/go/core"
25
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053026 "github.com/opencord/voltha-go/db/model"
khenaidood948f772021-08-11 17:49:24 -040027 "github.com/opencord/voltha-lib-go/v7/pkg/log"
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053028 "google.golang.org/grpc/codes"
29 "google.golang.org/grpc/status"
30)
31
32// Loader hides all low-level locking & synchronization related to device transient state updates
33type Loader struct {
34 dbProxy *model.Proxy
35 // this lock protects the device transient state
36 lock sync.RWMutex
37 deviceTransientState *data
38}
39
40type data struct {
khenaidood948f772021-08-11 17:49:24 -040041 transientState core.DeviceTransientState_Types
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053042 deviceID string
43}
44
45func NewLoader(dbProxy *model.Proxy, deviceID string) *Loader {
46 return &Loader{
47 dbProxy: dbProxy,
48 deviceTransientState: &data{
khenaidood948f772021-08-11 17:49:24 -040049 transientState: core.DeviceTransientState_NONE,
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053050 deviceID: deviceID,
51 },
52 }
53}
54
55// Load queries existing transient state from the kv,
56// and should only be called once when first created.
57func (loader *Loader) Load(ctx context.Context) {
58 loader.lock.Lock()
59 defer loader.lock.Unlock()
60
khenaidood948f772021-08-11 17:49:24 -040061 var deviceTransientState core.DeviceTransientState
khenaidoo7585a962021-06-10 16:15:38 -040062 have, err := loader.dbProxy.Get(ctx, loader.deviceTransientState.deviceID, &deviceTransientState)
63 if err != nil {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053064 logger.Errorw(ctx, "failed-to-get-device-transient-state-from-cluster-data-proxy", log.Fields{"error": err})
65 return
66 }
khenaidoo7585a962021-06-10 16:15:38 -040067 if have {
68 loader.deviceTransientState.transientState = deviceTransientState.TransientState
69 return
70 }
khenaidood948f772021-08-11 17:49:24 -040071 loader.deviceTransientState.transientState = core.DeviceTransientState_NONE
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053072}
73
74// Lock acquires the lock for deviceTransientStateLoader, and returns a handle
75// which can be used to access it until it's unlocked.
76// This handle ensures that the deviceTransientState cannot be accessed if the lock is not held.
77// TODO: consider accepting a ctx and aborting the lock attempt on cancellation
78func (loader *Loader) Lock() *Handle {
79 loader.lock.Lock()
80 dataTransientState := loader.deviceTransientState
81 return &Handle{loader: loader, data: dataTransientState}
82}
83
84// Handle is allocated for each Lock() call, all modifications are made using it, and it is invalidated by Unlock()
85// This enforces correct Lock()-Usage()-Unlock() ordering.
86type Handle struct {
87 loader *Loader
88 data *data
89}
90
91// GetReadOnly returns device transient which MUST NOT be modified externally, but which is safe to keep indefinitely
khenaidood948f772021-08-11 17:49:24 -040092func (h *Handle) GetReadOnly() core.DeviceTransientState_Types {
Himani Chawla2ba1c9c2020-10-07 13:19:03 +053093 return h.data.transientState
94}
95
96// Update updates device transient state in KV store
97// The provided device transient state must not be modified afterwards.
khenaidood948f772021-08-11 17:49:24 -040098func (h *Handle) Update(ctx context.Context, state core.DeviceTransientState_Types) error {
99 var tState core.DeviceTransientState
Himani Chawla2ba1c9c2020-10-07 13:19:03 +0530100 tState.TransientState = state
101 if err := h.loader.dbProxy.Set(ctx, fmt.Sprint(h.data.deviceID), &tState); err != nil {
102 return status.Errorf(codes.Internal, "failed-to-update-device-%v-transient-state: %s", h.data.deviceID, err)
103 }
104 h.data.transientState = state
105 return nil
106}
107
108// Delete deletes device transient state from KV store
109func (h *Handle) Delete(ctx context.Context) error {
110 if err := h.loader.dbProxy.Remove(ctx, fmt.Sprint(h.data.deviceID)); err != nil {
111 return status.Errorf(codes.Internal, "failed-to-delete-device-%v-transient-state: %s", h.data.deviceID, err)
112 }
113 return nil
114}
115
116// UnLock releases the lock on the device transient state.
117func (h *Handle) UnLock() {
118 defer h.loader.lock.Unlock()
119 h.data = nil
120}