Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cache ipns entries to speed things up a little #1887

Merged
merged 1 commit into from
Nov 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions core/commands/ipns.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Resolve the value of another name:
},
Options: []cmds.Option{
cmds.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name"),
cmds.BoolOption("nocache", "n", "Do not used cached entries"),
},
Run: func(req cmds.Request, res cmds.Response) {

Expand All @@ -62,13 +63,27 @@ Resolve the value of another name:
}
}

router := n.Routing
if local, _, _ := req.Option("local").Bool(); local {
router = offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
nocache, _, _ := req.Option("nocache").Bool()
local, _, _ := req.Option("local").Bool()

// default to nodes namesys resolver
var resolver namesys.Resolver = n.Namesys

if local && nocache {
res.SetError(errors.New("cannot specify both local and nocache"), cmds.ErrNormal)
return
}

var name string
if local {
offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
resolver = namesys.NewRoutingResolver(offroute, 0)
}

if nocache {
resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0)
}

var name string
if len(req.Arguments()) == 0 {
if n.Identity == "" {
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
Expand All @@ -86,7 +101,10 @@ Resolve the value of another name:
depth = namesys.DefaultDepthLimit
}

resolver := namesys.NewRoutingResolver(router)
if !strings.HasPrefix(name, "/ipns/") {
name = "/ipns/" + name
}

output, err := resolver.ResolveN(req.Context(), name, depth)
if err != nil {
res.SetError(err, cmds.ErrNormal)
Expand Down
14 changes: 13 additions & 1 deletion core/commands/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Publish an <ipfs-path> to another public key (not implemented):
Options: []cmds.Option{
cmds.BoolOption("resolve", "resolve given path before publishing (default=true)"),
cmds.StringOption("lifetime", "t", "time duration that the record will be valid for (default: 24hrs)"),
cmds.StringOption("ttl", "time duration this record should be cached for (caution: experimental)"),
},
Run: func(req cmds.Request, res cmds.Response) {
log.Debug("Begin Publish")
Expand Down Expand Up @@ -96,7 +97,18 @@ Publish an <ipfs-path> to another public key (not implemented):
popts.pubValidTime = d
}

output, err := publish(req.Context(), n, n.PrivateKey, path.Path(pstr), popts)
ctx := req.Context()
if ttl, found, _ := req.Option("ttl").String(); found {
d, err := time.ParseDuration(ttl)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

ctx = context.WithValue(ctx, "ipns-publish-ttl", d)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 we should enhance the context much more often.

This would allow us to get a trace of where it failed in timeouts instead of a blank "deadline exceeded".

}

output, err := publish(ctx, n, n.PrivateKey, path.Path(pstr), popts)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
Expand Down
31 changes: 29 additions & 2 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,13 @@ func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost
bitswapNetwork := bsnet.NewFromIpfsHost(n.PeerHost, n.Routing)
n.Exchange = bitswap.New(ctx, n.Identity, bitswapNetwork, n.Blockstore, alwaysSendToPeer)

size, err := n.getCacheSize()
if err != nil {
return err
}

// setup name system
n.Namesys = namesys.NewNameSystem(n.Routing, n.Repo.Datastore())
n.Namesys = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), size)

// setup ipns republishing
err = n.setupIpnsRepublisher()
Expand All @@ -238,6 +243,23 @@ func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost
return nil
}

// getCacheSize returns cache life and cache size
func (n *IpfsNode) getCacheSize() (int, error) {
cfg, err := n.Repo.Config()
if err != nil {
return 0, err
}

cs := cfg.Ipns.ResolveCacheSize
if cs == 0 {
cs = 128
}
if cs < 0 {
return 0, fmt.Errorf("cannot specify negative resolve cache size")
}
return cs, nil
}

func (n *IpfsNode) setupIpnsRepublisher() error {
cfg, err := n.Repo.Config()
if err != nil {
Expand Down Expand Up @@ -456,7 +478,12 @@ func (n *IpfsNode) SetupOfflineRouting() error {

n.Routing = offroute.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)

n.Namesys = namesys.NewNameSystem(n.Routing, n.Repo.Datastore())
size, err := n.getCacheSize()
if err != nil {
return err
}

n.Namesys = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), size)

return nil
}
Expand Down
2 changes: 1 addition & 1 deletion fuse/ipns/ipns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.M
}

