github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/posting/list_test.go (about)

     1  /*
     2   * Copyright 2015-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package posting
    18  
    19  import (
    20  	"context"
    21  	"io/ioutil"
    22  	"math"
    23  	"math/rand"
    24  	"os"
    25  	"sort"
    26  	"strconv"
    27  	"testing"
    28  
    29  	"github.com/dgraph-io/badger"
    30  	bpb "github.com/dgraph-io/badger/pb"
    31  	"github.com/stretchr/testify/require"
    32  
    33  	"github.com/dgraph-io/dgraph/protos/pb"
    34  	"github.com/dgraph-io/dgraph/schema"
    35  	"github.com/dgraph-io/dgraph/x"
    36  )
    37  
    38  func (l *List) PostingList() *pb.PostingList {
    39  	l.RLock()
    40  	defer l.RUnlock()
    41  	return l.plist
    42  }
    43  
    44  func listToArray(t *testing.T, afterUid uint64, l *List, readTs uint64) []uint64 {
    45  	out := make([]uint64, 0, 10)
    46  	l.Iterate(readTs, afterUid, func(p *pb.Posting) error {
    47  		out = append(out, p.Uid)
    48  		return nil
    49  	})
    50  	return out
    51  }
    52  
    53  func checkUids(t *testing.T, l *List, uids []uint64, readTs uint64) {
    54  	require.Equal(t, uids, listToArray(t, 0, l, readTs))
    55  	if len(uids) >= 3 {
    56  		require.Equal(t, uids[1:], listToArray(t, 10, l, readTs), uids[1:])
    57  		require.Equal(t, []uint64{81}, listToArray(t, 80, l, readTs))
    58  		require.Empty(t, listToArray(t, 82, l, readTs))
    59  	}
    60  }
    61  
    62  func addMutationHelper(t *testing.T, l *List, edge *pb.DirectedEdge, op uint32, txn *Txn) {
    63  	if op == Del {
    64  		edge.Op = pb.DirectedEdge_DEL
    65  	} else if op == Set {
    66  		edge.Op = pb.DirectedEdge_SET
    67  	} else {
    68  		x.Fatalf("Unhandled op: %v", op)
    69  	}
    70  	err := l.addMutation(context.Background(), txn, edge)
    71  	require.NoError(t, err)
    72  }
    73  
    74  func (l *List) commitMutation(startTs, commitTs uint64) error {
    75  	l.Lock()
    76  	defer l.Unlock()
    77  
    78  	plist, ok := l.mutationMap[startTs]
    79  	if !ok {
    80  		// It was already committed, might be happening due to replay.
    81  		return nil
    82  	}
    83  	if commitTs == 0 {
    84  		// Abort mutation.
    85  		delete(l.mutationMap, startTs)
    86  		return nil
    87  	}
    88  
    89  	// We have a valid commit.
    90  	plist.CommitTs = commitTs
    91  	for _, mpost := range plist.Postings {
    92  		mpost.CommitTs = commitTs
    93  	}
    94  
    95  	// In general, a posting list shouldn't try to mix up it's job of keeping
    96  	// things in memory, with writing things to disk. A separate process can
    97  	// roll up and write them to disk. posting list should only keep things in
    98  	// memory, to make it available for transactions. So, all we need to do here
    99  	// is to roll them up periodically, now being done by draft.go.
   100  	// For the PLs in memory, we roll them up after we do the disk rollup.
   101  	return nil
   102  }
   103  
   104  func TestAddMutation(t *testing.T) {
   105  	key := x.DataKey("name", 2)
   106  
   107  	txn := NewTxn(1)
   108  	l, err := txn.Get(key)
   109  	require.NoError(t, err)
   110  
   111  	edge := &pb.DirectedEdge{
   112  		ValueId: 9,
   113  		Label:   "testing",
   114  	}
   115  	addMutationHelper(t, l, edge, Set, txn)
   116  
   117  	require.Equal(t, listToArray(t, 0, l, 1), []uint64{9})
   118  
   119  	p := getFirst(l, 1)
   120  	require.NotNil(t, p, "Unable to retrieve posting")
   121  	require.EqualValues(t, p.Label, "testing")
   122  
   123  	// Add another edge now.
   124  	edge.ValueId = 81
   125  	addMutationHelper(t, l, edge, Set, txn)
   126  	require.Equal(t, listToArray(t, 0, l, 1), []uint64{9, 81})
   127  
   128  	// Add another edge, in between the two above.
   129  	edge.ValueId = 49
   130  	addMutationHelper(t, l, edge, Set, txn)
   131  	require.Equal(t, listToArray(t, 0, l, 1), []uint64{9, 49, 81})
   132  
   133  	checkUids(t, l, []uint64{9, 49, 81}, 1)
   134  
   135  	// Delete an edge, add an edge, replace an edge
   136  	edge.ValueId = 49
   137  	addMutationHelper(t, l, edge, Del, txn)
   138  
   139  	edge.ValueId = 69
   140  	addMutationHelper(t, l, edge, Set, txn)
   141  
   142  	edge.ValueId = 9
   143  	edge.Label = "anti-testing"
   144  	addMutationHelper(t, l, edge, Set, txn)
   145  	l.commitMutation(1, 2)
   146  
   147  	uids := []uint64{9, 69, 81}
   148  	checkUids(t, l, uids, 3)
   149  
   150  	p = getFirst(l, 3)
   151  	require.NotNil(t, p, "Unable to retrieve posting")
   152  	require.EqualValues(t, "anti-testing", p.Label)
   153  }
   154  
   155  func getFirst(l *List, readTs uint64) (res pb.Posting) {
   156  	l.Iterate(readTs, 0, func(p *pb.Posting) error {
   157  		res = *p
   158  		return ErrStopIteration
   159  	})
   160  	return res
   161  }
   162  
   163  func checkValue(t *testing.T, ol *List, val string, readTs uint64) {
   164  	p := getFirst(ol, readTs)
   165  	require.Equal(t, uint64(math.MaxUint64), p.Uid) // Cast to prevent overflow.
   166  	require.EqualValues(t, val, p.Value)
   167  }
   168  
   169  // TODO(txn): Add tests after lru eviction
   170  func TestAddMutation_Value(t *testing.T) {
   171  	key := x.DataKey("value", 10)
   172  	ol, err := getNew(key, ps)
   173  	require.NoError(t, err)
   174  	edge := &pb.DirectedEdge{
   175  		Value: []byte("oh hey there"),
   176  		Label: "new-testing",
   177  	}
   178  	txn := &Txn{StartTs: 1}
   179  	addMutationHelper(t, ol, edge, Set, txn)
   180  	checkValue(t, ol, "oh hey there", txn.StartTs)
   181  
   182  	// Run the same check after committing.
   183  	ol.commitMutation(txn.StartTs, txn.StartTs+1)
   184  	checkValue(t, ol, "oh hey there", uint64(3))
   185  
   186  	// The value made it to the posting list. Changing it now.
   187  	edge.Value = []byte(strconv.Itoa(119))
   188  	txn = &Txn{StartTs: 3}
   189  	addMutationHelper(t, ol, edge, Set, txn)
   190  	checkValue(t, ol, "119", txn.StartTs)
   191  }
   192  
   193  func TestAddMutation_jchiu1(t *testing.T) {
   194  	key := x.DataKey("value", 12)
   195  	ol, err := GetNoStore(key)
   196  	require.NoError(t, err)
   197  
   198  	// Set value to cars and merge to BadgerDB.
   199  	edge := &pb.DirectedEdge{
   200  		Value: []byte("cars"),
   201  		Label: "jchiu",
   202  	}
   203  	txn := &Txn{StartTs: 1}
   204  	addMutationHelper(t, ol, edge, Set, txn)
   205  	ol.commitMutation(1, uint64(2))
   206  
   207  	// TODO: Read at commitTimestamp with all committed
   208  	require.EqualValues(t, 1, ol.Length(uint64(3), 0))
   209  	checkValue(t, ol, "cars", uint64(3))
   210  
   211  	txn = &Txn{StartTs: 3}
   212  	// Set value to newcars, but don't merge yet.
   213  	edge = &pb.DirectedEdge{
   214  		Value: []byte("newcars"),
   215  		Label: "jchiu",
   216  	}
   217  	addMutationHelper(t, ol, edge, Set, txn)
   218  	require.EqualValues(t, 1, ol.Length(txn.StartTs, 0))
   219  	checkValue(t, ol, "newcars", txn.StartTs)
   220  
   221  	// Set value to someothercars, but don't merge yet.
   222  	edge = &pb.DirectedEdge{
   223  		Value: []byte("someothercars"),
   224  		Label: "jchiu",
   225  	}
   226  	addMutationHelper(t, ol, edge, Set, txn)
   227  	require.EqualValues(t, 1, ol.Length(txn.StartTs, 0))
   228  	checkValue(t, ol, "someothercars", txn.StartTs)
   229  
   230  	// Set value back to the committed value cars, but don't merge yet.
   231  	edge = &pb.DirectedEdge{
   232  		Value: []byte("cars"),
   233  		Label: "jchiu",
   234  	}
   235  	addMutationHelper(t, ol, edge, Set, txn)
   236  	require.EqualValues(t, 1, ol.Length(txn.StartTs, 0))
   237  	checkValue(t, ol, "cars", txn.StartTs)
   238  }
   239  
   240  func TestAddMutation_DelSet(t *testing.T) {
   241  	key := x.DataKey("value", 1534)
   242  	ol, err := GetNoStore(key)
   243  	require.NoError(t, err)
   244  
   245  	// DO sp*, don't commit
   246  	// Del a value cars and but don't merge.
   247  	edge := &pb.DirectedEdge{
   248  		Value: []byte(x.Star),
   249  		Op:    pb.DirectedEdge_DEL,
   250  	}
   251  	txn := &Txn{StartTs: 1}
   252  	err = ol.addMutation(context.Background(), txn, edge)
   253  	require.NoError(t, err)
   254  
   255  	// Set value to newcars, commit it
   256  	edge = &pb.DirectedEdge{
   257  		Value: []byte("newcars"),
   258  	}
   259  	txn = &Txn{StartTs: 2}
   260  	addMutationHelper(t, ol, edge, Set, txn)
   261  	ol.commitMutation(2, uint64(3))
   262  	require.EqualValues(t, 1, ol.Length(3, 0))
   263  	checkValue(t, ol, "newcars", 3)
   264  }
   265  
   266  func TestAddMutation_DelRead(t *testing.T) {
   267  	key := x.DataKey("value", 1543)
   268  	ol, err := GetNoStore(key)
   269  	require.NoError(t, err)
   270  
   271  	// Set value to newcars, and commit it
   272  	edge := &pb.DirectedEdge{
   273  		Value: []byte("newcars"),
   274  	}
   275  	txn := &Txn{StartTs: 1}
   276  	addMutationHelper(t, ol, edge, Set, txn)
   277  	ol.commitMutation(1, uint64(2))
   278  	require.EqualValues(t, 1, ol.Length(2, 0))
   279  	checkValue(t, ol, "newcars", 2)
   280  
   281  	// DO sp*, don't commit
   282  	// Del a value cars and but don't merge.
   283  	edge = &pb.DirectedEdge{
   284  		Value: []byte(x.Star),
   285  		Op:    pb.DirectedEdge_DEL,
   286  	}
   287  	txn = &Txn{StartTs: 3}
   288  	err = ol.addMutation(context.Background(), txn, edge)
   289  	require.NoError(t, err)
   290  
   291  	// Part of same transaction as sp*, so should see zero length even
   292  	// if not committed yet.
   293  	require.EqualValues(t, 0, ol.Length(3, 0))
   294  
   295  	// Commit sp* only in oracle, don't apply to pl yet
   296  	ol.commitMutation(3, 5)
   297  
   298  	// This read should ignore sp*, since readts is 4 and it was committed at 5
   299  	require.EqualValues(t, 1, ol.Length(4, 0))
   300  	checkValue(t, ol, "newcars", 4)
   301  
   302  	require.EqualValues(t, 0, ol.Length(6, 0))
   303  }
   304  
   305  func TestAddMutation_jchiu2(t *testing.T) {
   306  	key := x.DataKey("value", 15)
   307  	ol, err := GetNoStore(key)
   308  	require.NoError(t, err)
   309  
   310  	// Del a value cars and but don't merge.
   311  	edge := &pb.DirectedEdge{
   312  		Value: []byte("cars"),
   313  		Label: "jchiu",
   314  	}
   315  	txn := &Txn{StartTs: 1}
   316  	addMutationHelper(t, ol, edge, Del, txn)
   317  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 0))
   318  
   319  	// Set value to newcars, but don't merge yet.
   320  	edge = &pb.DirectedEdge{
   321  		Value: []byte("newcars"),
   322  		Label: "jchiu",
   323  	}
   324  	addMutationHelper(t, ol, edge, Set, txn)
   325  	require.EqualValues(t, 1, ol.Length(txn.StartTs, 0))
   326  	checkValue(t, ol, "newcars", txn.StartTs)
   327  }
   328  
   329  func TestAddMutation_jchiu2_Commit(t *testing.T) {
   330  	key := x.DataKey("value", 16)
   331  	ol, err := GetNoStore(key)
   332  	require.NoError(t, err)
   333  
   334  	// Del a value cars and but don't merge.
   335  	edge := &pb.DirectedEdge{
   336  		Value: []byte("cars"),
   337  		Label: "jchiu",
   338  	}
   339  	txn := &Txn{StartTs: 1}
   340  	addMutationHelper(t, ol, edge, Del, txn)
   341  	ol.commitMutation(1, uint64(2))
   342  	require.EqualValues(t, 0, ol.Length(uint64(3), 0))
   343  
   344  	// Set value to newcars, but don't merge yet.
   345  	edge = &pb.DirectedEdge{
   346  		Value: []byte("newcars"),
   347  		Label: "jchiu",
   348  	}
   349  	txn = &Txn{StartTs: 3}
   350  	addMutationHelper(t, ol, edge, Set, txn)
   351  	ol.commitMutation(3, uint64(4))
   352  	require.EqualValues(t, 1, ol.Length(5, 0))
   353  	checkValue(t, ol, "newcars", 5)
   354  }
   355  
   356  func TestAddMutation_jchiu3(t *testing.T) {
   357  	key := x.DataKey("value", 29)
   358  	ol, err := GetNoStore(key)
   359  	require.NoError(t, err)
   360  
   361  	// Set value to cars and merge to BadgerDB.
   362  	edge := &pb.DirectedEdge{
   363  		Value: []byte("cars"),
   364  		Label: "jchiu",
   365  	}
   366  	txn := &Txn{StartTs: 1}
   367  	addMutationHelper(t, ol, edge, Set, txn)
   368  	ol.commitMutation(1, uint64(2))
   369  	require.Equal(t, 1, ol.Length(uint64(3), 0))
   370  	require.EqualValues(t, 1, ol.Length(uint64(3), 0))
   371  	checkValue(t, ol, "cars", uint64(3))
   372  
   373  	// Del a value cars and but don't merge.
   374  	edge = &pb.DirectedEdge{
   375  		Value: []byte("cars"),
   376  		Label: "jchiu",
   377  	}
   378  	txn = &Txn{StartTs: 3}
   379  	addMutationHelper(t, ol, edge, Del, txn)
   380  	require.Equal(t, 0, ol.Length(txn.StartTs, 0))
   381  
   382  	// Set value to newcars, but don't merge yet.
   383  	edge = &pb.DirectedEdge{
   384  		Value: []byte("newcars"),
   385  		Label: "jchiu",
   386  	}
   387  	addMutationHelper(t, ol, edge, Set, txn)
   388  	require.EqualValues(t, 1, ol.Length(txn.StartTs, 0))
   389  	checkValue(t, ol, "newcars", txn.StartTs)
   390  
   391  	// Del a value newcars and but don't merge.
   392  	edge = &pb.DirectedEdge{
   393  		Value: []byte("newcars"),
   394  		Label: "jchiu",
   395  	}
   396  	addMutationHelper(t, ol, edge, Del, txn)
   397  	require.Equal(t, 0, ol.Length(txn.StartTs, 0))
   398  }
   399  
   400  func TestAddMutation_mrjn1(t *testing.T) {
   401  	key := x.DataKey("value", 21)
   402  	ol, err := GetNoStore(key)
   403  	require.NoError(t, err)
   404  
   405  	// Set a value cars and merge.
   406  	edge := &pb.DirectedEdge{
   407  		Value: []byte("cars"),
   408  		Label: "jchiu",
   409  	}
   410  	txn := &Txn{StartTs: 1}
   411  	addMutationHelper(t, ol, edge, Set, txn)
   412  	ol.commitMutation(1, uint64(2))
   413  
   414  	// Delete the previously committed value cars. But don't merge.
   415  	txn = &Txn{StartTs: 3}
   416  	edge = &pb.DirectedEdge{
   417  		Value: []byte("cars"),
   418  		Label: "jchiu",
   419  	}
   420  	addMutationHelper(t, ol, edge, Del, txn)
   421  	require.Equal(t, 0, ol.Length(txn.StartTs, 0))
   422  
   423  	// Do this again to cover Del, muid == curUid, inPlist test case.
   424  	// Delete the previously committed value cars. But don't merge.
   425  	edge = &pb.DirectedEdge{
   426  		Value: []byte("cars"),
   427  		Label: "jchiu",
   428  	}
   429  	addMutationHelper(t, ol, edge, Del, txn)
   430  	require.Equal(t, 0, ol.Length(txn.StartTs, 0))
   431  
   432  	// Set the value again to cover Set, muid == curUid, inPlist test case.
   433  	// Set the previously committed value cars. But don't merge.
   434  	edge = &pb.DirectedEdge{
   435  		Value: []byte("cars"),
   436  		Label: "jchiu",
   437  	}
   438  	addMutationHelper(t, ol, edge, Set, txn)
   439  	checkValue(t, ol, "cars", txn.StartTs)
   440  
   441  	// Delete it again, just for fun.
   442  	edge = &pb.DirectedEdge{
   443  		Value: []byte("cars"),
   444  		Label: "jchiu",
   445  	}
   446  	addMutationHelper(t, ol, edge, Del, txn)
   447  	require.Equal(t, 0, ol.Length(txn.StartTs, 0))
   448  }
   449  
   450  func TestMillion(t *testing.T) {
   451  	// Ensure list is stored in a single part.
   452  	maxListSize = math.MaxInt32
   453  
   454  	key := x.DataKey("bal", 1331)
   455  	ol, err := getNew(key, ps)
   456  	require.NoError(t, err)
   457  	var commits int
   458  	N := int(1e6)
   459  	for i := 2; i <= N; i += 2 {
   460  		edge := &pb.DirectedEdge{
   461  			ValueId: uint64(i),
   462  		}
   463  		txn := Txn{StartTs: uint64(i)}
   464  		addMutationHelper(t, ol, edge, Set, &txn)
   465  		require.NoError(t, ol.commitMutation(uint64(i), uint64(i)+1))
   466  		if i%10000 == 0 {
   467  			// Do a rollup, otherwise, it gets too slow to add a million mutations to one posting
   468  			// list.
   469  			t.Logf("Start Ts: %d. Rolling up posting list.\n", txn.StartTs)
   470  			kvs, err := ol.Rollup()
   471  			require.NoError(t, err)
   472  			require.NoError(t, writePostingListToDisk(kvs))
   473  			ol, err = getNew(key, ps)
   474  			require.NoError(t, err)
   475  		}
   476  		commits++
   477  	}
   478  
   479  	t.Logf("Completed a million writes.\n")
   480  	opt := ListOptions{ReadTs: uint64(N) + 1}
   481  	l, err := ol.Uids(opt)
   482  	require.NoError(t, err)
   483  	require.Equal(t, commits, len(l.Uids), "List of Uids received: %+v", l.Uids)
   484  	for i, uid := range l.Uids {
   485  		require.Equal(t, uint64(i+1)*2, uid)
   486  	}
   487  }
   488  
   489  // Test the various mutate, commit and abort sequences.
   490  func TestAddMutation_mrjn2(t *testing.T) {
   491  	ctx := context.Background()
   492  	key := x.DataKey("bal", 1001)
   493  	ol, err := getNew(key, ps)
   494  	require.NoError(t, err)
   495  	var readTs uint64
   496  	for readTs = 1; readTs < 10; readTs++ {
   497  		edge := &pb.DirectedEdge{
   498  			ValueId:   readTs,
   499  			ValueType: pb.Posting_INT,
   500  		}
   501  		txn := &Txn{StartTs: readTs}
   502  		addMutationHelper(t, ol, edge, Set, txn)
   503  	}
   504  	for i := 1; i < 10; i++ {
   505  		// Each of these txns see their own write.
   506  		opt := ListOptions{ReadTs: uint64(i)}
   507  		list, err := ol.Uids(opt)
   508  		require.NoError(t, err)
   509  		require.EqualValues(t, 1, len(list.Uids))
   510  		require.EqualValues(t, uint64(i), list.Uids[0])
   511  	}
   512  	require.EqualValues(t, 0, ol.Length(readTs, 0))
   513  	require.NoError(t, ol.commitMutation(1, 0))
   514  	require.NoError(t, ol.commitMutation(3, 4))
   515  	require.NoError(t, ol.commitMutation(6, 10))
   516  	require.NoError(t, ol.commitMutation(9, 14))
   517  	require.EqualValues(t, 3, ol.Length(15, 0)) // The three commits.
   518  
   519  	{
   520  		edge := &pb.DirectedEdge{
   521  			Value: []byte(x.Star),
   522  			Op:    pb.DirectedEdge_DEL,
   523  		}
   524  		txn := &Txn{StartTs: 7}
   525  		err := ol.addMutation(ctx, txn, edge)
   526  		require.NoError(t, err)
   527  
   528  		// Add edge just to test that the deletion still happens.
   529  		edge = &pb.DirectedEdge{
   530  			ValueId:   7,
   531  			ValueType: pb.Posting_INT,
   532  		}
   533  		err = ol.addMutation(ctx, txn, edge)
   534  		require.NoError(t, err)
   535  
   536  		require.EqualValues(t, 3, ol.Length(15, 0)) // The three commits should still be found.
   537  		require.NoError(t, ol.commitMutation(7, 11))
   538  
   539  		require.EqualValues(t, 2, ol.Length(10, 0)) // Two commits should be found.
   540  		require.EqualValues(t, 1, ol.Length(12, 0)) // Only one commit should be found.
   541  		require.EqualValues(t, 2, ol.Length(15, 0)) // Only one commit should be found.
   542  	}
   543  	{
   544  		edge := &pb.DirectedEdge{
   545  			Value: []byte(x.Star),
   546  			Op:    pb.DirectedEdge_DEL,
   547  		}
   548  		txn := &Txn{StartTs: 5}
   549  		err := ol.addMutation(ctx, txn, edge)
   550  		require.NoError(t, err)
   551  		require.NoError(t, ol.commitMutation(5, 7))
   552  
   553  		// Commits are:
   554  		// 4, 7 (Delete *), 10, 11 (Delete *), 14
   555  		require.EqualValues(t, 1, ol.Length(8, 0)) // Nothing below 8, but consider itself.
   556  		require.NoError(t, ol.commitMutation(8, 0))
   557  		require.EqualValues(t, 0, ol.Length(8, 0))  // Nothing <= 8.
   558  		require.EqualValues(t, 1, ol.Length(10, 0)) // Find committed 10.
   559  		require.EqualValues(t, 1, ol.Length(12, 0)) // Find committed 11.
   560  		require.EqualValues(t, 2, ol.Length(15, 0)) // Find committed 14.
   561  		opts := ListOptions{ReadTs: 15}
   562  		list, err := ol.Uids(opts)
   563  		require.NoError(t, err)
   564  		require.EqualValues(t, 7, list.Uids[0])
   565  		require.EqualValues(t, 9, list.Uids[1])
   566  	}
   567  }
   568  
   569  func TestAddMutation_gru(t *testing.T) {
   570  	key := x.DataKey("question.tag", 0x01)
   571  	ol, err := getNew(key, ps)
   572  	require.NoError(t, err)
   573  
   574  	{
   575  		// Set two tag ids and merge.
   576  		edge := &pb.DirectedEdge{
   577  			ValueId: 0x2b693088816b04b7,
   578  			Label:   "gru",
   579  		}
   580  		txn := &Txn{StartTs: 1}
   581  		addMutationHelper(t, ol, edge, Set, txn)
   582  		edge = &pb.DirectedEdge{
   583  			ValueId: 0x29bf442b48a772e0,
   584  			Label:   "gru",
   585  		}
   586  		addMutationHelper(t, ol, edge, Set, txn)
   587  		ol.commitMutation(1, uint64(2))
   588  	}
   589  
   590  	{
   591  		edge := &pb.DirectedEdge{
   592  			ValueId: 0x38dec821d2ac3a79,
   593  			Label:   "gru",
   594  		}
   595  		txn := &Txn{StartTs: 3}
   596  		addMutationHelper(t, ol, edge, Set, txn)
   597  		edge = &pb.DirectedEdge{
   598  			ValueId: 0x2b693088816b04b7,
   599  			Label:   "gru",
   600  		}
   601  		addMutationHelper(t, ol, edge, Del, txn)
   602  		ol.commitMutation(3, uint64(4))
   603  	}
   604  }
   605  
   606  func TestAddMutation_gru2(t *testing.T) {
   607  	key := x.DataKey("question.tag", 0x100)
   608  	ol, err := getNew(key, ps)
   609  	require.NoError(t, err)
   610  
   611  	{
   612  		// Set two tag ids and merge.
   613  		edge := &pb.DirectedEdge{
   614  			ValueId: 0x02,
   615  			Label:   "gru",
   616  		}
   617  		txn := &Txn{StartTs: 1}
   618  		addMutationHelper(t, ol, edge, Set, txn)
   619  		edge = &pb.DirectedEdge{
   620  			ValueId: 0x03,
   621  			Label:   "gru",
   622  		}
   623  		txn = &Txn{StartTs: 1}
   624  		addMutationHelper(t, ol, edge, Set, txn)
   625  		ol.commitMutation(1, uint64(2))
   626  	}
   627  
   628  	{
   629  		// Lets set a new tag and delete the two older ones.
   630  		edge := &pb.DirectedEdge{
   631  			ValueId: 0x02,
   632  			Label:   "gru",
   633  		}
   634  		txn := &Txn{StartTs: 3}
   635  		addMutationHelper(t, ol, edge, Del, txn)
   636  		edge = &pb.DirectedEdge{
   637  			ValueId: 0x03,
   638  			Label:   "gru",
   639  		}
   640  		addMutationHelper(t, ol, edge, Del, txn)
   641  
   642  		edge = &pb.DirectedEdge{
   643  			ValueId: 0x04,
   644  			Label:   "gru",
   645  		}
   646  		addMutationHelper(t, ol, edge, Set, txn)
   647  
   648  		ol.commitMutation(3, uint64(4))
   649  	}
   650  
   651  	// Posting list should just have the new tag.
   652  	uids := []uint64{0x04}
   653  	require.Equal(t, uids, listToArray(t, 0, ol, uint64(5)))
   654  }
   655  
   656  func TestAddAndDelMutation(t *testing.T) {
   657  	// Ensure each test uses unique key since we don't clear the postings
   658  	// after each test
   659  	key := x.DataKey("dummy_key", 0x927)
   660  	ol, err := getNew(key, ps)
   661  	require.NoError(t, err)
   662  
   663  	{
   664  		edge := &pb.DirectedEdge{
   665  			ValueId: 0x02,
   666  			Label:   "gru",
   667  		}
   668  		txn := &Txn{StartTs: 1}
   669  		addMutationHelper(t, ol, edge, Set, txn)
   670  		ol.commitMutation(1, uint64(2))
   671  	}
   672  
   673  	{
   674  		edge := &pb.DirectedEdge{
   675  			ValueId: 0x02,
   676  			Label:   "gru",
   677  		}
   678  		txn := &Txn{StartTs: 3}
   679  		addMutationHelper(t, ol, edge, Del, txn)
   680  		addMutationHelper(t, ol, edge, Del, txn)
   681  		ol.commitMutation(3, uint64(4))
   682  
   683  		checkUids(t, ol, []uint64{}, 5)
   684  	}
   685  	checkUids(t, ol, []uint64{}, 5)
   686  }
   687  
   688  func TestAfterUIDCount(t *testing.T) {
   689  	key := x.DataKey("value", 22)
   690  	ol, err := getNew(key, ps)
   691  	require.NoError(t, err)
   692  	// Set value to cars and merge to BadgerDB.
   693  	edge := &pb.DirectedEdge{
   694  		Label: "jchiu",
   695  	}
   696  
   697  	txn := &Txn{StartTs: 1}
   698  	for i := 100; i < 300; i++ {
   699  		edge.ValueId = uint64(i)
   700  		addMutationHelper(t, ol, edge, Set, txn)
   701  	}
   702  	require.EqualValues(t, 200, ol.Length(txn.StartTs, 0))
   703  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 199))
   704  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   705  
   706  	// Delete half of the edges.
   707  	for i := 100; i < 300; i += 2 {
   708  		edge.ValueId = uint64(i)
   709  		addMutationHelper(t, ol, edge, Del, txn)
   710  	}
   711  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 0))
   712  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 199))
   713  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   714  
   715  	// Try to delete half of the edges. Redundant deletes.
   716  	for i := 100; i < 300; i += 2 {
   717  		edge.ValueId = uint64(i)
   718  		addMutationHelper(t, ol, edge, Del, txn)
   719  	}
   720  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 0))
   721  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 199))
   722  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   723  
   724  	// Delete everything.
   725  	for i := 100; i < 300; i++ {
   726  		edge.ValueId = uint64(i)
   727  		addMutationHelper(t, ol, edge, Del, txn)
   728  	}
   729  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 0))
   730  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 199))
   731  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   732  
   733  	// Insert 1/4 of the edges.
   734  	for i := 100; i < 300; i += 4 {
   735  		edge.ValueId = uint64(i)
   736  		addMutationHelper(t, ol, edge, Set, txn)
   737  	}
   738  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 0))
   739  	require.EqualValues(t, 25, ol.Length(txn.StartTs, 199))
   740  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   741  
   742  	// Insert 1/4 of the edges.
   743  	edge.Label = "somethingelse"
   744  	for i := 100; i < 300; i += 4 {
   745  		edge.ValueId = uint64(i)
   746  		addMutationHelper(t, ol, edge, Set, txn)
   747  	}
   748  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 0)) // Expect no change.
   749  	require.EqualValues(t, 25, ol.Length(txn.StartTs, 199))
   750  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   751  
   752  	// Insert 1/4 of the edges.
   753  	for i := 103; i < 300; i += 4 {
   754  		edge.ValueId = uint64(i)
   755  		addMutationHelper(t, ol, edge, Set, txn)
   756  	}
   757  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 0))
   758  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 199))
   759  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   760  }
   761  
   762  func TestAfterUIDCount2(t *testing.T) {
   763  	key := x.DataKey("value", 23)
   764  	ol, err := getNew(key, ps)
   765  	require.NoError(t, err)
   766  
   767  	// Set value to cars and merge to BadgerDB.
   768  	edge := &pb.DirectedEdge{
   769  		Label: "jchiu",
   770  	}
   771  
   772  	txn := &Txn{StartTs: 1}
   773  	for i := 100; i < 300; i++ {
   774  		edge.ValueId = uint64(i)
   775  		addMutationHelper(t, ol, edge, Set, txn)
   776  	}
   777  	require.EqualValues(t, 200, ol.Length(txn.StartTs, 0))
   778  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 199))
   779  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   780  
   781  	// Re-insert 1/4 of the edges. Counts should not change.
   782  	edge.Label = "somethingelse"
   783  	for i := 100; i < 300; i += 4 {
   784  		edge.ValueId = uint64(i)
   785  		addMutationHelper(t, ol, edge, Set, txn)
   786  	}
   787  	require.EqualValues(t, 200, ol.Length(txn.StartTs, 0))
   788  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 199))
   789  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   790  }
   791  
   792  func TestDelete(t *testing.T) {
   793  	key := x.DataKey("value", 25)
   794  	ol, err := getNew(key, ps)
   795  	require.NoError(t, err)
   796  
   797  	// Set value to cars and merge to BadgerDB.
   798  	edge := &pb.DirectedEdge{
   799  		Label: "jchiu",
   800  	}
   801  
   802  	txn := &Txn{StartTs: 1}
   803  	for i := 1; i <= 30; i++ {
   804  		edge.ValueId = uint64(i)
   805  		addMutationHelper(t, ol, edge, Set, txn)
   806  	}
   807  	require.EqualValues(t, 30, ol.Length(txn.StartTs, 0))
   808  	edge.Value = []byte(x.Star)
   809  	addMutationHelper(t, ol, edge, Del, txn)
   810  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 0))
   811  	ol.commitMutation(txn.StartTs, txn.StartTs+1)
   812  
   813  	require.EqualValues(t, 0, ol.Length(txn.StartTs+2, 0))
   814  }
   815  
   816  func TestAfterUIDCountWithCommit(t *testing.T) {
   817  	key := x.DataKey("value", 26)
   818  	ol, err := getNew(key, ps)
   819  	require.NoError(t, err)
   820  
   821  	// Set value to cars and merge to BadgerDB.
   822  	edge := &pb.DirectedEdge{
   823  		Label: "jchiu",
   824  	}
   825  
   826  	txn := &Txn{StartTs: 1}
   827  	for i := 100; i < 400; i++ {
   828  		edge.ValueId = uint64(i)
   829  		addMutationHelper(t, ol, edge, Set, txn)
   830  	}
   831  	require.EqualValues(t, 300, ol.Length(txn.StartTs, 0))
   832  	require.EqualValues(t, 200, ol.Length(txn.StartTs, 199))
   833  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 400))
   834  
   835  	// Commit to database.
   836  	ol.commitMutation(txn.StartTs, txn.StartTs+1)
   837  
   838  	txn = &Txn{StartTs: 3}
   839  	// Mutation layer starts afresh from here.
   840  	// Delete half of the edges.
   841  	for i := 100; i < 400; i += 2 {
   842  		edge.ValueId = uint64(i)
   843  		addMutationHelper(t, ol, edge, Del, txn)
   844  	}
   845  	require.EqualValues(t, 150, ol.Length(txn.StartTs, 0))
   846  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 199))
   847  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 400))
   848  
   849  	// Try to delete half of the edges. Redundant deletes.
   850  	for i := 100; i < 400; i += 2 {
   851  		edge.ValueId = uint64(i)
   852  		addMutationHelper(t, ol, edge, Del, txn)
   853  	}
   854  	require.EqualValues(t, 150, ol.Length(txn.StartTs, 0))
   855  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 199))
   856  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 400))
   857  
   858  	// Delete everything.
   859  	for i := 100; i < 400; i++ {
   860  		edge.ValueId = uint64(i)
   861  		addMutationHelper(t, ol, edge, Del, txn)
   862  	}
   863  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 0))
   864  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 199))
   865  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 400))
   866  
   867  	// Insert 1/4 of the edges.
   868  	for i := 100; i < 300; i += 4 {
   869  		edge.ValueId = uint64(i)
   870  		addMutationHelper(t, ol, edge, Set, txn)
   871  	}
   872  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 0))
   873  	require.EqualValues(t, 25, ol.Length(txn.StartTs, 199))
   874  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   875  
   876  	// Insert 1/4 of the edges.
   877  	edge.Label = "somethingelse"
   878  	for i := 100; i < 300; i += 4 {
   879  		edge.ValueId = uint64(i)
   880  		addMutationHelper(t, ol, edge, Set, txn)
   881  	}
   882  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 0)) // Expect no change.
   883  	require.EqualValues(t, 25, ol.Length(txn.StartTs, 199))
   884  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   885  
   886  	// Insert 1/4 of the edges.
   887  	for i := 103; i < 300; i += 4 {
   888  		edge.ValueId = uint64(i)
   889  		addMutationHelper(t, ol, edge, Set, txn)
   890  	}
   891  	require.EqualValues(t, 100, ol.Length(txn.StartTs, 0))
   892  	require.EqualValues(t, 50, ol.Length(txn.StartTs, 199))
   893  	require.EqualValues(t, 0, ol.Length(txn.StartTs, 300))
   894  }
   895  
   896  func createMultiPartList(t *testing.T, size int, addLabel bool) (*List, int) {
   897  	// For testing, set the max list size to a lower threshold.
   898  	maxListSize = 5000
   899  	defer func() {
   900  		maxListSize = math.MaxInt32
   901  	}()
   902  
   903  	key := x.DataKey("multi-bal", 1331)
   904  	ol, err := getNew(key, ps)
   905  	require.NoError(t, err)
   906  	commits := 0
   907  	for i := 1; i <= size; i++ {
   908  		edge := &pb.DirectedEdge{
   909  			ValueId: uint64(i),
   910  		}
   911  		if addLabel {
   912  			edge.Label = strconv.Itoa(i)
   913  		}
   914  
   915  		txn := Txn{StartTs: uint64(i)}
   916  		addMutationHelper(t, ol, edge, Set, &txn)
   917  		require.NoError(t, ol.commitMutation(uint64(i), uint64(i)+1))
   918  		if i%2000 == 0 {
   919  			kvs, err := ol.Rollup()
   920  			require.NoError(t, err)
   921  			require.NoError(t, writePostingListToDisk(kvs))
   922  			ol, err = getNew(key, ps)
   923  			require.NoError(t, err)
   924  		}
   925  		commits++
   926  	}
   927  
   928  	kvs, err := ol.Rollup()
   929  	require.NoError(t, err)
   930  	require.NoError(t, writePostingListToDisk(kvs))
   931  	ol, err = getNew(key, ps)
   932  	require.NoError(t, err)
   933  
   934  	return ol, commits
   935  }
   936  
   937  func createAndDeleteMultiPartList(t *testing.T, size int) (*List, int) {
   938  	// For testing, set the max list size to a lower threshold.
   939  	maxListSize = 5000
   940  	defer func() {
   941  		maxListSize = math.MaxInt32
   942  	}()
   943  
   944  	key := x.DataKey("bal_del", 1331)
   945  	ol, err := getNew(key, ps)
   946  	require.NoError(t, err)
   947  	commits := 0
   948  	for i := 1; i <= size; i++ {
   949  		edge := &pb.DirectedEdge{
   950  			ValueId: uint64(i),
   951  		}
   952  
   953  		txn := Txn{StartTs: uint64(i)}
   954  		addMutationHelper(t, ol, edge, Set, &txn)
   955  		require.NoError(t, ol.commitMutation(uint64(i), uint64(i)+1))
   956  		if i%2000 == 0 {
   957  			kvs, err := ol.Rollup()
   958  			require.NoError(t, err)
   959  			require.NoError(t, writePostingListToDisk(kvs))
   960  			ol, err = getNew(key, ps)
   961  			require.NoError(t, err)
   962  		}
   963  		commits++
   964  	}
   965  
   966  	// Delete all the previously inserted entries from the list.
   967  	baseStartTs := uint64(size) + 1
   968  	for i := 1; i <= size; i++ {
   969  		edge := &pb.DirectedEdge{
   970  			ValueId: uint64(i),
   971  		}
   972  		txn := Txn{StartTs: baseStartTs + uint64(i)}
   973  		addMutationHelper(t, ol, edge, Del, &txn)
   974  		require.NoError(t, ol.commitMutation(baseStartTs+uint64(i), baseStartTs+uint64(i)+1))
   975  		if i%2000 == 0 {
   976  			kvs, err := ol.Rollup()
   977  			require.NoError(t, err)
   978  			require.NoError(t, writePostingListToDisk(kvs))
   979  			ol, err = getNew(key, ps)
   980  			require.NoError(t, err)
   981  		}
   982  		commits++
   983  	}
   984  
   985  	return ol, commits
   986  }
   987  
   988  func writePostingListToDisk(kvs []*bpb.KV) error {
   989  	writer := NewTxnWriter(pstore)
   990  	for _, kv := range kvs {
   991  		if err := writer.SetAt(kv.Key, kv.Value, kv.UserMeta[0], kv.Version); err != nil {
   992  			return err
   993  		}
   994  	}
   995  	return writer.Flush()
   996  }
   997  
   998  // Create a multi-part list and verify all the uids are there.
   999  func TestMultiPartListBasic(t *testing.T) {
  1000  	size := int(1e5)
  1001  	ol, commits := createMultiPartList(t, size, false)
  1002  	t.Logf("List parts %v", len(ol.plist.Splits))
  1003  	opt := ListOptions{ReadTs: uint64(size) + 1}
  1004  	l, err := ol.Uids(opt)
  1005  	require.NoError(t, err)
  1006  	require.Equal(t, commits, len(l.Uids), "List of Uids received: %+v", l.Uids)
  1007  	for i, uid := range l.Uids {
  1008  		require.Equal(t, uint64(i+1), uid)
  1009  	}
  1010  }
  1011  
  1012  // Verify that iteration works with an afterUid value greater than zero.
  1013  func TestMultiPartListIterAfterUid(t *testing.T) {
  1014  	size := int(1e5)
  1015  	ol, _ := createMultiPartList(t, size, false)
  1016  	t.Logf("List parts %v", len(ol.plist.Splits))
  1017  
  1018  	var visitedUids []uint64
  1019  	ol.Iterate(uint64(size+1), 50000, func(p *pb.Posting) error {
  1020  		visitedUids = append(visitedUids, p.Uid)
  1021  		return nil
  1022  	})
  1023  	require.Equal(t, 50000, len(visitedUids))
  1024  	for i, uid := range visitedUids {
  1025  		require.Equal(t, uint64(50000+i+1), uid)
  1026  	}
  1027  }
  1028  
  1029  // Verify that postings can be retrieved in multi-part lists.
  1030  func TestMultiPartListWithPostings(t *testing.T) {
  1031  	size := int(1e5)
  1032  	ol, commits := createMultiPartList(t, size, true)
  1033  	t.Logf("List parts %v", len(ol.plist.Splits))
  1034  
  1035  	var labels []string
  1036  	err := ol.Iterate(uint64(size)+1, 0, func(p *pb.Posting) error {
  1037  		if len(p.Label) > 0 {
  1038  			labels = append(labels, p.Label)
  1039  		}
  1040  		return nil
  1041  	})
  1042  	require.NoError(t, err)
  1043  	require.Equal(t, commits, len(labels))
  1044  	for i, label := range labels {
  1045  		require.Equal(t, label, strconv.Itoa(int(i+1)))
  1046  	}
  1047  }
  1048  
  1049  // Verify marshaling of multi-part lists.
  1050  func TestMultiPartListMarshal(t *testing.T) {
  1051  	size := int(1e5)
  1052  	ol, _ := createMultiPartList(t, size, false)
  1053  	t.Logf("List parts %v", len(ol.plist.Splits))
  1054  
  1055  	kvs, err := ol.Rollup()
  1056  	require.NoError(t, err)
  1057  	require.Equal(t, len(kvs), len(ol.plist.Splits)+1)
  1058  	require.NoError(t, writePostingListToDisk(kvs))
  1059  
  1060  	sort.Slice(kvs, func(i, j int) bool {
  1061  		return string(kvs[i].Key) < string(kvs[j].Key)
  1062  	})
  1063  
  1064  	key := x.DataKey("multi-bal", 1331)
  1065  	require.Equal(t, key, kvs[0].Key)
  1066  
  1067  	for i, startUid := range ol.plist.Splits {
  1068  		partKey, err := x.GetSplitKey(key, startUid)
  1069  		require.NoError(t, err)
  1070  		require.Equal(t, partKey, kvs[i+1].Key)
  1071  		part, err := ol.readListPart(startUid)
  1072  		require.NoError(t, err)
  1073  		data, err := part.Marshal()
  1074  		require.NoError(t, err)
  1075  		require.Equal(t, data, kvs[i+1].Value)
  1076  		require.Equal(t, []byte{BitCompletePosting}, kvs[i+1].UserMeta)
  1077  		require.Equal(t, ol.minTs, kvs[i+1].Version)
  1078  	}
  1079  }
  1080  
  1081  // Verify that writing a multi-part list to disk works correctly.
  1082  func TestMultiPartListWriteToDisk(t *testing.T) {
  1083  	size := int(1e5)
  1084  	originalList, commits := createMultiPartList(t, size, false)
  1085  
  1086  	kvs, err := originalList.Rollup()
  1087  	require.NoError(t, err)
  1088  	require.Equal(t, len(kvs), len(originalList.plist.Splits)+1)
  1089  
  1090  	require.NoError(t, writePostingListToDisk(kvs))
  1091  	newList, err := getNew(kvs[0].Key, ps)
  1092  	require.NoError(t, err)
  1093  
  1094  	opt := ListOptions{ReadTs: uint64(size) + 1}
  1095  	originalUids, err := originalList.Uids(opt)
  1096  	require.NoError(t, err)
  1097  	newUids, err := newList.Uids(opt)
  1098  	require.NoError(t, err)
  1099  	require.Equal(t, commits, len(originalUids.Uids))
  1100  	require.Equal(t, len(originalUids.Uids), len(newUids.Uids))
  1101  	for i := range originalUids.Uids {
  1102  		require.Equal(t, originalUids.Uids[i], newUids.Uids[i])
  1103  	}
  1104  }
  1105  
  1106  // Verify that adding and deleting all the entries returns an empty list.
  1107  func TestMultiPartListDelete(t *testing.T) {
  1108  	size := int(1e4)
  1109  	ol, commits := createAndDeleteMultiPartList(t, size)
  1110  	t.Logf("List parts %v", len(ol.plist.Splits))
  1111  	require.Equal(t, size*2, commits)
  1112  
  1113  	counter := 0
  1114  	ol.Iterate(math.MaxUint64, 0, func(p *pb.Posting) error {
  1115  		counter++
  1116  		return nil
  1117  	})
  1118  	require.Equal(t, 0, counter)
  1119  
  1120  	kvs, err := ol.Rollup()
  1121  	require.NoError(t, err)
  1122  	require.Equal(t, len(kvs), 1)
  1123  
  1124  	for _, kv := range kvs {
  1125  		require.Equal(t, []byte{BitEmptyPosting}, kv.UserMeta)
  1126  		require.Equal(t, ol.minTs, kv.Version)
  1127  	}
  1128  }
  1129  
  1130  // Verify that the first part of a multi-part list is kept even when all its
  1131  // entries have been deleted. Do this by creating a list, deleting the first
  1132  // half, and ensuring iteration and mutation still work as expected.
  1133  func TestMultiPartListDeleteAndAdd(t *testing.T) {
  1134  	size := int(1e5)
  1135  	// For testing, set the max list size to a lower threshold.
  1136  	maxListSize = 5000
  1137  	defer func() {
  1138  		maxListSize = math.MaxInt32
  1139  	}()
  1140  
  1141  	// Add entries to the maps.
  1142  	key := x.DataKey("del_add", 1331)
  1143  	ol, err := getNew(key, ps)
  1144  	require.NoError(t, err)
  1145  	for i := 1; i <= size; i++ {
  1146  		edge := &pb.DirectedEdge{
  1147  			ValueId: uint64(i),
  1148  		}
  1149  
  1150  		txn := Txn{StartTs: uint64(i)}
  1151  		addMutationHelper(t, ol, edge, Set, &txn)
  1152  		require.NoError(t, ol.commitMutation(uint64(i), uint64(i)+1))
  1153  		if i%2000 == 0 {
  1154  			kvs, err := ol.Rollup()
  1155  			require.NoError(t, err)
  1156  			require.NoError(t, writePostingListToDisk(kvs))
  1157  			ol, err = getNew(key, ps)
  1158  			require.NoError(t, err)
  1159  		}
  1160  	}
  1161  
  1162  	// Verify all entries are in the list.
  1163  	opt := ListOptions{ReadTs: math.MaxUint64}
  1164  	l, err := ol.Uids(opt)
  1165  	require.NoError(t, err)
  1166  	require.Equal(t, size, len(l.Uids), "List of Uids received: %+v", l.Uids)
  1167  	for i, uid := range l.Uids {
  1168  		require.Equal(t, uint64(i+1), uid)
  1169  	}
  1170  
  1171  	// Delete the first half of the previously inserted entries from the list.
  1172  	baseStartTs := uint64(size) + 1
  1173  	for i := 1; i <= 50000; i++ {
  1174  		edge := &pb.DirectedEdge{
  1175  			ValueId: uint64(i),
  1176  		}
  1177  		txn := Txn{StartTs: baseStartTs + uint64(i)}
  1178  		addMutationHelper(t, ol, edge, Del, &txn)
  1179  		require.NoError(t, ol.commitMutation(baseStartTs+uint64(i), baseStartTs+uint64(i)+1))
  1180  		if i%2000 == 0 {
  1181  			kvs, err := ol.Rollup()
  1182  			require.NoError(t, err)
  1183  			require.NoError(t, writePostingListToDisk(kvs))
  1184  			ol, err = getNew(key, ps)
  1185  			require.NoError(t, err)
  1186  		}
  1187  	}
  1188  
  1189  	// Rollup list at the end of all the deletions.
  1190  	kvs, err := ol.Rollup()
  1191  	require.NoError(t, err)
  1192  	require.NoError(t, writePostingListToDisk(kvs))
  1193  	ol, err = getNew(key, ps)
  1194  	require.NoError(t, err)
  1195  
  1196  	// Verify that the entries were actually deleted.
  1197  	opt = ListOptions{ReadTs: math.MaxUint64}
  1198  	l, err = ol.Uids(opt)
  1199  	require.NoError(t, err)
  1200  	require.Equal(t, 50000, len(l.Uids), "List of Uids received: %+v", l.Uids)
  1201  	for i, uid := range l.Uids {
  1202  		require.Equal(t, 50000+uint64(i+1), uid)
  1203  	}
  1204  
  1205  	// Re-add the entries that were just deleted.
  1206  	baseStartTs = uint64(2*size) + 1
  1207  	for i := 1; i <= 50000; i++ {
  1208  		edge := &pb.DirectedEdge{
  1209  			ValueId: uint64(i),
  1210  		}
  1211  		txn := Txn{StartTs: baseStartTs + uint64(i)}
  1212  		addMutationHelper(t, ol, edge, Set, &txn)
  1213  		require.NoError(t, ol.commitMutation(baseStartTs+uint64(i), baseStartTs+uint64(i)+1))
  1214  
  1215  		if i%2000 == 0 {
  1216  			kvs, err := ol.Rollup()
  1217  			require.NoError(t, err)
  1218  			require.NoError(t, writePostingListToDisk(kvs))
  1219  			ol, err = getNew(key, ps)
  1220  			require.NoError(t, err)
  1221  		}
  1222  	}
  1223  
  1224  	// Rollup list at the end of all the additions
  1225  	kvs, err = ol.Rollup()
  1226  	require.NoError(t, err)
  1227  	require.NoError(t, writePostingListToDisk(kvs))
  1228  	ol, err = getNew(key, ps)
  1229  	require.NoError(t, err)
  1230  
  1231  	// Verify all entries are once again in the list.
  1232  	opt = ListOptions{ReadTs: math.MaxUint64}
  1233  	l, err = ol.Uids(opt)
  1234  	require.NoError(t, err)
  1235  	require.Equal(t, size, len(l.Uids), "List of Uids received: %+v", l.Uids)
  1236  	for i, uid := range l.Uids {
  1237  		require.Equal(t, uint64(i+1), uid)
  1238  	}
  1239  }
  1240  
  1241  var ps *badger.DB
  1242  
  1243  func TestMain(m *testing.M) {
  1244  	x.Init()
  1245  	Config.AllottedMemory = 1024.0
  1246  	Config.CommitFraction = 0.10
  1247  
  1248  	dir, err := ioutil.TempDir("", "storetest_")
  1249  	x.Check(err)
  1250  
  1251  	ps, err = badger.OpenManaged(badger.DefaultOptions(dir))
  1252  	x.Check(err)
  1253  	Init(ps)
  1254  	schema.Init(ps)
  1255  
  1256  	r := m.Run()
  1257  
  1258  	os.RemoveAll(dir)
  1259  	os.Exit(r)
  1260  }
  1261  
  1262  func BenchmarkAddMutations(b *testing.B) {
  1263  	key := x.DataKey("name", 1)
  1264  	l, err := getNew(key, ps)
  1265  	if err != nil {
  1266  		b.Error(err)
  1267  	}
  1268  	b.ResetTimer()
  1269  
  1270  	ctx := context.Background()
  1271  	for i := 0; i < b.N; i++ {
  1272  		if err != nil {
  1273  			b.Error(err)
  1274  			return
  1275  		}
  1276  		edge := &pb.DirectedEdge{
  1277  			ValueId: uint64(rand.Intn(b.N) + 1),
  1278  			Label:   "testing",
  1279  			Op:      pb.DirectedEdge_SET,
  1280  		}
  1281  		txn := &Txn{StartTs: 1}
  1282  		if err = l.addMutation(ctx, txn, edge); err != nil {
  1283  			b.Error(err)
  1284  		}
  1285  	}
  1286  }