diff --git a/dgraph/cmd/bulk/mapper.go b/dgraph/cmd/bulk/mapper.go index 8bfbdfb5422..5f500ca1bfa 100644 --- a/dgraph/cmd/bulk/mapper.go +++ b/dgraph/cmd/bulk/mapper.go @@ -231,10 +231,16 @@ func (m *mapper) addMapEntry(key []byte, p *pb.Posting, shard int) { func (m *mapper) processNQuad(nq gql.NQuad) { sid := m.uid(nq.GetSubject()) + if sid == 0 { + panic(fmt.Sprintf("invalid UID with value 0 for %v", nq.GetSubject())) + } var oid uint64 var de *pb.DirectedEdge if nq.GetObjectValue() == nil { oid = m.uid(nq.GetObjectId()) + if oid == 0 { + panic(fmt.Sprintf("invalid UID with value 0 for %v", nq.GetObjectId())) + } de = nq.CreateUidEdge(sid, oid) } else { var err error diff --git a/gql/mutation.go b/gql/mutation.go index a96b053af9d..c02c0258efe 100644 --- a/gql/mutation.go +++ b/gql/mutation.go @@ -27,7 +27,7 @@ import ( ) var ( - errInvalidUID = errors.New("UID has to be greater than one") + errInvalidUID = errors.New("UID must to be greater than 0") ) // Mutation stores the strings corresponding to set and delete operations. diff --git a/posting/index.go b/posting/index.go index 06402596340..022ce2bd11d 100644 --- a/posting/index.go +++ b/posting/index.go @@ -91,7 +91,9 @@ func (txn *Txn) addIndexMutations(ctx context.Context, info *indexMutationInfo) attr := info.edge.Attr uid := info.edge.Entity - x.AssertTrue(uid != 0) + if uid == 0 { + return errors.New("invalid UID with value 0") + } tokens, err := indexTokens(ctx, info) if err != nil { // This data is not indexable diff --git a/worker/backup_processor.go b/worker/backup_processor.go index 2043fff349b..74bc842ea21 100644 --- a/worker/backup_processor.go +++ b/worker/backup_processor.go @@ -141,6 +141,7 @@ func (pr *BackupProcessor) WriteBackup(ctx context.Context) (*pb.Status, error) stream.ChooseKey = func(item *badger.Item) bool { parsedKey, err := x.Parse(item.Key()) if err != nil { + glog.Errorf("error %v while parsing key %v during backup. Skip.", err, hex.EncodeToString(item.Key())) return false } diff --git a/worker/draft.go b/worker/draft.go index 0d52f0e761f..dcfa130a2ba 100644 --- a/worker/draft.go +++ b/worker/draft.go @@ -19,6 +19,7 @@ package worker import ( "bytes" "context" + "encoding/hex" "fmt" "sort" "sync" @@ -240,6 +241,7 @@ func detectPendingTxns(attr string) error { tctxs := posting.Oracle().IterateTxns(func(key []byte) bool { pk, err := x.Parse(key) if err != nil { + glog.Errorf("error %v while parsing key %v", err, hex.EncodeToString(key)) return false } return pk.Attr == attr diff --git a/worker/export.go b/worker/export.go index 4d5632a9f67..e09af4a4892 100644 --- a/worker/export.go +++ b/worker/export.go @@ -21,6 +21,7 @@ import ( "bytes" "compress/gzip" "context" + "encoding/hex" "encoding/json" "fmt" "os" @@ -439,6 +440,7 @@ func export(ctx context.Context, in *pb.ExportRequest) error { stream.ChooseKey = func(item *badger.Item) bool { pk, err := x.Parse(item.Key()) if err != nil { + glog.Errorf("error %v while parsing key %v during export. Skip.", err, hex.EncodeToString(item.Key())) return false } @@ -469,6 +471,7 @@ func export(ctx context.Context, in *pb.ExportRequest) error { item := itr.Item() pk, err := x.Parse(item.Key()) if err != nil { + glog.Errorf("error %v while parsing key %v during export. Skip.", err, hex.EncodeToString(item.Key())) return nil, err } e := &exporter{ diff --git a/x/keys.go b/x/keys.go index 023808e41fc..ce39777eea2 100644 --- a/x/keys.go +++ b/x/keys.go @@ -439,7 +439,7 @@ func Parse(key []byte) (ParsedKey, error) { var p ParsedKey if len(key) == 0 { - return p, errors.Errorf("0 length key") + return p, errors.New("0 length key") } p.bytePrefix = key[0] @@ -476,7 +476,9 @@ func Parse(key []byte) (ParsedKey, error) { return p, errors.Errorf("uid length < 8 for key: %q, parsed key: %+v", key, p) } p.Uid = binary.BigEndian.Uint64(k) - + if p.Uid == 0 { + return p, errors.Errorf("Invalid UID with value 0 for key: %v", key) + } if !p.HasStartUid { break } diff --git a/x/keys_test.go b/x/keys_test.go index 7441c6ff378..a96761b5958 100644 --- a/x/keys_test.go +++ b/x/keys_test.go @@ -27,7 +27,14 @@ import ( func TestDataKey(t *testing.T) { var uid uint64 - for uid = 0; uid < 1001; uid++ { + + // key with uid = 0 is invalid + uid = 0 + key := DataKey("bad uid", uid) + _, err := Parse(key) + require.Error(t, err) + + for uid = 1; uid < 1001; uid++ { // Use the uid to derive the attribute so it has variable length and the test // can verify that multiple sizes of attr work correctly. sattr := fmt.Sprintf("attr:%d", uid) @@ -58,7 +65,7 @@ func TestDataKey(t *testing.T) { func TestParseDataKeyWithStartUid(t *testing.T) { var uid uint64 startUid := uint64(math.MaxUint64) - for uid = 0; uid < 1001; uid++ { + for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) key := DataKey(sattr, uid) key, err := SplitKey(key, startUid) @@ -113,7 +120,7 @@ func TestIndexKeyWithStartUid(t *testing.T) { func TestReverseKey(t *testing.T) { var uid uint64 - for uid = 0; uid < 1001; uid++ { + for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) key := ReverseKey(sattr, uid) @@ -129,7 +136,7 @@ func TestReverseKey(t *testing.T) { func TestReverseKeyWithStartUid(t *testing.T) { var uid uint64 startUid := uint64(math.MaxUint64) - for uid = 0; uid < 1001; uid++ { + for uid = 1; uid < 1001; uid++ { sattr := fmt.Sprintf("attr:%d", uid) key := ReverseKey(sattr, uid) @@ -252,4 +259,10 @@ func TestBadKeys(t *testing.T) { key = []byte{1, 0x00, 0x04, 1, 2} _, err = Parse(key) require.Error(t, err) + + // key with uid = 0 is invalid + uid := 0 + key = DataKey("bad uid", uint64(uid)) + _, err = Parse(key) + require.Error(t, err) }