Skip to content

datastore grows in size; StorageMax not respected since 0.39.0 #11096

Closed

Description

@etam

Checklist

Installation method

dist.ipfs.tech or ipfs-update

Version

Kubo version: 0.39.0
Repo version: 18
System version: amd64/linux
Golang version: go1.25.4

Config

{
  "API": {
    "HTTPHeaders": {
      "Access-Control-Allow-Methods": [
        "PUT",
        "POST"
      ],
      "Access-Control-Allow-Origin": [
        "http://localhost:5001",
        "http://127.0.0.1:5001",
      ]
    }
  },
  "Addresses": {
    "API": [
      "/ip4/0.0.0.0/tcp/5001",
      "/ip6/::/tcp/5001"
    ],
    "Announce": [
      "/ip4/185.40.199.126/tcp/4001",
      "/ip4/185.40.199.126/udp/4001/webrtc-direct",
      "/ip4/185.40.199.126/udp/4001/quic-v1",
      "/ip4/185.40.199.126/udp/4001/quic-v1/webtransport",
      "/ip6/2a00:c90::56:2/tcp/4001",
      "/ip6/2a00:c90::56:2/udp/4001/webrtc-direct",
      "/ip6/2a00:c90::56:2/udp/4001/quic-v1",
      "/ip6/2a00:c90::56:2/udp/4001/quic-v1/webtransport"
    ],
    "AppendAnnounce": null,
    "Gateway": [
      "/ip4/0.0.0.0/tcp/8080",
      "/ip6/::/tcp/8080"
    ],
    "NoAnnounce": [
      "/ip4/10.0.0.0/ipcidr/8",
      "/ip4/100.64.0.0/ipcidr/10",
      "/ip4/169.254.0.0/ipcidr/16",
      "/ip4/172.16.0.0/ipcidr/12",
      "/ip4/192.0.0.0/ipcidr/24",
      "/ip4/192.0.2.0/ipcidr/24",
      "/ip4/192.168.0.0/ipcidr/16",
      "/ip4/198.18.0.0/ipcidr/15",
      "/ip4/198.51.100.0/ipcidr/24",
      "/ip4/203.0.113.0/ipcidr/24",
      "/ip4/240.0.0.0/ipcidr/4",
      "/ip6/100::/ipcidr/64",
      "/ip6/2001:2::/ipcidr/48",
      "/ip6/2001:db8::/ipcidr/32",
      "/ip6/fc00::/ipcidr/7",
      "/ip6/fe80::/ipcidr/10"
    ],
    "Swarm": [
      "/ip4/0.0.0.0/tcp/4001",
      "/ip4/0.0.0.0/udp/4001/quic-v1",
      "/ip4/0.0.0.0/udp/4001/quic-v1/webtransport",
      "/ip6/::/tcp/4001",
      "/ip6/::/udp/4001/quic-v1",
      "/ip6/::/udp/4001/quic-v1/webtransport"
    ]
  },
  "AutoConf": {},
  "AutoNAT": {},
  "Bootstrap": [
    "auto"
  ],
  "DNS": {
    "Resolvers": {
      ".": "auto"
    }
  },
  "Datastore": {
    "BloomFilterSize": 0,
    "GCPeriod": "1h",
    "HashOnRead": false,
    "Spec": {
      "mounts": [
        {
          "child": {
            "path": "blocks",
            "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2",
            "sync": true,
            "type": "flatfs"
          },
          "mountpoint": "/blocks",
          "prefix": "flatfs.datastore",
          "type": "measure"
        },
        {
          "child": {
            "compression": "none",
            "path": "datastore",
            "type": "levelds"
          },
          "mountpoint": "/",
          "prefix": "leveldb.datastore",
          "type": "measure"
        }
      ],
      "type": "mount"
    },
    "StorageGCWatermark": 90,
    "StorageMax": "5GB"
  },
  "Discovery": {
    "MDNS": {
      "Enabled": false
    }
  },
  "Experimental": {
    "FilestoreEnabled": false,
    "GraphsyncEnabled": false,
    "Libp2pStreamMounting": false,
    "P2pHttpProxy": false,
    "StrategicProviding": false,
    "UrlstoreEnabled": false
  },
  "Gateway": {
    "APICommands": [],
    "HTTPHeaders": {},
    "NoDNSLink": false,
    "NoFetch": false,
    "PathPrefixes": [],
    "PublicGateways": {
      "localhost": null
    },
    "RootRedirect": "",
    "Writable": false
  },
  "Identity": {
    "PeerID": "<redacted>",
    "PrivKey": "<redacted>"
  },
  "Internal": {},
  "Ipns": {
    "DelegatedPublishers": [
      "auto"
    ],
    "RecordLifetime": "",
    "RepublishPeriod": "",
    "ResolveCacheSize": 128
  },
  "Migration": {
    "DownloadSources": [],
    "Keep": ""
  },
  "Mounts": {
    "FuseAllowOther": false,
    "IPFS": "/ipfs",
    "IPNS": "/ipns"
  },
  "Peering": {
    "Peers": [
      {
        "Addrs": [
          "/ip4/146.59.1.158/tcp/4001",
          "/ip4/146.59.1.158/udp/4001/webrtc-direct",
          "/ip4/146.59.1.158/udp/4001/quic-v1",
          "/ip4/146.59.1.158/udp/4001/quic-v1/webtransport",
          "/ip6/2001:41d0:602:3d9e::1/tcp/4001",
          "/ip6/2001:41d0:602:3d9e::1/udp/4001/webrtc-direct",
          "/ip6/2001:41d0:602:3d9e::1/udp/4001/quic-v1",
          "/ip6/2001:41d0:602:3d9e::1/udp/4001/quic-v1/webtransport",
          "/ip4/10.35.17.9/tcp/4001",
          "/ip4/10.35.17.9/udp/4001/webrtc-direct",
          "/ip4/10.35.17.9/udp/4001/quic-v1",
          "/ip4/10.35.17.9/udp/4001/quic-v1/webtransport",
          "/ip6/fde8:87d3:9415:9832::9/tcp/4001",
          "/ip6/fde8:87d3:9415:9832::9/udp/4001/webrtc-direct",
          "/ip6/fde8:87d3:9415:9832::9/udp/4001/quic-v1",
          "/ip6/fde8:87d3:9415:9832::9/udp/4001/quic-v1/webtransport"
        ],
        "ID": "12D3KooWSMyfy3sqRyd6Q1VA85DSedLrkaoQKSx551BEZHjwkx1k"
      },
      {
        "Addrs": [
          "/ip4/185.236.108.204/tcp/4001",
          "/ip4/185.236.108.204/udp/4001/webrtc-direct",
          "/ip4/185.236.108.204/udp/4001/quic-v1",
          "/ip4/185.236.108.204/udp/4001/quic-v1/webtransport",
          "/ip4/10.35.18.2/tcp/4001",
          "/ip4/10.35.18.2/udp/4001/webrtc-direct",
          "/ip4/10.35.18.2/udp/4001/quic-v1",
          "/ip4/10.35.18.2/udp/4001/quic-v1/webtransport",
          "/ip6/fde8:87d3:9415:9833::2/tcp/4001",
          "/ip6/fde8:87d3:9415:9833::2/udp/4001/webrtc-direct",
          "/ip6/fde8:87d3:9415:9833::2/udp/4001/quic-v1",
          "/ip6/fde8:87d3:9415:9833::2/udp/4001/quic-v1/webtransport"
        ],
        "ID": "12D3KooWMB9trMK6nwymDYZiTh2niKncoZydSf5A9AkKyeDcdws9"
      }
    ]
  },
  "Pinning": {
    "RemoteServices": {}
  },
  "Plugins": {
    "Plugins": null
  },
  "Pubsub": {
    "DisableSigning": false,
    "Router": ""
  },
  "Routing": {
    "AcceleratedDHTClient": false,
    "DelegatedRouters": [
      "auto"
    ],
    "Routers": null
  },
  "Swarm": {
    "AddrFilters": [
      "/ip4/10.0.0.0/ipcidr/8",
      "/ip4/100.64.0.0/ipcidr/10",
      "/ip4/169.254.0.0/ipcidr/16",
      "/ip4/172.16.0.0/ipcidr/12",
      "/ip4/192.0.0.0/ipcidr/24",
      "/ip4/192.0.2.0/ipcidr/24",
      "/ip4/192.168.0.0/ipcidr/16",
      "/ip4/198.18.0.0/ipcidr/15",
      "/ip4/198.51.100.0/ipcidr/24",
      "/ip4/203.0.113.0/ipcidr/24",
      "/ip4/240.0.0.0/ipcidr/4",
      "/ip6/100::/ipcidr/64",
      "/ip6/2001:2::/ipcidr/48",
      "/ip6/2001:db8::/ipcidr/32",
      "/ip6/fc00::/ipcidr/7",
      "/ip6/fe80::/ipcidr/10"
    ],
    "ConnMgr": {},
    "DisableBandwidthMetrics": false,
    "DisableNatPortMap": true,
    "RelayClient": {},
    "RelayService": {},
    "ResourceMgr": {},
    "Transports": {
      "Multiplexers": {},
      "Network": {},
      "Security": {}
    }
  }
}

