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  }