node.Routing = offroute.NewOfflineRouter(node.Repo.Datastore(), node.PrivateKey)
node.Namesys = namesys.NewNameSystem(node.Routing, node.Repo.Datastore())
node.Namesys = namesys.NewNameSystem(node.Routing, node.Repo.Datastore(), 0)

ipnsfs, err := nsfs.NewFilesystem(context.Background(), node.DAG, node.Namesys, node.Pinning, node.PrivateKey)
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions namesys/namesys.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,21 @@ type mpns struct {
}

// NewNameSystem will construct the IPFS naming system based on Routing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe update the comment with sensible defaults?

func NewNameSystem(r routing.IpfsRouting, ds ds.Datastore) NameSystem {
func NewNameSystem(r routing.IpfsRouting, ds ds.Datastore, cachesize int) NameSystem {
return &mpns{
resolvers: map[string]resolver{
"dns": newDNSResolver(),
"proquint": new(ProquintResolver),
"dht": newRoutingResolver(r),
"dht": NewRoutingResolver(r, cachesize),
},
publishers: map[string]Publisher{
"/ipns/": NewRoutingPublisher(r, ds),
},
}
}

const DefaultResolverCacheTTL = time.Minute

// Resolve implements Resolver.
func (ns *mpns) Resolve(ctx context.Context, name string) (path.Path, error) {
return ns.ResolveN(ctx, name, DefaultDepthLimit)
Expand Down
8 changes: 8 additions & 0 deletions namesys/pb/namesys.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions namesys/pb/namesys.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ message IpnsEntry {
optional bytes validity = 4;

optional uint64 sequence = 5;

optional uint64 ttl = 6;
}
18 changes: 18 additions & 0 deletions namesys/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,31 @@ func (p *ipnsPublisher) getPreviousSeqNo(ctx context.Context, ipnskey key.Key) (
return e.GetSequence(), nil
}

// setting the TTL on published records is an experimental feature.
// as such, i'm using the context to wire it through to avoid changing too
// much code along the way.
func checkCtxTTL(ctx context.Context) (time.Duration, bool) {
v := ctx.Value("ipns-publish-ttl")
if v == nil {
return 0, false
}

d, ok := v.(time.Duration)
return d, ok
}

func PutRecordToRouting(ctx context.Context, k ci.PrivKey, value path.Path, seqnum uint64, eol time.Time, r routing.IpfsRouting, id peer.ID) error {
namekey, ipnskey := IpnsKeysForID(id)
entry, err := CreateRoutingEntryData(k, value, seqnum, eol)
if err != nil {
return err
}

ttl, ok := checkCtxTTL(ctx)
if ok {
entry.Ttl = proto.Uint64(uint64(ttl.Nanoseconds()))
}

err = PublishEntry(ctx, r, ipnskey, entry)
if err != nil {
return err
Expand Down
4 changes: 4 additions & 0 deletions namesys/republisher/repub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
)

func TestRepublish(t *testing.T) {
// set cache life to zero for testing low-period repubs

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand All @@ -34,6 +36,8 @@ func TestRepublish(t *testing.T) {
t.Fatal(err)
}

nd.Namesys = namesys.NewNameSystem(nd.Routing, nd.Repo.Datastore(), 0)

nodes = append(nodes, nd)
}

Expand Down
6 changes: 3 additions & 3 deletions namesys/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestRoutingResolve(t *testing.T) {
d := mockrouting.NewServer().Client(testutil.RandIdentityOrFatal(t))
dstore := ds.NewMapDatastore()

resolver := NewRoutingResolver(d)
resolver := NewRoutingResolver(d, 0)
publisher := NewRoutingPublisher(d, dstore)

privk, pubk, err := testutil.RandTestKeyPair(512)
Expand Down Expand Up @@ -53,7 +53,7 @@ func TestPrexistingExpiredRecord(t *testing.T) {
dstore := ds.NewMapDatastore()
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)

resolver := NewRoutingResolver(d)
resolver := NewRoutingResolver(d, 0)
publisher := NewRoutingPublisher(d, dstore)

privk, pubk, err := testutil.RandTestKeyPair(512)
Expand Down Expand Up @@ -90,7 +90,7 @@ func TestPrexistingRecord(t *testing.T) {
dstore := ds.NewMapDatastore()
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)

resolver := NewRoutingResolver(d)
resolver := NewRoutingResolver(d, 0)
publisher := NewRoutingPublisher(d, dstore)

privk, pubk, err := testutil.RandTestKeyPair(512)
Expand Down
Loading