Description

After update to 0.39.0 the datastore started to gain weight quite quickly.
Image

Initially I had Datastore.StorageMax set to default 10G. I changed it to 5GB and restarted kubo. A restart is purging the datastore. It grew again to 8.4G, which is way beyond 5GB. I'm running "ipfs repo gc" daily from cron. Even when run manually, it changes nothing.

Activity

  1. added
    kind/bugA bug in existing code (including security flaws)
    need/triageNeeds initial labeling and prioritization
    on Dec 8, 2025
  2. hsanjuan commented on Dec 9, 2025

    @hsanjuan
    Contributor

    Triage:

  3. added
    need/author-inputNeeds input from the original author
    and removed
    need/triageNeeds initial labeling and prioritization
    on Dec 9, 2025
  4. etam commented on Dec 9, 2025

    @etam
    Author

    I set Provide.DHT.SweepEnabled: false. Let's wait for results...

  5. etam commented on Dec 15, 2025

    @etam
    Author

    Yep. The disk usage stays flat.

  6. github-actions commented on Dec 22, 2025

    @github-actions
    Contributor

    Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.

  7. etam commented on Dec 22, 2025

    @etam
    Author

    What information is needed?

  8. github-actions commented on Dec 29, 2025

    @github-actions
    Contributor

    Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.

  9. etam commented on Dec 29, 2025

    @etam
    Author

    What information is needed?

  10. 15 remaining items

  11. Rashkae2 commented on Jan 30, 2026

    @Rashkae2

    How large do you want me to wait for? My Datastore usually shrinks to less than 2GB when Kubo is Started, and now sitting at 3.3 after almost 30 hrs uptime. (I might not be able to let this computer run continuously this week.)

  12. Rashkae2 commented on Jan 30, 2026

    @Rashkae2

    @etam or @Rashkae2 could you please run the following commands and paste output:

    • Wait for large disk usage (observed bug)
    • ipfs provide stat --all
    • ipfs provide stat --lan --all
    • Shutdown kubo
    • ipfs diag datastore count /

    The ipfs diag datastore commands does not appear to be correct. I get:

    ipfs diag datastore count /
    Error: expected 0 argument(s), got 3

    USAGE
    ipfs diag - Generate diagnostic reports.

    ipfs diag

    SUBCOMMANDS
    ipfs diag cmds - List commands run on this IPFS node.
    ipfs diag profile - Collect a performance profile for debugging.
    ipfs diag sys - Print system diagnostic information.

    For more information about each command, use:
    'ipfs diag --help'

    (I also tried on an offline 0.39-rc1 node, and got the same results.)

  13. guillaumemichel commented on Jan 30, 2026

    @guillaumemichel
    Member

    My Datastore usually shrinks to less than 2GB when Kubo is Started, and now sitting at 3.3

    @Rashkae2 yes, this should be good enough!

    Oh right! ipfs diag datastore is a new command that will be shipped in v0.40.0.

    If you are able to reproduce this issue from master and run ipfs diag datastore commands, it would be awesome.

    Otherwise running ipfs provide stat --all and ipfs provide stat --lan --all before and after node restart should already provide some useful information.

  14. Rashkae2 commented on Jan 30, 2026

    @Rashkae2

    Before Restart:

    
    $ du -sh datastore  
    3.5G    datastore  
    
    $ ipfs provide stat --all
    Connectivity:
      Status: online (2026-01-28 22:21:19)
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 0 regions
    
    Schedule:
      CIDs scheduled:        148k (148,131)
      Regions scheduled:     142
      Avg prefix length:     7.2
      Next region prefix:    00010010
      Next region reprovide: 13:00:31
    
    Timings:
      Uptime:              38h39m13.5s (2026-01-28 22:21:12)
      Current time offset: 4h33m10.6s
      Cycle started:       2026-01-30 08:27:14
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     18.3
      Peers swept:            2,813
      Full keyspace coverage: false
      Reachable peers:        2,567 (91%)
      Avg region size:        32.8
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs, 0 regions
      Ongoing reprovides:              0 CIDs, 0 regions
      Total CIDs provided:             314k    (314,068)
      Total records provided:          5M      (5,712,943)
      Total provide errors:            0
      CIDs provided/min/worker:        4.1
      CIDs reprovided/min/worker:      1,357.7
      Region reprovide duration:       48.2s
      Avg CIDs/reprovide:              1,061.5
      Regions reprovided (last cycle): 135
    
    Workers:
      Active workers: 0 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        0         0
        Dedicated:     2         1
        Available:     15        14
        Queued:        0         0
      Max connections/worker: 20
    
      $ ipfs provide stat --lan  --all
    Connectivity:
      Status: offline (2026-01-29 00:21:12)
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 1 regions
    
    Schedule:
      CIDs scheduled:        148k (148,131)
      Regions scheduled:     1
      Avg prefix length:     N/A
      Next region prefix:    N/A
      Next region reprovide: 06:27:14
    
    Timings:
      Uptime:              38h39m52.8s (2026-01-28 22:21:11)
      Current time offset: 4h33m49.8s
      Cycle started:       2026-01-30 08:27:14
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     N/A
      Peers swept:            0
      Full keyspace coverage: false
      Reachable peers:        0
      Avg region size:        N/A
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs, 0 regions
      Ongoing reprovides:              0 CIDs, 0 regions
      Total CIDs provided:             0
      Total records provided:          0
      Total provide errors:            0
      CIDs provided/min/worker:        N/A
      CIDs reprovided/min/worker:      N/A
      Region reprovide duration:       N/A
      Avg CIDs/reprovide:              N/A
      Regions reprovided (last cycle): 0
    
    Workers:
      Active workers: 0 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        0         0
        Dedicated:     2         1
        Available:     15        14
        Queued:        0         0
      Max connections/worker: 20
    

    After Restart!!

     $ du -sh datastore
    1.9G    datastore
    
    $ ipfs provide stat --all
    Connectivity:
      Status: online (2026-01-30 13:01:50)
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 0 regions
    
    Schedule:
      CIDs scheduled:        148k (148,131)
      Regions scheduled:     128
      Avg prefix length:     7
      Next region prefix:    0001000
      Next region reprovide: 13:05:41
    
    Timings:
      Uptime:              55.4s (2026-01-30 13:01:42)
      Current time offset: 4h35m23.2s
      Cycle started:       2026-01-30 08:27:14
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     N/A
      Peers swept:            0
      Full keyspace coverage: false
      Reachable peers:        0
      Avg region size:        N/A
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs, 0 regions
      Ongoing reprovides:              0 CIDs, 0 regions
      Total CIDs provided:             0
      Total records provided:          0
      Total provide errors:            0
      CIDs provided/min/worker:        N/A
      CIDs reprovided/min/worker:      N/A
      Region reprovide duration:       N/A
      Avg CIDs/reprovide:              N/A
      Regions reprovided (last cycle): 0
    
    Workers:
      Active workers: 0 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        0         0
        Dedicated:     2         1
        Available:     15        14
        Queued:        0         0
      Max connections/worker: 20
    
      
      $ ipfs provide stat --lan  --all
    Connectivity:
      Status: disconnected
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 0 regions
    
    Schedule:
      CIDs scheduled:        148k (148,131)
      Regions scheduled:     1
      Avg prefix length:     N/A
      Next region prefix:    N/A
      Next region reprovide: 06:27:14
    
    Timings:
      Uptime:              1m12.6s (2026-01-30 13:01:42)
      Current time offset: 4h35m40.4s
      Cycle started:       2026-01-30 08:27:14
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     N/A
      Peers swept:            0
      Full keyspace coverage: false
      Reachable peers:        0
      Avg region size:        N/A
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs, 0 regions
      Ongoing reprovides:              0 CIDs, 0 regions
      Total CIDs provided:             0
      Total records provided:          0
      Total provide errors:            0
      CIDs provided/min/worker:        N/A
      CIDs reprovided/min/worker:      N/A
      Region reprovide duration:       N/A
      Avg CIDs/reprovide:              N/A
      Regions reprovided (last cycle): 0
    
    Workers:
      Active workers: 0 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        0         0
        Dedicated:     2         1
        Available:     15        14
        Queued:        0         0
      Max connections/worker: 20
    
  15. guillaumemichel commented on Feb 3, 2026

    @guillaumemichel
    Member

    Thanks for the update @Rashkae2 !

    It seems to show that the issue doesn't come from LAN DHT provider nor provide queue.

    So far, I have been unable to reproduce the issue on the latest master.

    It would be great if you can checkout the latest master, run make install, try to reproduce the problem and run ipfs diag datastore count commands to show the datastore state. Alternatively, you could try again after the v0.40.0 release (or rc).

  16. guillaumemichel commented on Feb 5, 2026

    @guillaumemichel
    Member

    I have been trying to reproduce the issue. I have a much lower number of advertised CIDs (7k vs 148k)

    ➜  ~ ipfs --version --all
    Kubo version: 0.40.0-dev-22ca729eb
    Repo version: 18
    System version: amd64/linux
    Golang version: go1.25.6 X:nodwarf5
    

    I can confirm that the datastore filesize seems to increase over time, and then shrink (probably leveldb compaction).

    Here is the script I ran to monitor the datastore size when kubo was running

    while true; do 
        echo "$(date '+%Y-%m-%d %H:%M:%S'), $(du -sb ~/.ipfs/datastore/ | cut -f1), $(du -sh ~/.ipfs/datastore/ | cut -f1)" | tee -a datastore_monitor.log
        sleep 60
    done

    datastore_monitor.log

    I noticed that the size of the datastore shrank when I shut down kubo. Hence the observed datastore key counts look normal:

    ➜  kubo git:(master) ipfs provide stat --all
    Connectivity:
      Status: online (2026-02-03 10:27:08)
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 0 regions
    
    Schedule:
      CIDs scheduled:        7k (7,387)
      Regions scheduled:     139
      Avg prefix length:     7.1
      Next region prefix:    1101110
      Next region reprovide: 13:59:34
    
    Timings:
      Uptime:              51h22m33.7s (2026-02-03 10:27:02)
      Current time offset: 7h34m5.1s
      Cycle started:       2026-02-05 06:15:30
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     18.4
      Peers swept:            2,793
      Full keyspace coverage: true
      Reachable peers:        2,606 (93%)
      Avg region size:        32.0
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs,  0 regions
      Ongoing reprovides:              46 CIDs, 1 regions
      Total CIDs provided:             28k      (28,807)
      Total records provided:          532k     (532,079)
      Total provide errors:            0
      CIDs provided/min/worker:        N/A
      CIDs reprovided/min/worker:      94.3
      Region reprovide duration:       34.7s
      Avg CIDs/reprovide:              53.1
      Regions reprovided (last cycle): 135
    
    Workers:
      Active workers: 1 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        1         0
        Dedicated:     2         1
        Available:     14        14
        Queued:        0         0
      Max connections/worker: 20
    ➜  kubo git:(master) ipfs provide stat --all --lan
    Connectivity:
      Status: online (2026-02-03 10:27:04)
    
    Queues:
      Provide queue:   0 CIDs, 0 regions
      Reprovide queue: 0 regions
    
    Schedule:
      CIDs scheduled:        7k (7,387)
      Regions scheduled:     9
      Avg prefix length:     4.8
      Next region prefix:    0
      Next region reprovide: 17:15:30
    
    Timings:
      Uptime:              51h22m37.2s (2026-02-03 10:27:02)
      Current time offset: 7h34m8.6s
      Cycle started:       2026-02-05 06:15:30
      Reprovide interval:  22h0m0s
    
    Network:
      Avg record holders:     17.0
      Peers swept:            289
      Full keyspace coverage: true
      Reachable peers:        257 (88%)
      Avg region size:        37.6
      Replication factor:     20
    
    Operations:
      Ongoing provides:                0 CIDs, 0 regions
      Ongoing reprovides:              0 CIDs, 0 regions
      Total CIDs provided:             48k     (48,499)
      Total records provided:          885k    (885,947)
      Total provide errors:            0
      CIDs provided/min/worker:        N/A
      CIDs reprovided/min/worker:      476.7
      Region reprovide duration:       5m9.8s
      Avg CIDs/reprovide:              820.7
      Regions reprovided (last cycle): 3
    
    Workers:
      Active workers: 0 / 16 (max)
      Free workers:   13
        Workers stats: Periodic  Burst
        Active:        0         0
        Dedicated:     2         1
        Available:     15        14
        Queued:        0         0
      Max connections/worker: 20
    
    ➜  ~ ipfs diag datastore count /
    31650
    ➜  ~ ipfs diag datastore count /provider
    7595
    ➜  ~ ipfs diag datastore count /provider/keystore
    7389
    ➜  ~ ipfs diag datastore count /provider/wan     
    190
    ➜  ~ ipfs diag datastore count /provider/lan
    16
    ➜  ~ ipfs diag datastore count /provider/lan/history
    14
    ➜  ~ ipfs diag datastore count /provider/wan/history
    188
    ➜  ~ ipfs diag datastore count /provider/wan/pqueue 
    0
    ➜  ~ ipfs diag datastore count /provider/lan/pqueue
    0
    

    It seems that leveldb compaction is for something in the datastore size variation, but it may not be the only reason to reach such a large datastore state.

  17. lidel commented on Feb 9, 2026

    @lidel
    Contributor

    Thank you @guillaumemichel, this felt like useful path of inquiry, I did some digging into this last week. Here's what I found (sorry for chaotic notes, did not had time to clean up):

    Reproduction

    Built kubo from current master (c6702eaf8), created a fresh LevelDB repo with 50k small unpinned blocks via ipfs block put, and set Provide.DHT.Interval to 2m so I could watch multiple provide cycles without waiting 22 hours.

    Did the same with a Pebble repo (flatfs for blocks, pebbleds for metadata) to compare.

    The double-buffer keystore swap

    The main source of write churn is the ResettableKeystore in go-libp2p-kad-dht. It keeps two copies of the CID keystore under /provider/keystore/0 and /provider/keystore/1, and on every syncKeystore() call (once at startup, then every Provide.DHT.Interval), it:

    1. Empties the alternate buffer (deletes all keys)
    2. Walks the datastore or pinned DAGs and writes all CIDs into the alternate buffer
    3. Flips the active marker
    4. Empties what was the primary buffer

    So for N CIDs, each cycle does roughly 2N deletes + N writes in LevelDB. With 50k CIDs that's ~150k operations per cycle. Each delete becomes a tombstone in the SSTable files that sits there until background compaction gets around to it.

    Code: kubo/core/node/provider.go:514-565 calls ResetCids() in a loop, which triggers the swap in go-libp2p-kad-dht/provider/keystore/resettable_keystore.go:294-336.

    LevelDB numbers

    Measured datastore/ directory size at each stage:

    After init + 50k block put:             1.4 MB
    Daemon start (provider init):           6.8 MB
    After ~8 min of provide sweep:         13.4 MB  (monotonic growth)
    After first ResetCids keystore sync:   17.9 MB  (sudden jump from double-buffer swap)
    After 40 min with 2m cycles:          46.0 MB
    After repo gc + keystore down to 1 CID:
      - brief dip to 34.8 MB (LevelDB did compact a bit)
      - back up to 38.2 MB after next ResetCids cycle
    

    LevelDB does compact, but it only reclaimed about 1 MB during a 5-minute window, while each 2m cycle dumps another round of tombstones. The net result is growth that outpaces compaction.

    Pebble numbers (same test, flatfs + pebbleds)

    After init + 50k block put:             2.9 KB  (buffered in memtable)
    Daemon start:                          24.9 MB
    After 47 min with 2m cycles:           28.4 MB  (relatively stable)
    After repo gc + keystore to 1 CID:    22.3 MB  (compacted 6 MB)
    After next ResetCids cycle:            29.5 MB
    Stabilized:                            oscillates 22-30 MB
    

    Pebble reclaimed 6 MB (21%) vs LevelDB's 1 MB (2.8%) in the same observation window. Its tombstone-aware compaction keeps growth bounded. LevelDB's growth outpaces its compaction.

    Other findings

    • ipfs provide clear only clears the in-memory queue. No datastore writes, no tombstones, no effect on disk.
      • we may nuke the datastore (both /0 and /1) in addition to memory?
    • Both datastores also accumulate DHT server records from other nodes under /providers/. After 47 min with the 2m interval the Pebble test had 581k such records. Separate growth vector, but adds up on long-running nodes.
    • @guillaumemichel your observation that "the datastore shrank when I shut down kubo" is consistent with what I saw. LevelDB does some compaction during Close(), but not enough to offset what accumulated it seems?

    What could help

    Quick and easy:

    As for actual fixes, one thought is to introduce concept of compaction somehow, perhaps:

    • Upstream Compact() methods -- neither go-ds-leveldb nor go-ds-pebble expose compaction. Adding Compact(ctx context.Context) error to both (wrapping DB.CompactRange / db.Compact) is a prerequisite for the rest. Perhaps we could define a Compactor interface in go-datastore? Something to discuss.
    • Then, Compact after keystore sync -- the sync is where most tombstones come from. Triggering compaction right after the swap+empty sequence would prevent accumulation between cycles.
    • ipfs repo compact command -- offline manual trigger, like ipfs diag datastore count but calls Compact(). Lets operators reclaim space without waiting for a restart.
    • We probably want to avoid Compact on shutdown -- call Compact() before Close() in FSRepo.Close(). Adds shutdown latency, may break various orchestrations that force-kill if process does not shut down fast.

    Second, probably unlikely as it mitigates rather than fixes leveldb problem:

    • Rethink the double-buffer -- the ResettableKeystore design generates 2N tombstones per cycle. Reworking this somehow to an in-place diff approach (only delete CIDs that were actually removed, only add new ones) would cut write amplification significantly. Bigger change in go-libp2p-kad-dht, probably not feasible / not worth it given switching to pebble fixes problem and does not require big refactor.

    Third, change default Datastore of ipfs init

    • flatfs + pebble? we could replace leveldb with pebble in default config (keep blocks in flatfs), this way users benefit from better compaction
    • keep leveldb but tweak -- any knobs we can adjust / expose? Unlikely. iiuc the fundamental issue is that LevelDB's compaction heuristics don't prioritize tombstone
      removal the way Pebble does, so touching any existing defaults in LevelDB may harm/change existing performance profile (could do more harm than good for existing users.)

    Unsure if there is an easy win here beyond documenting the current leveldb behavior.
    We could switch from flatfs for blocks and leveldb for everything else → flatfs + pebbleds, but don't want to float the boat if we dont have to.

    Thoughts?

  18. removed their assignment
    on Feb 9, 2026
  19. guillaumemichel commented on Feb 10, 2026

    @guillaumemichel
    Member
    • Rethink the double-buffer -- the ResettableKeystore design generates 2N tombstones per cycle. Reworking this somehow to an in-place diff approach (only delete CIDs that were actually removed, only add new ones) would cut write amplification significantly. Bigger change in go-libp2p-kad-dht, probably not feasible / not worth it given switching to pebble fixes problem and does not require big refactor.

    This isn't an option in the current state of Kubo. If we ever switch to reference counting CIDs to advertise, then it becomes easy to implement.

  20. guillaumemichel commented on Feb 13, 2026

    @guillaumemichel
    Member

    See potential fix in #11198 and libp2p/go-libp2p-kad-dht#1233

  21. Rashkae2 commented on Feb 15, 2026

    @Rashkae2

    I won't have a long running node sample for a few more days at least, but 40-rc1 seems completely different from 0.39. In 18 hours uptime, datasore actually shrunk (from 2.0GB to 1.8GB) instead of suddenly growing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium: Good to have, but can wait until someone steps upneed/maintainers-inputNeeds input from the current maintainer(s)topic/docsDocumentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      ⌂ 换网址