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

GC & multitenancy #712

Merged
merged 28 commits into from
Dec 2, 2020
Merged

GC & multitenancy #712

merged 28 commits into from
Dec 2, 2020

Conversation

jsign
Copy link
Contributor

@jsign jsign commented Nov 19, 2020

A TL;DR of this PR, more details below:

  • Now it should be safe to run GC in the IPFS node at any point in time without any coordination with Powergate: e.g: with a cronjob or similar.
  • Now the FFS subsystem is fully-multitenant, so different FFS instances can store the same Cid. This means each of them, for the same cid, will have their own log output, StorageInfo, reference counting and correct real pin/unpinning in hot-storage, etc.
  • A new migration system was built to migrate existing non-multitenant data to new multi-tenant datastore schemas.
  • Same as the above point for reference counting regarding pinning cids in go-ipfs.
  • Some improvements/fixes in the wild.

Details about GC safety

The main problem with having safe IPFS GC at any point in time is all the staging data that might not be actually have ran its corresponding job.

The solution to this is to allow HotStorage have two types of pins:

  • Staging pins.
  • Real pins.

Now every time you pow data stage, it gets pinned in the underlying go-ipfs node. Internally, Powergate keeps track of which Cids are pinned in which way.

For example, say that FFS instance IID1 stages some data with cid Cid1. From that moment Cid1 is staged in the IPFS node. Then we have two cases:

  1. The user pushes a config for Cid1.
  2. For some reason the user abandons that staged data and never pushes a config.

In case 1, when the Job ends up running we have two cases:
1.a - The config that was pushed had HotStorage enabled. In this case, Cid1 is now switched to be a "real pin" instead of a "staging pin".
2.a - The config that was pushed had HotStorage disabled. In this case, Cid1 gets unpinned from the go-ipfs node.

In summary for case 1, after the Job runs the staged Cid1 gets promoted to a "real pin" or gets unpinned. Working this way means that IPFS GC can run any point in time after the data was staged and it's always safe to do so, i.e: no needed data that a queued or executing Job need will be deleted by IFPS.

In case 2, we have a situation of pinned data that would never execute a Job thus, a priori, never gets unpinned without extra logic. To handle this case, Powergate now has a "Staging GC" cron that runs every X minutes (configurable via flags) to manage these cases.

How this GC works? It basically analyzes all staged Cids that:

  • Were staged at least 1hr ago.
  • That Cid isn't part of a Queued or Executing job.

Those Cids look OK to be unpinned and let be GCed. Saying it differently, if we have some data which is "Stage pinned" for a "long" time, and we don't have any scheduled (queued) Job or executing one, then we can assume these staged data is abandoned. It's important this check that the Cid isn't part of a Queued job, since if we have a long queue of pending Jobs there's the chance that staged data is staged for more than 1hr.

There're knobs via flags/env to configure:

  • --ffsgcinterval: Frequency in which the Powergate GC runs to unpin old/abandoned staged data. (15min by default)
  • --ffsgcstagegraceperiod: How old staged data should be to be considered potentially unpinnable (1hr by default)

I also included two extra admin CLI commands for GC related things:

  • pow admin data gcstaged: This is for doing a manual trigger of a Powergate GC unpinning run. (What gets automatically run every 15min). Might be useful if the user wants to disable automatic unpinning, and just want to run it manually (or via API) for some reason.
  • pow admin data pinnedCids: This will dump all pinned Cids from Hot-Storage. Each Cid will say which FFS instances is pinning the data, and which kind of pin those are. e.g: we could see that Cid1 is pinned by FFS1 with a Staged Pin, and by FFS2 with a real pin. Just to have some visibility of why a Cid is pinned in IPFS, since if you see the ipfs pin ls output you only see that Cid1 is pinned but you might not understand why it's the case.

Exampleof pinnedCids output:

{
  "cids":  [
    {
      "cid":  "QmeBWFEUxvb25v9HrjoXe8c39i3f47Ge71wySGM6RowuwA",
      "users":  [
        {
          "userId":  "7a3c326d-5ccd-4375-bf1b-aca176e8b8ba",
          "staged":  true,
          "createdAt":  "1606242965"
        }
      ]
    }
  ]
}

Finally, as expected, if we have a Cid pinned by multiple FFS instances... only when all FFS instances unpin the Cid, it gets really unpinned from the go-ipfs node. Saying it differently, now HotStorage does reference counting to really know when a Cid can be unpinned from the IPFS node.


Details about multitenancy

