Skip to content

Commit

Permalink
resolves linkedin#35
Browse files Browse the repository at this point in the history
  • Loading branch information
Karrick S. McDermott committed Aug 22, 2018
1 parent f698316 commit 3485ba9
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 22 deletions.
3 changes: 2 additions & 1 deletion canonical.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ func pcfMap(jsonMap map[string]interface{}, proc pcfProcessor) string {
// float.
if k == "size" {
if s, ok := v.(string); ok {
s, err := strconv.Atoi(s)
s, err := strconv.ParseUint(s, 10, 0)
if err != nil {
// should never get here because already validated schema
panic(fmt.Errorf("Fixed size ought to be number greater than zero: %v", s))
}
v = float64(s)
Expand Down
26 changes: 11 additions & 15 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,39 +365,35 @@ func (c *Codec) CanonicalSchema() string {
return c.schemaCanonical
}

func (c *Codec) CRC64Avro() uint64 {
return 0
}

const crc64Empty = uint64(0xc15d213aa4d7a795)

var crc64Table [256]uint64

// func init() {
// initCRC64AvroTable()
// }

func initCRC64AvroTable() {
func initCRC64AvroTable() [256]uint64 {
var crc64Table [256]uint64
for i := uint64(0); i < 256; i++ {
fp := i
for j := 0; j < 8; j++ {
fp = (fp >> 1) ^ (crc64Empty & -(fp & 1)) // unsigned right shift >>>
}
crc64Table[i] = fp
}
return crc64Table
}

func calculateCRC64Avro(b []byte) uint64 {
initCRC64AvroTable()
crc64Table := initCRC64AvroTable()
fp := crc64Empty
for i := 0; i < len(b); i++ {
fp = (fp >> 8) ^ crc64Table[(byte(fp)^b[i])&0xff]
fp = (fp >> 8) ^ crc64Table[(byte(fp)^b[i])&0xff] // unsigned right shift >>>
}
return fp
}

func (c *Codec) SchemaCRC64Avro() uint64 {
return calculateCRC64Avro([]byte(c.schemaCanonical))
// SchemaCRC64Avro returns a signed 64-bit integer Rabin fingerprint for the
// canonical schema.
func (c *Codec) SchemaCRC64Avro() int64 {
// Must perform the bitwise calculations using unsigned 64-bit integer math,
// but the Avro code and test files return a signed 64-bit integer.
return int64(calculateCRC64Avro([]byte(c.schemaCanonical)))
}

// convert a schema data structure to a codec, prefixing with specified
Expand Down
58 changes: 52 additions & 6 deletions codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,59 @@ func ExampleCodecCanonicalSchema() {
}

func TestSchemaCRC64Avro(t *testing.T) {
codec, err := goavro.NewCodec(`"int"`)
if err != nil {
t.Fatal(err)
cases := []struct {
Schema string
Fingerprint int64
}{
{
Schema: `"null"`,
Fingerprint: 7195948357588979594,
},
{
Schema: `"boolean"`,
Fingerprint: -6970731678124411036,
},
{
Schema: `"int"`,
Fingerprint: 8247732601305521295,
},
{
Schema: `"long"`,
Fingerprint: -3434872931120570953,
},
{
Schema: `"float"`,
Fingerprint: 5583340709985441680,
},
{
Schema: `"double"`,
Fingerprint: -8181574048448539266,
},
{
Schema: `"bytes"`,
Fingerprint: 5746618253357095269,
},
{
Schema: `"string"`,
Fingerprint: -8142146995180207161,
},
{
Schema: `[ "int" ]`,
Fingerprint: -5232228896498058493,
},
{
Schema: `[ "int" , {"type":"boolean"} ]`,
Fingerprint: 5392556393470105090,
},
}

_ = codec
if got, want := codec.SchemaCRC64Avro(), uint64(13); got != want {
t.Errorf("GOT: %#x; WANT: %#x", got, want)
for _, c := range cases {
codec, err := goavro.NewCodec(c.Schema)
if err != nil {
t.Fatalf("CASE: %s; cannot create code: %s", c.Schema, err)
}
if got, want := codec.SchemaCRC64Avro(), c.Fingerprint; got != want {
t.Errorf("CASE: %s; GOT: %#x; WANT: %#x", c.Schema, got, want)
}
}
}

0 comments on commit 3485ba9

Please sign in to comment.