<commit_before>package mssqlx

import (
	"database/sql"
	"errors"
	"fmt"
	"net"
	"sync"
	"time"
)

var (
	// ErrNetwork networking error
	ErrNetwork = errors.New("Network error/Connection refused")

	// ErrNoConnection there is no connection to db
	ErrNoConnection = errors.New("No connection available")
)

func parseError(db *DB, err error) error {
	if err == nil {
		return nil
	}

	if _, ok := err.(net.Error); ok {
		return ErrNetwork
	}

	if db.Ping() != nil {
		return ErrNetwork
	}

	return err
}

// dbLinkListNode a node of linked-list contains sqlx.DB
type dbLinkListNode struct {
	db   *DB
	next *dbLinkListNode
	prev *dbLinkListNode
}

type DBNode interface {
	GetDB() *DB
}

func (c *dbLinkListNode) GetDB() *DB {
	return c.db
}

// dbLinkList a round robin and thread-safe linked-list of sqlx.DB
type dbLinkList struct {
	// head and tail of linked-list
	head *dbLinkListNode
	tail *dbLinkListNode

	// size of this linked list
	size int

	// current point on linked-list
	current *dbLinkListNode

	lock sync.RWMutex
}

// Next return next element from current node on linked-list. If current node is last node, the next one is head.
func (c *dbLinkList) next() *dbLinkListNode {
	c.lock.RLock()
	if c.current == nil {
		c.lock.RUnlock()
		return nil
	}
	defer c.lock.RUnlock()

	return c.current.next
}

// Prev return previous element from current node on linked-list. If current node is head node, the previous one is tail.
func (c *dbLinkList) prev() *dbLinkListNode {
	c.lock.RLock()
	if c.current == nil {
		c.lock.RUnlock()
		return nil
	}
	defer c.lock.RUnlock()

	return c.current.prev
}

// add node to last of linked-list
func (c *dbLinkList) add(node *dbLinkListNode) {
	if node == nil || node.db == nil {
		return
	}

	c.lock.Lock()
	defer c.lock.Unlock()

	c.size++

	if c.head == nil {
		c.head, c.tail, c.current = node, node, node
		node.next = node
		node.prev = node

		return
	}

	node.next, node.prev = c.head, c.tail
	c.head.prev, c.tail.next = node, node

	c.tail = node
}

// remove a node
func (c *dbLinkList) remove(node *dbLinkListNode) bool {
	c.lock.Lock()
	defer c.lock.Unlock()

	if node == nil || node.next == nil || node.prev == nil || c.size == 0 { // important to prevent double remove
		return false
	}

	node.prev.next, node.next.prev = node.next, node.prev

	// Check size
	if c.size--; c.size == 0 {
		c.head, c.tail, c.current = nil, nil, nil
		node.next, node.prev = nil, nil // important to prevent double remove

		return true
	}

	if c.current == node {
		c.current = node.next
	}

	node.next, node.prev = nil, nil // important to prevent double remove
	return true
}

// moveNext get current and make current pointer to next
func (c *dbLinkList) moveNext() (cur *dbLinkListNode) {
	c.lock.Lock()
	defer c.lock.Unlock()<commit_msg>Fix bugs and strengthen health check<commit_after>package mssqlx

import (
	"database/sql"
	"errors"
	"fmt"
	"net"
	"sync"
	"time"
)

var (
	// ErrNetwork networking error
	ErrNetwork = errors.New("Network error/Connection refused")

	// ErrNoConnection there is no connection to db
	ErrNoConnection = errors.New("No connection available")
)

func parseError(db *DB, err error) error {
	if err == nil {
		return nil
	}

	if _, ok := err.(net.Error); ok {
		return ErrNetwork
	}

	if _, err := db.Exec("SELECT 1"); err != nil {
		return ErrNetwork
	}

	return err
}

// dbLinkListNode a node of linked-list contains sqlx.DB
type dbLinkListNode struct {
	db   *DB
	next *dbLinkListNode
	prev *dbLinkListNode
}

type DBNode interface {
	GetDB() *DB
}

func (c *dbLinkListNode) GetDB() *DB {
	return c.db
}

// dbLinkList a round robin and thread-safe linked-list of sqlx.DB
type dbLinkList struct {
	// head and tail of linked-list
	head *dbLinkListNode
	tail *dbLinkListNode

	// size of this linked list
	size int

	// current point on linked-list
	current *dbLinkListNode

	lock sync.RWMutex
}

// Next return next element from current node on linked-list. If current node is last node, the next one is head.
func (c *dbLinkList) next() *dbLinkListNode {
	c.lock.RLock()
	if c.current == nil {
		c.lock.RUnlock()
		return nil
	}
	defer c.lock.RUnlock()

	return c.current.next
}

// Prev return previous element from current node on linked-list. If current node is head node, the previous one is tail.
func (c *dbLinkList) prev() *dbLinkListNode {
	c.lock.RLock()
	if c.current == nil {
		c.lock.RUnlock()
		return nil
	}
	defer c.lock.RUnlock()

	return c.current.prev
}

// add node to last of linked-list
func (c *dbLinkList) add(node *dbLinkListNode) {
	if node == nil || node.db == nil {
		return
	}

	c.lock.Lock()
	defer c.lock.Unlock()

	c.size++

	if c.head == nil {
		c.head, c.tail, c.current = node, node, node
		node.next = node
		node.prev = node

		return
	}

	node.next, node.prev = c.head, c.tail
	c.head.prev, c.tail.next = node, node

	c.tail = node
}

// remove a node
func (c *dbLinkList) remove(node *dbLinkListNode) bool {
	c.lock.Lock()
	defer c.lock.Unlock()

	if node == nil || node.next == nil || node.prev == nil || c.size == 0 { // important to prevent double remove
		return false
	}

	node.prev.next, node.next.prev = node.next, node.prev

	// Check size
	if c.size--; c.size == 0 {
		c.head, c.tail, c.current = nil, nil, nil
		node.next, node.prev = nil, nil // important to prevent double remove

		return true
	}

	if c.current == node {
		c.current = node.next
	}

	if c.head == node {
		c.head = node.next
	}

	if c.tail == node {
		c.tail = node.prev
	}

	node.next, node.prev = nil, nil // important to prevent double remove
	return true
}

// moveNext get current and make current pointer to next
func (c *dbLinkList) moveNext() (cur *dbLinkListNode) {
	c.lock.Lock()
	defer c.lock.Unlock()
{'fraction_non_alphanumeric': 0.12412587412587413, 'fraction_numerical': 0.0008741258741258741, 'mean_word_length': 3.1306859205776174, 'pattern_counts': {'":': 0, '<': 3, '<?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': '4058277', 'n_tokens_mistral': 2117, 'n_tokens_neox': 2035, 'n_words': 661}