Now we support different FFS instances storing the same Cid. This involved changes in multiple internal components of the scheduler:

  • Trackstore: The component that keeps track of which Cids have repair or renew enabled capabilities. Since now more than one FFS instance can store the same Cid, then we might have to run repairing or renewals for multiple FFSs for the same Cid.
  • StorageInfo store: Since multiple FFSs instances will save hot and cold information about the current state of storage, this can't be only keyed by Cid but (Cid,FFS instance).
  • JobLogger: JobLogger is the component that has the human friend log of a Job. Since now we have multiple FFSs instances pushing to Filecoin the same Cid, then we might have a different stream of logs for the same Cid. This fixes some weird behavior that some might see of having a second instance push a config for an existing Cid from another instance, and magically seeing Job logs for that Cid (which are from the other instance).

Migrations library

A new migration package was created that keeps track of which version the underlying datastore is. It also registers different Migration functions that transition version X to X+1. These Migrations are run in datastore transaction, so all the logic executed in the migration is atomic so it can fail safely without leaving "half-baked" data transformations.

Whenever Powergate runs, the first thing it does after initializing the underlying Datastore is ensuring the datastore version is equal to the latest version. If that isn't the case, it will run all the transformations to move the current version to the latest version.

The current version of the datastore is assumed to be in /migration/version.
We have to handle two special cases if Powergate recognizes that /migration/version key doesn't exist:

  • We're running a Powergate that has data on a version before this migration setup exists. (e.g: all existing Powergates up to now). In this case, the datastore is assumed to be in version 0.
  • We're running a completely clean Powergate for the first time.

In both cases, the /migration/version key doesn't exist. To distinguish both, the library checks if the datastore has at least 1 key. If there's at least 1 key in the datastore but /migration/version doesn't exist, then we're in the first case. If the datastore is completely empty, we're in the last case.

The distinction is necessary since the first case should run the necessary migrations to move from version 0, to the latest version that the newest migration migrates to. If we're in the second case (Powergate run for the firs time), we avoid any migration logic and set /migration/key value directly to the latest version.

As mentioned above, all existing Powergates are considered to be in version 0 now. In this PR there's a single migration function that has 4 sub-migrations:

  1. JobLogger migration: This migration reads existing job logs for a Cid, and migrates them to the new keyspace format, that is from: /ffs/joblogger/<cid>/<timestamp> to /ffs/joblogger/<ffsid>/<cid>/<timestamp>. Since we can already have multiple FFS instances storing the same Cid, the migration automatically duplicates entries for all FFS instances that might be having the same Cid... so we don't leave any FFS instance "empty" on logs that it might already existed from its POV. (Hope makes sense, but I can extend if isn't clear).
  2. StorageInfo migration: Same as above. The StorageInfo entries are migrated to a new key namespace, and every existing StorageInfo entry that is referenced in many FFS instances is copied once per instance, so we don't leave FFS instances orphaned on shared Cids StorageInfo.
  3. TrackStore migration: Same as above. We migrate data to acknowledge that multiple FFS instances might be setting repair and renew features in their storage configs, and all should be tracked for repair/renew crons.
  4. Pinstore filling: The migration detects all FFS instances that have HotStorage enabled, and fills the Pinstore with that information... so to recreate the correct pin reference counting in HotStorage.

Most of the above logic is a bit confusing since migrations that involve transforming a non-multitenant to multitenant setup is a bit hairy. These transformations not only copy the data to a new key but also have to copy the data multiple times once for each FFS instance that makes sense.

All this is covering the full set of cases that might appear. Most probably 90% of the Powergate instances weren't pushing the same Cid in different FFS instances... but this is the correct way to do the migrations.

@jsign jsign added the patch label Nov 19, 2020
migration/migration.go Outdated Show resolved Hide resolved
@jsign jsign added the enhancement New feature or request label Nov 20, 2020
@jsign jsign self-assigned this Nov 20, 2020
api/client/admin/hs.go Show resolved Hide resolved
api/server/admin/hs.go Show resolved Hide resolved
api/server/server.go Show resolved Hide resolved
api/server/server.go Outdated Show resolved Hide resolved
api/server/server.go Show resolved Hide resolved
c2: {ffs.APIID("ID3")},
}
txn, _ := ds.NewTransaction(false)
err := migrateJobLogger(txn, cidOwners)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We run this sub-migration on the datastore.

require.NoError(t, err)
require.NoError(t, txn.Commit())

