Skip to content

Commit

Permalink
Improve LookupStateReference
Browse files Browse the repository at this point in the history
Improve `IStore.LookupStateReference()` method by limiting the number of results
  • Loading branch information
earlbread committed Oct 7, 2019
1 parent ebf4077 commit b862efb
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 30 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ To be released.
[[#462], [#560]]
- `Swarm<T>` class became to implement `IDisposable` again and should be
disposed to clean up its internal resources. [[#485]]
- `IStore.IterateStateReferences()` method became to receive
`highestIndex`, `lowestIndex`, and `limit` parameters. [[#447], [#545]]

### Added interfaces

### Behavioral changes

- Improved performance of `StoreExtension.LookupStateReference<T>()` method.
[[#447], [#545]]

### Bug fixes

- Fixed a bug where `Swarm<T>.AppendBlocksAsync()` re-requests blocks that
Expand All @@ -27,8 +32,10 @@ To be released.
`Operation on non-blocking socket would block`. [[#405], [#485]]

[#405]: https://github.com/planetarium/libplanet/issues/405
[#447]: https://github.com/planetarium/libplanet/issues/447
[#462]: https://github.com/planetarium/libplanet/issues/462
[#485]: https://github.com/planetarium/libplanet/pull/485
[#545]: https://github.com/planetarium/libplanet/pull/545
[#550]: https://github.com/planetarium/libplanet/issues/550
[#555]: https://github.com/planetarium/libplanet/issues/555
[#558]: https://github.com/planetarium/libplanet/pull/558
Expand Down
77 changes: 68 additions & 9 deletions Libplanet.Tests/Store/StoreTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,34 +338,39 @@ public void IterateIndexes()
[Fact]
public void IterateStateReferences()
{
Address address = this.Fx.Address1;
Address address = Fx.Address1;
var addresses = new[] { address }.ToImmutableHashSet();

Block<DumbAction> block1 = Fx.Block1;
Block<DumbAction> block2 = Fx.Block2;
Block<DumbAction> block3 = Fx.Block3;

Transaction<DumbAction> tx4 = Fx.MakeTransaction(
new DumbAction[] { new DumbAction(address, "foo") }
new[] { new DumbAction(address, "foo") }
);
Block<DumbAction> block4 = TestUtils.MineNext(Fx.Block3, new[] { tx4 });
Block<DumbAction> block4 = TestUtils.MineNext(block3, new[] { tx4 });

Transaction<DumbAction> tx5 = Fx.MakeTransaction(
new DumbAction[] { new DumbAction(address, "bar") }
new[] { new DumbAction(address, "bar") }
);
Block<DumbAction> block5 = TestUtils.MineNext(block4, new[] { tx5 });

Assert.Empty(this.Fx.Store.IterateStateReferences(this.Fx.StoreChainId, address));
Assert.Empty(Fx.Store.IterateStateReferences(Fx.StoreChainId, address));

Fx.Store.StoreStateReference(
Fx.StoreChainId,
tx4.UpdatedAddresses,
addresses,
block4.Hash,
block4.Index
);
Assert.Equal(
new[] { Tuple.Create(block4.Hash, block4.Index) },
this.Fx.Store.IterateStateReferences(this.Fx.StoreChainId, address)
Fx.Store.IterateStateReferences(Fx.StoreChainId, address)
);

Fx.Store.StoreStateReference(
Fx.StoreChainId,
tx5.UpdatedAddresses,
addresses,
block5.Hash,
block5.Index
);
Expand All @@ -375,8 +380,62 @@ public void IterateStateReferences()
Tuple.Create(block5.Hash, block5.Index),
Tuple.Create(block4.Hash, block4.Index),
},
this.Fx.Store.IterateStateReferences(this.Fx.StoreChainId, address)
Fx.Store.IterateStateReferences(Fx.StoreChainId, address)
);

Fx.Store.StoreStateReference(Fx.StoreChainId, addresses, block3.Hash, block3.Index);
Fx.Store.StoreStateReference(Fx.StoreChainId, addresses, block2.Hash, block2.Index);
Fx.Store.StoreStateReference(Fx.StoreChainId, addresses, block1.Hash, block1.Index);

Assert.Equal(
new[]
{
Tuple.Create(block5.Hash, block5.Index),
Tuple.Create(block4.Hash, block4.Index),
Tuple.Create(block3.Hash, block3.Index),
Tuple.Create(block2.Hash, block2.Index),
Tuple.Create(block1.Hash, block1.Index),
},
Fx.Store.IterateStateReferences(Fx.StoreChainId, address)
);

Assert.Equal(
new[]
{
Tuple.Create(block5.Hash, block5.Index),
Tuple.Create(block4.Hash, block4.Index),
},
Fx.Store.IterateStateReferences(Fx.StoreChainId, address, lowestIndex: block4.Index)
);

Assert.Equal(
new[]
{
Tuple.Create(block2.Hash, block2.Index),
Tuple.Create(block1.Hash, block1.Index),
},
Fx.Store.IterateStateReferences(
Fx.StoreChainId, address, highestIndex: block2.Index)
);

Assert.Equal(
new[]
{
Tuple.Create(block3.Hash, block3.Index),
Tuple.Create(block2.Hash, block2.Index),
},
Fx.Store.IterateStateReferences(
Fx.StoreChainId, address, highestIndex: block3.Index, limit: 2)
);

Assert.Throws<ArgumentException>(() =>
{
Fx.Store.IterateStateReferences(
Fx.StoreChainId,
address,
highestIndex: block2.Index,
lowestIndex: block3.Index);
});
}

[Fact]
Expand Down
9 changes: 7 additions & 2 deletions Libplanet.Tests/Store/StoreTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,15 @@ AddressStateMap states

public IEnumerable<Tuple<HashDigest<SHA256>, long>> IterateStateReferences(
Guid chainId,
Address address)
Address address,
long? highestIndex,
long? lowestIndex,
int? limit)
{
// FIXME: Log arguments properly
_logs.Add((nameof(IterateStateReferences), chainId, address));
return _store.IterateStateReferences(chainId, address);
return _store.IterateStateReferences(
chainId, address, highestIndex, lowestIndex, limit);
}

public void StoreStateReference(
Expand Down
5 changes: 4 additions & 1 deletion Libplanet/Store/BaseStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ AddressStateMap states
/// <inheritdoc />
public abstract IEnumerable<Tuple<HashDigest<SHA256>, long>> IterateStateReferences(
Guid chainId,
Address address);
Address address,
long? highestIndex,
long? lowestIndex,
int? limit);

public abstract void StoreStateReference(
Guid chainId,
Expand Down
12 changes: 9 additions & 3 deletions Libplanet/Store/IStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,20 @@ AddressStateMap states
/// </summary>
/// <param name="chainId">The chain ID.</param>
/// <param name="address">The <see cref="Address"/> to get state references.</param>
/// <param name="highestIndex">The highest index of state references to get.</param>
/// <param name="lowestIndex">The lowest index of state references to get.</param>
/// <param name="limit">The maximum number of state references to get.</param>
/// <returns><em>Ordered</em> pairs of a state reference and a corresponding
/// <see cref="Block{T}.Index"/>. The highest index (i.e., the closest to the tip) goes
/// first and the lowest index (i.e., the closest to the genesis) goes last.</returns>
/// <seealso
/// cref="StoreStateReference(Guid , IImmutableSet{Address}, HashDigest{SHA256}, long)"/>
IEnumerable<Tuple<HashDigest<SHA256>, long>> IterateStateReferences(
Guid chainId,
Address address);
Address address,
long? highestIndex = null,
long? lowestIndex = null,
int? limit = null);

/// <summary>
/// Stores a state reference, which is a <see cref="Block{T}.Hash"/>
Expand All @@ -220,7 +226,7 @@ IEnumerable<Tuple<HashDigest<SHA256>, long>> IterateStateReferences(
/// <param name="blockIndex">The <see cref="Block{T}.Index"/> which has the state
/// of the <see cref="Address"/>. This must refer to the same block
/// that <paramref name="blockHash"/> refers to.</param>
/// <seealso cref="IterateStateReferences(Guid, Address)"/>
/// <seealso cref="IterateStateReferences(Guid, Address, long?, long?, int?)"/>
void StoreStateReference(
Guid chainId,
IImmutableSet<Address> addresses,
Expand All @@ -243,7 +249,7 @@ void StoreStateReference(
/// <paramref name="branchPoint"/>.</typeparam>
/// <exception cref="ChainIdNotFoundException">Thrown when the given
/// <paramref name="sourceChainId"/> does not exist.</exception>
/// <seealso cref="IterateStateReferences(Guid, Address)"/>
/// <seealso cref="IterateStateReferences(Guid, Address, long?, long?, int?)"/>
/// <seealso
/// cref="StoreStateReference(Guid, IImmutableSet{Address}, HashDigest{SHA256}, long)"/>
void ForkStateReferences<T>(
Expand Down
23 changes: 20 additions & 3 deletions Libplanet/Store/LiteDBStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -426,16 +426,33 @@ public override void SetBlockStates(
/// <inheritdoc/>
public override IEnumerable<Tuple<HashDigest<SHA256>, long>> IterateStateReferences(
Guid chainId,
Address address)
Address address,
long? highestIndex,
long? lowestIndex,
int? limit)
{
highestIndex = highestIndex ?? long.MaxValue;
lowestIndex = lowestIndex ?? 0;

if (highestIndex < lowestIndex)
{
var message =
$"highestIndex({highestIndex}) must be greater than or equal to " +
$"lowestIndex({lowestIndex})";
throw new ArgumentException(
message,
nameof(highestIndex));
}

string collId = StateRefId(chainId);
LiteCollection<StateRefDoc> coll = _db.GetCollection<StateRefDoc>(collId);
string addressString = address.ToHex().ToLower();
IEnumerable<StateRefDoc> stateRefs = coll.Find(
Query.And(
Query.All("BlockIndex", Query.Descending),
Query.EQ("AddressString", addressString)
)
Query.EQ("AddressString", addressString),
Query.Between("BlockIndex", lowestIndex, highestIndex)
), limit: limit ?? int.MaxValue
);
return stateRefs
.Select(doc => new Tuple<HashDigest<SHA256>, long>(doc.BlockHash, doc.BlockIndex));
Expand Down
15 changes: 3 additions & 12 deletions Libplanet/Store/StoreExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static class StoreExtension
/// <typeparam name="T">An <see cref="IAction"/> class used with
/// <paramref name="lookupUntil"/>.</typeparam>
/// <seealso cref="IStore.StoreStateReference(Guid, IImmutableSet{Address}, HashDigest{SHA256}, long)"/>
/// <seealso cref="IStore.IterateStateReferences(Guid, Address)"/>
/// <seealso cref="IStore.IterateStateReferences(Guid, Address, long?, long?, int?)"/>
#pragma warning restore MEN002
public static Tuple<HashDigest<SHA256>, long> LookupStateReference<T>(
this IStore store,
Expand All @@ -40,17 +40,8 @@ public static Tuple<HashDigest<SHA256>, long> LookupStateReference<T>(
throw new ArgumentNullException(nameof(lookupUntil));
}

IEnumerable<Tuple<HashDigest<SHA256>, long>> stateRefs =
store.IterateStateReferences(chainId, address);
foreach (Tuple<HashDigest<SHA256>, long> pair in stateRefs)
{
if (pair.Item2 <= lookupUntil.Index)
{
return Tuple.Create(pair.Item1, pair.Item2);
}
}

return null;
return store.IterateStateReferences(chainId, address, lookupUntil.Index, limit: 1)
.FirstOrDefault();
}

/// <summary>
Expand Down

0 comments on commit b862efb

Please sign in to comment.