<commit_before>package consistentHashing

import (
	"errors"
	//"fmt"
	rbt "github.com/emirpasic/gods/trees/redblacktree"
	"github.com/otnt/distributed-system-how-to/node"
	"sort"
	"sync"
)

//The abstruct structure of consistent hash ring.
//It consists of a Red-Black-Tree serve as the ring.
type Ring struct {
	Tree *rbt.Tree
	mux  sync.Mutex
}

//Create a new consistent hashing ring with default
//value setting.
//
//@return: pointer to new created consistent hashing ring
func NewRing() (ring *Ring) {
	ring = &Ring{}
	ring.Tree = rbt.NewWithStringComparator()
	return
}

//Add a new Node to consistent hashing ring.
//This function block the running routine until the Node
//is successfully added.
//
//@param node: Node to be added
func (ring *Ring) AddSync(node *node.Node) {
	ring.mux.Lock()
	for _, key := range node.Keys {
		ring.Tree.Put(key, node)
	}
	ring.mux.Unlock()

	return
}

//Remove a new Node to consistent hashing ring.
//This function block the running routine until the Node
//is successfully removed.
//
//@param node: Node to be removed
func (ring *Ring) RemoveSync(node *node.Node) {
	ring.mux.Lock()
	for _, key := range node.Keys {
		ring.Tree.Remove(key)
	}
	ring.mux.Unlock()

	return
}

// Add a new Node to consistent hashing ring.
//
// @param addChan: incoming channel of Node pointer
// @param complete: outgoing channel of Node pointer, indicating
//                   which Node has been added
func (ring *Ring) AddAsync(addChan <-chan *node.Node, complete chan<- *node.Node) {
	for node := range addChan {
		keys := node.Keys

		ring.mux.Lock()
		for _, key := range keys {
			ring.Tree.Put(key, node)
		}
		ring.mux.Unlock()

		complete <- node
	}
	close(complete)
}

// Remove a Node from consistent hashing ring.
//
// @param removeChan: incoming channel of Node pointer
// @param complete: outgoing channel of Node pointer, indicating
//                  which Node has been removed
func (ring *Ring) RemoveAsync(removeChan <-chan *node.Node, complete chan<- *node.Node) {
	for node := range removeChan {
		keys := node.Keys

		ring.mux.Lock()
		for _, key := range keys {
			ring.Tree.Remove(key)
		}
		ring.mux.Unlock()

		complete <- node
	}
	close(complete)
}

// Lookup for a Node in consistent hashing ring.
// This function is actually redirected to Successor
//
// @param key: string of key
// @return: return the node if such successor founded, otherwise an error is
//          given
func (ring *Ring) LookUp(key string) (*node.Node, error) {
	size := ring.Tree.Size()
	if size == 0 {
		return &node.Node{}, errors.New("No node alive")

	}

	interfaceSlice := ring.Tree.Keys()
	keys := make([]string, size)
	for i := range keys {
		keys[i] = interfaceSlice[i].(string)
	}

	index := sort.SearchStrings(keys, key)
	if index == size {
		index = 0
	}

	return ring.Tree.Values()[index].(*node.Node), nil
}

// Get successor of a given key(this key is supposed to belong to a Node)<commit_msg>modify comment of LookUp<commit_after>package consistentHashing

import (
	"errors"
	//"fmt"
	rbt "github.com/emirpasic/gods/trees/redblacktree"
	"github.com/otnt/distributed-system-how-to/node"
	"sort"
	"sync"
)

//The abstruct structure of consistent hash ring.
//It consists of a Red-Black-Tree serve as the ring.
type Ring struct {
	Tree *rbt.Tree
	mux  sync.Mutex
}

//Create a new consistent hashing ring with default
//value setting.
//
//@return: pointer to new created consistent hashing ring
func NewRing() (ring *Ring) {
	ring = &Ring{}
	ring.Tree = rbt.NewWithStringComparator()
	return
}

//Add a new Node to consistent hashing ring.
//This function block the running routine until the Node
//is successfully added.
//
//@param node: Node to be added
func (ring *Ring) AddSync(node *node.Node) {
	ring.mux.Lock()
	for _, key := range node.Keys {
		ring.Tree.Put(key, node)
	}
	ring.mux.Unlock()

	return
}

//Remove a new Node to consistent hashing ring.
//This function block the running routine until the Node
//is successfully removed.
//
//@param node: Node to be removed
func (ring *Ring) RemoveSync(node *node.Node) {
	ring.mux.Lock()
	for _, key := range node.Keys {
		ring.Tree.Remove(key)
	}
	ring.mux.Unlock()

	return
}

// Add a new Node to consistent hashing ring.
//
// @param addChan: incoming channel of Node pointer
// @param complete: outgoing channel of Node pointer, indicating
//                   which Node has been added
func (ring *Ring) AddAsync(addChan <-chan *node.Node, complete chan<- *node.Node) {
	for node := range addChan {
		keys := node.Keys

		ring.mux.Lock()
		for _, key := range keys {
			ring.Tree.Put(key, node)
		}
		ring.mux.Unlock()

		complete <- node
	}
	close(complete)
}

// Remove a Node from consistent hashing ring.
//
// @param removeChan: incoming channel of Node pointer
// @param complete: outgoing channel of Node pointer, indicating
//                  which Node has been removed
func (ring *Ring) RemoveAsync(removeChan <-chan *node.Node, complete chan<- *node.Node) {
	for node := range removeChan {
		keys := node.Keys

		ring.mux.Lock()
		for _, key := range keys {
			ring.Tree.Remove(key)
		}
		ring.mux.Unlock()

		complete <- node
	}
	close(complete)
}

// Lookup for a Node in consistent hashing ring given a key.
// If the input key is the same as some Node's key, then the result is
// that exact Node.
//
// @param key: string of key
// @return: return the node if such successor founded, otherwise an error is
//          given
func (ring *Ring) LookUp(key string) (*node.Node, error) {
	size := ring.Tree.Size()
	if size == 0 {
		return &node.Node{}, errors.New("No node alive")

	}

	interfaceSlice := ring.Tree.Keys()
	keys := make([]string, size)
	for i := range keys {
		keys[i] = interfaceSlice[i].(string)
	}

	index := sort.SearchStrings(keys, key)
	if index == size {
		index = 0
	}

	return ring.Tree.Values()[index].(*node.Node), nil
}

// Get successor of a given key(this key is supposed to belong to a Node)
{'fraction_non_alphanumeric': 0.12754158964879853, 'fraction_numerical': 0.0006721559401781214, 'mean_word_length': 3.1856540084388185, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2873434', 'n_tokens_mistral': 2014, 'n_tokens_neox': 1889, 'n_words': 678}