RICPLT-2801, RICPLT-2802
[ric-plt/submgr.git] / pkg / control / tracker.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package control
21
22 import (
23         "fmt"
24         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
25         "sync"
26 )
27
28 type TransactionKey struct {
29         SubID     uint16 // subscription id / sequence number
30         TransType Action // action ongoing (CREATE/DELETE etc)
31 }
32
33 type TransactionXappKey struct {
34         Addr string // xapp addr
35         Port uint16 // xapp port
36         Xid  string // xapp xid in req
37 }
38
39 type Transaction struct {
40         tracker           *Tracker           // tracker instance
41         Key               TransactionKey     // action key
42         Xappkey           TransactionXappKey // transaction key
43         OrigParams        *xapp.RMRParams    // request orginal params
44         RespReceived      bool
45         ForwardRespToXapp bool
46 }
47
48 func (t *Transaction) SubRouteInfo() SubRouteInfo {
49         return SubRouteInfo{t.Key.TransType, t.Xappkey.Addr, t.Xappkey.Port, t.Key.SubID}
50 }
51
52 /*
53 Implements a record of ongoing transactions and helper functions to CRUD the records.
54 */
55 type Tracker struct {
56         transactionTable     map[TransactionKey]*Transaction
57         transactionXappTable map[TransactionXappKey]*Transaction
58         mutex                sync.Mutex
59 }
60
61 func (t *Tracker) Init() {
62         t.transactionTable = make(map[TransactionKey]*Transaction)
63         t.transactionXappTable = make(map[TransactionXappKey]*Transaction)
64 }
65
66 /*
67 Checks if a tranascation with similar type has been ongoing. If not then creates one.
68 Returns error if there is similar transatcion ongoing.
69 */
70 func (t *Tracker) TrackTransaction(subID uint16, act Action, addr string, port uint16, params *xapp.RMRParams, respReceived bool, forwardRespToXapp bool) (*Transaction, error) {
71         key := TransactionKey{subID, act}
72         xappkey := TransactionXappKey{addr, port, params.Xid}
73         trans := &Transaction{t, key, xappkey, params, respReceived, forwardRespToXapp}
74         t.mutex.Lock()
75         defer t.mutex.Unlock()
76         if _, ok := t.transactionTable[key]; ok {
77                 // TODO: Implement merge related check here. If the key is same but the value is different.
78                 err := fmt.Errorf("transaction tracker: Similar transaction with sub id %d and type %s is ongoing", key.SubID, key.TransType)
79                 return nil, err
80         }
81         if _, ok := t.transactionXappTable[xappkey]; ok {
82                 // TODO: Implement merge related check here. If the key is same but the value is different.
83                 err := fmt.Errorf("transaction tracker: Similar transaction with xapp key %v is ongoing", xappkey)
84                 return nil, err
85         }
86         t.transactionTable[key] = trans
87         t.transactionXappTable[xappkey] = trans
88         return trans, nil
89 }
90
91 /*
92 Retreives the transaction table entry for the given request. Controls that only one response is sent to xapp.
93 Returns error in case the transaction cannot be found.
94 */
95 func (t *Tracker) RetriveTransaction(subID uint16, act Action) (*Transaction, error) {
96         key := TransactionKey{subID, act}
97         t.mutex.Lock()
98         defer t.mutex.Unlock()
99         if trans, ok := t.transactionTable[key]; ok {
100                 return trans, nil
101         }
102         err := fmt.Errorf("transaction record for Subscription ID %d and action %s does not exist", subID, act)
103         return nil, err
104 }
105
106 /*
107 Deletes the transaction table entry for the given request and returns the deleted xapp's address and port for reference.
108 Returns error in case the transaction cannot be found.
109 */
110 func (t *Tracker) completeTransaction(subID uint16, act Action) (*Transaction, error) {
111         key := TransactionKey{subID, act}
112         t.mutex.Lock()
113         defer t.mutex.Unlock()
114         if trans, ok1 := t.transactionTable[key]; ok1 {
115                 if _, ok2 := t.transactionXappTable[trans.Xappkey]; ok2 {
116                         delete(t.transactionXappTable, trans.Xappkey)
117                 }
118                 delete(t.transactionTable, key)
119                 return trans, nil
120         }
121         err := fmt.Errorf("transaction record for Subscription ID %d and action %s does not exist", subID, act)
122         return nil, err
123 }
124
125 /*
126 Makes possible to to detect has response already received from BTS
127 Returns error in case the transaction cannot be found.
128 */
129 func (t *Tracker) CheckResponseReceived(subID uint16, act Action) (*Transaction, bool, error) {
130         key := TransactionKey{subID, act}
131         t.mutex.Lock()
132         defer t.mutex.Unlock()
133         if trans, ok := t.transactionTable[key]; ok {
134                 if trans.RespReceived == false {
135                         trans.RespReceived = true
136                         // This is used to control that only one response action (success response, failure or timer) is excecuted for the transaction
137                         return trans, false, nil
138                 }
139                 return trans, true, nil
140         }
141         err := fmt.Errorf("transaction record for Subscription ID %d and action %s does not exist", subID, act)
142         return nil, false, err
143 }
144
145 /*
146 Makes possible to receive response to retransmitted request to BTS
147 Returns error in case the transaction cannot be found.
148 */
149 func (t *Tracker) RetryTransaction(subID uint16, act Action) error {
150         key := TransactionKey{subID, act}
151         t.mutex.Lock()
152         defer t.mutex.Unlock()
153         if trans, ok := t.transactionTable[key]; ok {
154                 trans.RespReceived = false
155                 return nil
156         }
157         err := fmt.Errorf("transaction record for Subscription ID %d and action %s does not exist", subID, act)
158         return err
159 }