post(t, ds, "testdata/v1_JobLogger.post")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We assert that the end result of the datastore state is the same as described in v1_JobLogger.post.

This style of doing test on migrations is quite easy since most of it is creating the pre and post state files.

"github.com/textileio/powergate/tests"
)

func TestEmptyDatastore(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here some tests of general Migrator library.
In this test we check the case of a new pristine Powergate. In this case, only the version will be set to the latest known version since doesn't make sense to run any migration.

require.Equal(t, 1, v)
}

func TestNonEmptyDatastore(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test the case of a Powergate already with data, but running the migration for the first time.
(e.g: all hosted or Hub powergate).

require.Equal(t, 1, v)
}

func TestNoop(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test the case of the migration running when the version is already the latest.. so most cases in general when Powergate is restarted or no new migrations exist.

@jsign jsign requested a review from asutula November 23, 2020 22:30
@jsign jsign marked this pull request as ready for review November 23, 2020 22:30
Comment on lines +64 to +66
if currentVersion > targetVersion {
return fmt.Errorf("migrations are forward only, current version %d, target version %d", currentVersion, targetVersion)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, this Migrator does forward only migrations. So check here for a situation in which the user might want to go back to an older tag of Powergate which isn't compatible with a newer datastore.

We can extend this lib to do forward and backward migrations. Now I did only forward since doesn't make sense for these big migrations of the PR to be rollbacked since that's impossible to do correctly.

We could define Migrations as rollback-able or not, and potentially allow backward migrations depending if the migration has a backward logic or not. That would be easy to do. Mentioning it just to consider for the future.

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Copy link
Member

@sanderpick sanderpick left a comment

Choose a reason for hiding this comment

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

Very nice! Lots of work. I read the description and comments to get an idea of the changes.

@jsign jsign force-pushed the jsign/sfgc4 branch 7 times, most recently from 54ad084 to b28ac75 Compare November 26, 2020 20:58
Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
@@ -4,7 +4,7 @@ RUN mkdir /app
WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download
RUN go mod download -x
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since downloading deps can take some time, I prefer seeing detailed output about what's being donwloaded.

Comment on lines 192 to 194
if err := runMigrations(conf); err != nil {
return nil, fmt.Errorf("running migrations: %s", err)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Before spinning internal components, we run migrations logic.

l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger"))
l := joblogger.New(txndstr.Wrap(ds, "ffs/joblogger_v2"))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

More about the need of suffixing migrated key namespaces soon.

@@ -537,15 +537,19 @@ func (s *Server) Close() {
}
}

func createDatastore(conf Config) (datastore.TxnDatastore, error) {
func createDatastore(conf Config, longTimeout bool) (datastore.TxnDatastore, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We enable a new flag longTimeout which returns a datastore that has long timeouts for operations and transactions.
Basically, the datastore that Powergate uses for operating has false value. For migrations, we create use a true value to allow for bigger timeouts since we do long-running operations.

repoPath, err := ioutil.TempDir("/tmp/powergate", ".powergate-*")
require.NoError(t, err)

repoPath := t.TempDir()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In Go 1.15, we can use (*testing.T).TempDir() which automatically cleans the folder when the test finishes, so no need to leave folders in tmp, or return "cls" funcs, and also deletes the folder even if the test panics.
We can use this in lots of places, just changed here.

Copy link
Member

Choose a reason for hiding this comment

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

Nice feature!


return owners, nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All below v0 functions are helpers for the migration stuff, which resolves some important questions for migrations:

  • Which iids exists.
  • Which iids own a Cid
  • Get the storage config of a Cid for a iid.

These methods should be agnostic of internal components, since if that is the case we could handcuff improving internal components in the future since migrations rely on them.

require.Equal(t, 0, v)
}

func TestRealDataBadger(t *testing.T) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I exported the go-datastore of one of our internal Powergate stacks locally in a Badger datastore.
And then just tested e2e with that real datastore that the migration runs correctly.

Comment on lines +164 to +165
func TestRealDataRemoteMongo(t *testing.T) {
t.SkipNow()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test case was mostly to test the migration directly in copied datastores of many live hosted powergates.
Disabled the test since doesn't make sense for CI.

Comment on lines +194 to +238
func pre(t *testing.T, ds datastore.TxnDatastore, path string) {
t.Helper()
f, err := os.Open(path)
require.NoError(t, err)
defer func() { require.NoError(t, f.Close()) }()

s := bufio.NewScanner(f)
for s.Scan() {
parts := strings.SplitN(s.Text(), ",", 2)
err = ds.Put(datastore.NewKey(parts[0]), []byte(parts[1]))
require.NoError(t, err)
}
}

func post(t *testing.T, ds datastore.TxnDatastore, path string) {
t.Helper()

f, err := os.Open(path)
require.NoError(t, err)
defer func() { require.NoError(t, f.Close()) }()

current := map[string][]byte{}
q := query.Query{}
res, err := ds.Query(q)
require.NoError(t, err)
defer func() { require.NoError(t, res.Close()) }()
for r := range res.Next() {
require.NoError(t, r.Error)
current[r.Key] = r.Value
}

expected := map[string][]byte{}
s := bufio.NewScanner(f)
for s.Scan() {
parts := strings.SplitN(s.Text(), ",", 2)
expected[parts[0]] = []byte(parts[1])
}

require.Equal(t, len(expected), len(current))
for k1, v1 := range current {
v2, ok := expected[k1]
require.True(t, ok)
require.Equal(t, v2, v1)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pre is a function that reads a csv files with key,values as a initial state of a datastore for tests.
post is a function that asserts if a datastore has the same state as a csv file with key,values.

@@ -0,0 +1,3 @@
/ffs/joblogger_v2/ID1/QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE/1602952162298722885,{"Cid":{"/":"QmPewMLNZEgnLxaenjo9Q5qwQwW3zHZ7Ac973UmeJ6VWHE"},"RetrievalID":"","Timestamp":1602952162298722885,"Jid":"ad6da2a0-5465-4275-a330-2537062765c8","Msg":"Deal 763168 with miner f022142 is active on-chain"}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here the pre and post files for each test case.
A new datastore is populated with .pre file key-values, the migration is run, and then it's asserted if the datastore is exactly in the .post key-values state.

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
@@ -34,8 +34,7 @@ type Store struct {
ds datastore.Datastore
watchers []watcher

queued []ffs.StorageJob
executingCids map[cid.Cid]ffs.JobID
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I deleted executingCids since now that we're multitenant I could simply use the executingJobs cache.
So one less cache to maintain.

Comment on lines +407 to +410
// We can already clean resumed started deals.
if err := s.sjs.RemoveStartedDeals(curr.APIID, curr.Cid); err != nil {
return ffs.ColdInfo{}, allErrors, fmt.Errorf("removing resumed started deals storage: %s", err)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doing the /ffs/scheduler/sjstore/starteddeals migration with real data I realized that in some border cases we leaving some already handled started deals.

In general the resumed deals would been removed by the already existing RemoveStartedDeals that existed below. But if after resuming deals, we consider that we need to create new deals to ensure the replication factor and we have some early return for some reason, the resumed deals won't be removed.

// For each cid owner, we create the same registry
// in the new key version.
for _, iid := range owners {
newKey := datastore.NewKey("/ffs/joblogger_v2/").ChildString(iid.String()).ChildString(cidStr).ChildString(timestampStr)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here the detail about _v2 suffixes.
What's happening in many migrations is that we try doing something like:

  • Original key: /hello/world/<cid>
  • New key: /hello/world/<iid>/<cid>

For doing the migration, we scan all original keys with Query{Prefix:"/hello/world"}.

Depending on the underlying way that the go-datastore implementation works, that can produce problems; and that was the case, since the new keys we're .Puting are also a result of the query itself.

That's to say, we start getting /hello/world/<cid> keys, but at the same time we're iterating that query we're inserting others /hello/world/<iid>/<cid> which will appear later in the query iteration and is not something we want (new keys satisfy the prefix from the query). We only want to iterate the original keys.

Not a big deal and is solved with the _v2 suffixing to avoid the iteration to consider the new keys.

In the Badger implementation of go-datastore this doesn't happen, since Badger has snapshot capabilities on the query execution and you won't see new keys that appear after the query was started. But in Mongo that isn't the case. It's just different ways that queries work in different databases.

Copy link
Member

Choose a reason for hiding this comment

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

Tricky

Copy link
Member

@asutula asutula left a comment

Choose a reason for hiding this comment

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

Awesome work. This all makes good sense to me. Left a couple questions, one potential issue.

api/client/admin/hs.go Show resolved Hide resolved
repoPath, err := ioutil.TempDir("/tmp/powergate", ".powergate-*")
require.NoError(t, err)

repoPath := t.TempDir()
Copy link
Member

Choose a reason for hiding this comment

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

Nice feature!

if err := m.Ensure(); err != nil {
return fmt.Errorf("running migrations: %s", err)
}
log.Infof("Migrations ensured")
Copy link
Member

Choose a reason for hiding this comment

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

Beautiful, nice and simple (from here anyway).

ffs/coreipfs/internal/pinstore/pinstore.go Outdated Show resolved Hide resolved
Comment on lines +27 to 36
type TrackedStorageConfig struct {
IID ffs.APIID
StorageConfig ffs.StorageConfig
}

// New retruns a new Store.
func New(ds datastore.Datastore) (*Store, error) {
s := &Store{
ds: ds,
repairables: map[cid.Cid]struct{}{},
renewables: map[cid.Cid]struct{}{},
}
if err := s.loadCaches(); err != nil {
return nil, fmt.Errorf("loading renewable/repairable caches: %s", err)
}
return s, nil
// TrackedCid contains tracked storage configs for a Cid.
type TrackedCid struct {
Cid cid.Cid
Tracked []TrackedStorageConfig
}
Copy link
Member

Choose a reason for hiding this comment

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

I guess I'm not familiar with the implementation of repair/renew, but just curious why storing a list per cid is better than using a instanceId/cid key with a StorageConfig value, avoiding that complexity you mentioned.

@@ -163,6 +175,50 @@ func (s *Scheduler) Cancel(jid ffs.JobID) error {
return nil
}

// GCStaged runs a unpinned garbage collection of stage-pins.
func (s *Scheduler) GCStaged(ctx context.Context) ([]cid.Cid, error) {
return s.gcStaged(ctx, 0)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe I'm missing something here, but would expect 0 to be s.gc.StageGracePeriod

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, this is on purpose. This API is for the manual GC call that I feel should clean all staged stuff (grace period 0).
I'd imagine that the user would like the manual option to be more direct clean.

Copy link
Member

Choose a reason for hiding this comment

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

👍

// For each cid owner, we create the same registry
// in the new key version.
for _, iid := range owners {
newKey := datastore.NewKey("/ffs/joblogger_v2/").ChildString(iid.String()).ChildString(cidStr).ChildString(timestampStr)
Copy link
Member

Choose a reason for hiding this comment

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

Tricky

@asutula
Copy link
Member

asutula commented Nov 30, 2020

Oh, meant to ask about Client.StageFolder... That thing uses the IPFS HTTP client directly to the IPFS API we're proxying. So that would bypass all the pin counting logic. Problem?

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
@jsign
Copy link
Contributor Author

jsign commented Nov 30, 2020

Oh, meant to ask about Client.StageFolder... That thing uses the IPFS HTTP client directly to the IPFS API we're proxying. So that would bypass all the pin counting logic. Problem?

Yeah, any external API calls to go-ipfs are out of the path of tracking. What we can do is create some other API to stage-pin a Cid. So after it does ipfs add externally, the Powergate client calls that new API to stage-pin the resulting Cid.
That would be quite clean and easy. Also might server to stage-pin things from the IPFS network. Thoughts?

@asutula
Copy link
Member

asutula commented Nov 30, 2020

Yea that sounds like a good idea.

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
options.Unixfs.Pin(false),
options.Unixfs.Pin(true),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So for staging folders we also pin now.

Comment on lines +107 to +111
_, err = d.client.StageCid(ctx, &userPb.StageCidRequest{Cid: pth.Cid().String()})
if err != nil {
return "", fmt.Errorf("stage pinning cid: %s", err)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We call a new API to stage Cids instead of streams of data.

Copy link
Member

Choose a reason for hiding this comment

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

Awesome

@jsign jsign merged commit 458e9c0 into master Dec 2, 2020
@jsign jsign deleted the jsign/sfgc4 branch December 2, 2020 17:52
andrewxhill pushed a commit that referenced this pull request Dec 12, 2020
* rebase & squash

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* trackstore progress

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* more progress

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* extensive trackstore tests

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* fixes

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* revert ci change

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* lints

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* fix docs

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* start migrations

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* progress

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* migration progress

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* storageinfo migr

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* progress

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* work

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* migration tests and changes

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* pinstore migration tests

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* lints

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* punctuation

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* change

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* rename

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* rename again

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* forward only

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* lint

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* fix admin ctx

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* allow for non-transactional migrations & real migration test & fixes

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* resume deal fixes & migration

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* improve comment

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>

* cover the stage folder usecase

Signed-off-by: Ignacio Hagopian <jsign.uy@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request patch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants