Skip to content

Commit

Permalink
feat: use generic to make linked list usable for both chats and nodes (
Browse files Browse the repository at this point in the history
…#70)

* savings

* fix(storage): tests

* changes: finiesh fixing all tests

* feat: remove slot from storage if it is not used any more
  • Loading branch information
timtimjnvr authored Nov 11, 2023
1 parent d1159b6 commit 04cd77b
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 199 deletions.
100 changes: 50 additions & 50 deletions crdt/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import (
"encoding/json"
"github.com/google/uuid"
"github.com/pkg/errors"
"log"
"time"
)

type (
Chat struct {
Id uuid.UUID `json:"id"`
Name string `json:"name"`
nodesInfos []*NodeInfos
nodesSlots []uint8
messages []*Message // ordered by date : 0 being the oldest message, 1 coming after 0 etc ...
}
)
Expand All @@ -25,7 +24,7 @@ func NewChat(name string) *Chat {
return &Chat{
Id: uuid.New(),
Name: name,
nodesInfos: make([]*NodeInfos, 0, maxNumberOfNodes),
nodesSlots: make([]uint8, 0, maxNumberOfNodes),
messages: make([]*Message, 0, maxNumberOfMessages),
}
}
Expand All @@ -38,70 +37,67 @@ func (c *Chat) GetName() string {
return c.Name
}

func (c *Chat) SaveNode(nodeInfo *NodeInfos) {
// update if found
for i, n := range c.nodesInfos {
if n.Id == nodeInfo.Id {
c.nodesInfos[i] = nodeInfo
func (c *Chat) SaveNode(nodeSlot uint8) {

// check if present
for _, s := range c.nodesSlots {
if s == nodeSlot {
return
}
}

// append if not found
c.nodesInfos = append(c.nodesInfos, nodeInfo)
c.nodesSlots = append(c.nodesSlots, nodeSlot)
}

func (c *Chat) RemoveNodeBySlot(slot uint8) (string, error) {
func (c *Chat) RemoveNodeSlot(slot uint8) error {
// get index
var (
index int
found bool
n *NodeInfos
s uint8
)
for index, n = range c.nodesInfos {
if n.Slot == slot {

for index, s = range c.nodesSlots {
if s == slot {
found = true
break
}
}

if !found {
return "", NotFoundErr
return NotFoundErr
}

nodeName := c.nodesInfos[index].Name

if index == 0 && len(c.nodesInfos) == 1 {
c.nodesInfos = make([]*NodeInfos, 0, 0)
return nodeName, nil
if index == 0 && len(c.nodesSlots) == 1 {
c.nodesSlots = make([]uint8, 0, 0)
return nil
}

if index == 0 && len(c.nodesInfos) > 1 {
c.nodesInfos = c.nodesInfos[index+1:]
return nodeName, nil
if index == 0 && len(c.nodesSlots) > 1 {
c.nodesSlots = c.nodesSlots[index+1:]
return nil
}

if index == len(c.nodesInfos)-1 {
c.nodesInfos = c.nodesInfos[:len(c.nodesInfos)-1]
return nodeName, nil

if index == len(c.nodesSlots)-1 {
c.nodesSlots = c.nodesSlots[:len(c.nodesSlots)-1]
return nil
}
var (
newNodeInfos = make([]*NodeInfos, len(c.nodesInfos)-1)
j int
newNodesSlots = make([]uint8, len(c.nodesSlots)-1)
j int
)
for i := 0; i <= len(c.nodesInfos)-1; i++ {
for i := 0; i <= len(c.nodesSlots)-1; i++ {
if i == index {
continue
}

newNodeInfos[j] = c.nodesInfos[i]
newNodesSlots[j] = c.nodesSlots[i]
j++
}

c.nodesInfos = newNodeInfos
return nodeName, nil

c.nodesSlots = newNodesSlots
return nil
}

func (c *Chat) SaveMessage(message *Message) {
Expand Down Expand Up @@ -154,40 +150,42 @@ func (c *Chat) ToBytes() []byte {
// GetSlots returns all the slots identifying active TCP connections between nodes.
func (c *Chat) GetSlots() []uint8 {
length := 0
if len(c.nodesInfos) > 0 {
length = len(c.nodesInfos) - 1
if len(c.nodesSlots) > 0 {
length = len(c.nodesSlots) - 1
}

slots := make([]uint8, 0, length)
for _, i := range c.nodesInfos {
for _, s := range c.nodesSlots {
// My own slot
if i.Slot == 0 {
if s == 0 {
continue
}

slots = append(slots, i.Slot)
slots = append(slots, s)
}

return slots
}

func (c *Chat) GetNodeBySlot(slot uint8) (*NodeInfos, error) {
for _, i := range c.nodesInfos {
if i.Slot == slot {
return i, nil
/*
func (c *Chat) GetNodeBySlot(slot uint8) (*NodeInfos, error) {
for _, s := range c.nodesSlots {
if s == slot {
return s, nil
}
}
}

return &NodeInfos{}, NotFoundErr
}
return &NodeInfos{}, NotFoundErr
}
*/
/*
func (c *Chat) DisplayUsers() {
log.Printf("chat name : %s\n", c.Name)
for _, n := range c.nodesInfos {
for _, n := range c.nodesSlots {
log.Printf("- %s (Address: %s, Port: %s, Slot: %d)\n", n.Name, n.Address, n.Port, n.Slot)
}
}

*/
func (c *Chat) ContainsMessage(message *Message) bool {
for _, m := range c.messages {
if m.Id == message.Id {
Expand All @@ -197,12 +195,14 @@ func (c *Chat) ContainsMessage(message *Message) bool {
return false
}

func (c *Chat) containsNode(id uuid.UUID) bool {
for _, n := range c.nodesInfos {
/*
func (c *Chat) containsNode(s uuid.UUID) bool {
for _, n := range c.nodesSlots {
if n.Id == id {
return true
}
}
return false
}
*/
76 changes: 10 additions & 66 deletions crdt/chat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,89 +68,33 @@ func TestChat_RemoveNodeBySlot(t *testing.T) {
}{
{
name: "delete first node",
slot: 0,
slot: 1,
chat: &Chat{
nodesInfos: []*NodeInfos{
{
Id: idToDelete,
Slot: 0,
},
{
Id: uuid.New(),
Slot: 1,
},
{
Id: uuid.New(),
Slot: 2,
},
},
nodesSlots: []uint8{1, 2, 3},
},
expectedNumberOfNodes: 2,
},
{
name: "delete middle one",
slot: 1,
slot: 2,
chat: &Chat{
nodesInfos: []*NodeInfos{
{
Id: uuid.New(),
Slot: 0,
},
{
Id: idToDelete,
Slot: 1,
},
{
Id: uuid.New(),
Slot: 2,
},
},
nodesSlots: []uint8{1, 2, 3},
},
expectedNumberOfNodes: 2,
},
{
name: "delete middle one (4 elements)",
slot: 2,
chat: &Chat{
nodesInfos: []*NodeInfos{
{
Id: uuid.New(),
Slot: 0,
},
{
Id: uuid.New(),
Slot: 1,
},
{
Id: idToDelete,
Slot: 2,
},
{
Id: uuid.New(),
Slot: 3,
},
},
nodesSlots: []uint8{1, 2, 3, 4},
},
expectedNumberOfNodes: 3,
},
{
name: "delete last",
slot: 2,
slot: 3,
chat: &Chat{
nodesInfos: []*NodeInfos{
{
Id: uuid.New(),
Slot: 0,
},
{
Id: uuid.New(),
Slot: 1,
},
{
Id: idToDelete,
Slot: 2,
},
},
nodesSlots: []uint8{1, 2, 3},
},
expectedNumberOfNodes: 2,
},
Expand All @@ -159,9 +103,9 @@ func TestChat_RemoveNodeBySlot(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.chat.RemoveNodeBySlot(tt.slot)
assert.True(t, !tt.chat.containsNode(idToDelete))
assert.Equal(t, tt.expectedNumberOfNodes, len(tt.chat.nodesInfos))
tt.chat.RemoveNodeSlot(tt.slot)
assert.NotContains(t, idToDelete, tt.chat.nodesSlots)
assert.Equal(t, tt.expectedNumberOfNodes, len(tt.chat.nodesSlots))
})
}
}
12 changes: 3 additions & 9 deletions orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,14 @@ func (o *Orchestrator) HandleChats(wg *sync.WaitGroup, toExecute chan *crdt.Oper
continue
}

// there is no chat specified in operation in this case we need to remove node identified by newNodeSlot from all chats
if op.Typology == crdt.RemoveNode {
o.storage.RemoveNodeSlotFromStorage(op.Slot)
continue
}

// for other operation we need to get a chat from storage
chatID, err := uuid.Parse(op.TargetedChat)
if err != nil {
fmt.Printf(logErrFrmt, err)
continue
}

exists := o.storage.Exist(chatID)
exists := o.storage.ChatExist(chatID)
if !exists {
fmt.Printf(logErrFrmt, "unknown chat")
continue
Expand Down Expand Up @@ -154,7 +148,7 @@ func (o *Orchestrator) HandleChats(wg *sync.WaitGroup, toExecute chan *crdt.Oper
// add other nodes
slots, _ := o.storage.GetSlots(chatID)
for _, s := range slots {
nodeInfo, err := o.storage.GetNodeFromChatBySlot(chatID, s)
nodeInfo, err := o.storage.GetNodeBySlot(s)
if err != nil {
fmt.Printf(logErrFrmt, err)
}
Expand Down Expand Up @@ -239,7 +233,7 @@ func (o *Orchestrator) HandleChats(wg *sync.WaitGroup, toExecute chan *crdt.Oper

// Verify that slots are not used by any other chats
for s, _ := range toDelete {
if o.storage.IsSlotUsedByOtherChats(s, o.myInfos.Id, chatID) {
if o.storage.IsSlotUsedByOtherChats(s, chatID) {
toDelete[s] = false
}
}
Expand Down
Loading

0 comments on commit 04cd77b

Please sign in to comment.