github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/pehrest/hash-transaction-register.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package pehrest 4 5 import ( 6 "../authorization" 7 "../ganjine" 8 "../protocol" 9 "../srpc" 10 "../syllab" 11 ) 12 13 // HashTransactionRegisterService store details about HashTransactionRegister service 14 var HashTransactionRegisterService = service.Service{ 15 URN: "urn:giti:index.protocol:service:hash-transaction-register", 16 Domain: DomainName, 17 ID: 8526423448282596109, 18 IssueDate: 1587282740, 19 ExpiryDate: 0, 20 ExpireInFavorOfURN: "", 21 ExpireInFavorOfID: 0, 22 Status: protocol.Software_PreAlpha, 23 24 Authorization: authorization.Service{ 25 CRUD: authorization.CRUDCreate, 26 UserType: protocol.UserType_App, 27 }, 28 29 Detail: map[protocol.LanguageID]service.ServiceDetail{ 30 protocol.LanguageEnglish: { 31 Name: "Index Hash - Transaction Register", 32 Description: `Register new transaction on queue and get last record when transaction ready for this one! 33 Requester must send FinishTransaction() immediately, otherwise Transaction manager will drop this request from queue and chain! 34 transaction write can be on secondary indexes not primary indexes, due to primary index must always unique! 35 transaction manager on any node in a replication must sync with master replication corresponding node manager! 36 Get a record by ID when record ready to submit! Usually use in transaction queue to act when record ready to read! 37 Must send this request to specific node that handle that range!!`, 38 TAGS: []string{"transactional authority", "index lock ticket"}, 39 }, 40 }, 41 42 SRPCHandler: HashTransactionRegisterSRPC, 43 } 44 45 // HashTransactionRegister register new transaction on queue and get last record when transaction ready for this one! 46 func HashTransactionRegister(req *HashTransactionRegisterReq) (res *HashTransactionRegisterRes, err protocol.Error) { 47 var node protocol.ApplicationNode 48 node, err = protocol.App.GetNodeByStorage(req.MediaTypeID, req.IndexKey) 49 if err != nil { 50 return 51 } 52 53 if node.Node.State == protocol.ApplicationState_LocalNode { 54 res, err = HashTransactionRegister(req) 55 return 56 } 57 58 var st protocol.Stream 59 st, err = node.Conn.MakeOutcomeStream(0) 60 if err != nil { 61 return 62 } 63 64 st.Service = &HashTransactionRegisterService 65 st.OutcomePayload = req.ToSyllab() 66 67 err = node.Conn.Send(st) 68 if err != nil { 69 return 70 } 71 72 res = &HashTransactionRegisterRes{} 73 res.FromSyllab(srpc.GetPayload(st.IncomePayload)) 74 return 75 } 76 77 // HashTransactionRegisterSRPC is sRPC handler of HashTransactionRegister service. 78 func HashTransactionRegisterSRPC(st protocol.Stream) { 79 if st.Connection.UserID != protocol.OS.AppManifest().AppUUID() { 80 // TODO::: Attack?? 81 err = authorization.ErrUserNotAllow 82 return 83 } 84 85 var req = &HashTransactionRegisterReq{} 86 req.FromSyllab(srpc.GetPayload(st.IncomePayload)) 87 88 var res *HashTransactionRegisterRes 89 res, err = HashTransactionRegister(req) 90 if err != nil { 91 return 92 } 93 94 st.OutcomePayload = res.ToSyllab() 95 } 96 97 // HashTransactionRegisterReq is request structure of HashTransactionRegister() 98 type HashTransactionRegisterReq struct { 99 Type ganjine.RequestType 100 IndexKey [32]byte 101 RecordID [32]byte 102 } 103 104 // HashTransactionRegisterRes is response structure of HashTransactionRegister() 105 type HashTransactionRegisterRes struct { 106 Record []byte 107 } 108 109 // HashTransactionRegister register new transaction on queue and get last record when transaction ready for this one! 110 func HashTransactionRegister(req *HashTransactionRegisterReq) (res *HashTransactionRegisterRes, err protocol.Error) { 111 res = &HashTransactionRegisterRes{} 112 113 if req.Type == ganjine.RequestTypeBroadcast { 114 // tell other node that this node handle request and don't send this request to other nodes! 115 req.Type = ganjine.RequestTypeStandalone 116 var reqEncoded = req.ToSyllab() 117 118 // send request to other related nodes 119 for i := 1; i < len(ganjine.Cluster.Replications.Zones); i++ { 120 var conn = ganjine.Cluster.Replications.Zones[i].Nodes[ganjine.Cluster.Node.ID].Conn 121 var st protocol.Stream 122 st, err = conn.MakeOutcomeStream(0) 123 if err != nil { 124 // TODO::: Can we easily return error if two nodes did their job and not have enough resource to send request to final node?? 125 return 126 } 127 128 st.Service = &service.Service{ID: 8526423448282596109} 129 st.OutcomePayload = reqEncoded 130 131 err = conn.Send(st) 132 if err != nil { 133 // TODO::: Can we easily return error if two nodes do their job and just one node connection lost?? 134 return 135 } 136 137 // TODO::: Can we easily return response error without handle some known situations?? 138 err = err 139 } 140 141 // Do for i=0 as local node 142 res.Record, err = ganjine.Cluster.TransactionManager.RegisterTransaction(req.IndexKey, req.RecordID) 143 } else { 144 // Don't send last record due to Master node will give it to requester! 145 _, err = ganjine.Cluster.TransactionManager.RegisterTransaction(req.IndexKey, req.RecordID) 146 } 147 148 return 149 } 150 151 /* 152 -- Syllab Encoder & Decoder -- 153 */ 154 155 // FromSyllab decode from buf to req 156 // Due to this service just use internally, It skip check buf size syllab rule! Panic occur if bad request received! 157 func (req *HashTransactionRegisterReq) FromSyllab(payload []byte, stackIndex uint32) { 158 req.Type = ganjine.RequestType(syllab.GetUInt8(buf, 0)) 159 copy(req.IndexKey[:], buf[1:]) 160 copy(req.RecordID[:], buf[33:]) 161 return 162 } 163 164 // ToSyllab encode req to buf 165 func (req *HashTransactionRegisterReq) ToSyllab(payload []byte, stackIndex, heapIndex uint32) (freeHeapIndex uint32) { 166 buf = make([]byte, req.LenAsSyllab()+4) // +4 for sRPC ID instead get offset argument 167 syllab.SetUInt8(buf, 4, uint8(req.Type)) 168 copy(buf[5:], req.IndexKey[:]) 169 copy(buf[37:], req.RecordID[:]) 170 return 171 } 172 173 func (req *HashTransactionRegisterReq) LenOfSyllabStack() uint32 { 174 return 65 175 } 176 177 func (req *HashTransactionRegisterReq) LenOfSyllabHeap() (ln uint32) { 178 return 179 } 180 181 func (req *HashTransactionRegisterReq) LenAsSyllab() uint64 { 182 return uint64(req.LenOfSyllabStack() + req.LenOfSyllabHeap()) 183 } 184 185 // FromSyllab decode from buf to req 186 // Due to this service just use internally, It skip check buf size syllab rule! Panic occur if bad request received! 187 func (res *HashTransactionRegisterRes) FromSyllab(payload []byte, stackIndex uint32) { 188 // Due to just have one field in res structure we break syllab rules and skip get address and size of res.Record from buf 189 res.Record = buf 190 return 191 } 192 193 // ToSyllab encode req to buf 194 func (res *HashTransactionRegisterRes) ToSyllab(payload []byte, stackIndex, heapIndex uint32) (freeHeapIndex uint32) { 195 // Due to just have one field in res structure we break syllab rules and skip set address and size of res.Record in buf 196 // syllab.SetUInt32(buf, 4, res.LenOfSyllabStack()) 197 // syllab.SetUInt32(buf, 8, uint32(len(res.Record))) 198 copy(buf[4:], res.Record) 199 return 200 } 201 202 func (res *HashTransactionRegisterRes) LenOfSyllabStack() uint32 { 203 return 0 204 } 205 206 func (res *HashTransactionRegisterRes) LenOfSyllabHeap() (ln uint32) { 207 ln = uint32(len(res.Record)) 208 return 209 } 210 211 func (res *HashTransactionRegisterRes) LenAsSyllab() uint64 { 212 return uint64(res.LenOfSyllabStack() + res.LenOfSyllabHeap()) 213 }