Skip to content

Commit

Permalink
update hashing mechamisms
Browse files Browse the repository at this point in the history
  • Loading branch information
xiam committed Aug 15, 2022
1 parent 31f9ea6 commit 5ac579c
Show file tree
Hide file tree
Showing 21 changed files with 266 additions and 159 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/jackc/pgx/v4 v4.15.0
github.com/lib/pq v1.10.4
github.com/mattn/go-sqlite3 v1.14.9
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/segmentio/fasthash v1.0.3
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
Expand Down
109 changes: 109 additions & 0 deletions internal/cache/hash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package cache

import (
"fmt"

"github.com/segmentio/fasthash/fnv1a"
)

const (
hashTypeInt uint64 = 1 << iota
hashTypeSignedInt
hashTypeBool
hashTypeString
hashTypeHashable
hashTypeNil
)

type hasher struct {
t uint64
v interface{}
}

func (h *hasher) Hash() uint64 {
return NewHash(h.t, h.v)
}

func NewHashable(t uint64, v interface{}) Hashable {
return &hasher{t: t, v: v}
}

func InitHash(t uint64) uint64 {
return fnv1a.AddUint64(fnv1a.Init64, t)
}

func NewHash(t uint64, in ...interface{}) uint64 {
return AddToHash(InitHash(t), in...)
}

func AddToHash(h uint64, in ...interface{}) uint64 {
for i := range in {
if in[i] == nil {
continue
}
h = addToHash(h, in[i])
}
return h
}

func addToHash(h uint64, in interface{}) uint64 {
switch v := in.(type) {
case uint64:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), v)
case uint32:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
case uint16:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
case uint8:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
case uint:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
case int64:
if v < 0 {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeSignedInt), uint64(-v))
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
}
case int32:
if v < 0 {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeSignedInt), uint64(-v))
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
}
case int16:
if v < 0 {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeSignedInt), uint64(-v))
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
}
case int8:
if v < 0 {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeSignedInt), uint64(-v))
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
}
case int:
if v < 0 {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeSignedInt), uint64(-v))
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeInt), uint64(v))
}
case bool:
if v {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeBool), 1)
} else {
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeBool), 2)
}
case string:
return fnv1a.AddString64(fnv1a.AddUint64(h, hashTypeString), v)
case Hashable:
if in == nil {
panic(fmt.Sprintf("could not hash nil element %T", in))
}
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeHashable), v.Hash())
case nil:
return fnv1a.AddUint64(fnv1a.AddUint64(h, hashTypeNil), 0)
default:
panic(fmt.Sprintf("unsupported value type %T", in))
}
}
7 changes: 6 additions & 1 deletion internal/sqladapter/exql/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package exql
import (
"fmt"
"strings"

"github.com/upper/db/v4/internal/cache"
)

type columnWithAlias struct {
Expand All @@ -24,7 +26,10 @@ func ColumnWithName(name string) *Column {

// Hash returns a unique identifier for the struct.
func (c *Column) Hash() uint64 {
return quickHash(FragmentType_Column, c.Name)
if c == nil {
return cache.NewHash(FragmentType_Column, nil)
}
return cache.NewHash(FragmentType_Column, c.Name)
}

// Compile transforms the ColumnValue into an equivalent SQL representation.
Expand Down
10 changes: 7 additions & 3 deletions internal/sqladapter/exql/column_value.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package exql

import (
"github.com/upper/db/v4/internal/cache"
"strings"
)

Expand All @@ -21,7 +22,10 @@ type columnValueT struct {

// Hash returns a unique identifier for the struct.
func (c *ColumnValue) Hash() uint64 {
return quickHash(FragmentType_ColumnValue, c.Column, c.Operator, c.Value)
if c == nil {
return cache.NewHash(FragmentType_ColumnValue, nil)
}
return cache.NewHash(FragmentType_ColumnValue, c.Column, c.Operator, c.Value)
}

// Compile transforms the ColumnValue into an equivalent SQL representation.
Expand Down Expand Up @@ -74,9 +78,9 @@ func (c *ColumnValues) Insert(values ...Fragment) *ColumnValues {

// Hash returns a unique identifier for the struct.
func (c *ColumnValues) Hash() uint64 {
h := initHash(FragmentType_ColumnValues)
h := cache.InitHash(FragmentType_ColumnValues)
for i := range c.ColumnValues {
h = addToHash(h, c.ColumnValues[i])
h = cache.AddToHash(h, c.ColumnValues[i])
}
return h
}
Expand Down
10 changes: 7 additions & 3 deletions internal/sqladapter/exql/columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package exql

import (
"strings"

"github.com/upper/db/v4/internal/cache"
)

// Columns represents an array of Column.
Expand All @@ -13,9 +15,12 @@ var _ = Fragment(&Columns{})

// Hash returns a unique identifier.
func (c *Columns) Hash() uint64 {
h := initHash(FragmentType_Columns)
if c == nil {
return cache.NewHash(FragmentType_Columns, nil)
}
h := cache.InitHash(FragmentType_Columns)
for i := range c.Columns {
h = addToHash(h, c.Columns[i])
h = cache.AddToHash(h, c.Columns[i])
}
return h
}
Expand Down Expand Up @@ -51,7 +56,6 @@ func (c *Columns) IsEmpty() bool {

// Compile transforms the Columns into an equivalent SQL representation.
func (c *Columns) Compile(layout *Template) (compiled string, err error) {

if z, ok := layout.Read(c); ok {
return z, nil
}
Expand Down
9 changes: 8 additions & 1 deletion internal/sqladapter/exql/database.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package exql

import (
"github.com/upper/db/v4/internal/cache"
)

// Database represents a SQL database.
type Database struct {
Name string
Expand All @@ -14,7 +18,10 @@ func DatabaseWithName(name string) *Database {

// Hash returns a unique identifier for the struct.
func (d *Database) Hash() uint64 {
return quickHash(FragmentType_Database, d.Name)
if d == nil {
return cache.NewHash(FragmentType_Database, nil)
}
return cache.NewHash(FragmentType_Database, d.Name)
}

// Compile transforms the Database into an equivalent SQL representation.
Expand Down
9 changes: 8 additions & 1 deletion internal/sqladapter/exql/group_by.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package exql

import (
"github.com/upper/db/v4/internal/cache"
)

// GroupBy represents a SQL's "group by" statement.
type GroupBy struct {
Columns Fragment
Expand All @@ -13,7 +17,10 @@ type groupByT struct {

// Hash returns a unique identifier.
func (g *GroupBy) Hash() uint64 {
return quickHash(FragmentType_GroupBy, g.Columns)
if g == nil {
return cache.NewHash(FragmentType_GroupBy, nil)
}
return cache.NewHash(FragmentType_GroupBy, g.Columns)
}

// GroupByColumns creates and returns a GroupBy with the given column.
Expand Down
109 changes: 0 additions & 109 deletions internal/sqladapter/exql/hash.go

This file was deleted.

Loading

0 comments on commit 5ac579c

Please sign in to comment.