Full Code of etcd-io/bbolt for AI

main 73ea46600de4 cached
155 files
734.3 KB
222.9k tokens
1168 symbols
1 requests
Download .txt
Showing preview only (777K chars total). Download the full file or copy to clipboard to get everything.
Repository: etcd-io/bbolt
Branch: main
Commit: 73ea46600de4
Files: 155
Total size: 734.3 KB

Directory structure:
gitextract_ich4mfot/

├── .gitattributes
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── benchmark-pr.yaml
│       ├── benchmark-releases.yaml
│       ├── benchmark-template.yaml
│       ├── cross-arch-template.yaml
│       ├── cross-arch-test.yaml
│       ├── failpoint_test.yaml
│       ├── gh-workflow-approve.yaml
│       ├── robustness_nightly.yaml
│       ├── robustness_template.yaml
│       ├── robustness_test.yaml
│       ├── stale.yaml
│       ├── tests-template.yml
│       ├── tests_amd64.yaml
│       ├── tests_arm64.yaml
│       └── tests_windows.yml
├── .gitignore
├── .go-version
├── .golangci.yaml
├── CHANGELOG/
│   ├── CHANGELOG-1.3.md
│   ├── CHANGELOG-1.4.md
│   └── CHANGELOG-1.5.md
├── LICENSE
├── Makefile
├── OWNERS
├── README.md
├── allocate_test.go
├── bolt_aix.go
├── bolt_android.go
├── bolt_linux.go
├── bolt_openbsd.go
├── bolt_solaris.go
├── bolt_unix.go
├── bolt_windows.go
├── boltsync_unix.go
├── bucket.go
├── bucket_test.go
├── cmd/
│   └── bbolt/
│       ├── OWNERS
│       ├── README.md
│       ├── command/
│       │   ├── command_bench.go
│       │   ├── command_bench_test.go
│       │   ├── command_buckets.go
│       │   ├── command_buckets_test.go
│       │   ├── command_check.go
│       │   ├── command_check_test.go
│       │   ├── command_compact.go
│       │   ├── command_compact_test.go
│       │   ├── command_dump.go
│       │   ├── command_dump_test.go
│       │   ├── command_get.go
│       │   ├── command_get_test.go
│       │   ├── command_info.go
│       │   ├── command_info_test.go
│       │   ├── command_inspect.go
│       │   ├── command_inspect_test.go
│       │   ├── command_keys.go
│       │   ├── command_keys_test.go
│       │   ├── command_page.go
│       │   ├── command_page_item.go
│       │   ├── command_page_item_test.go
│       │   ├── command_page_test.go
│       │   ├── command_pages.go
│       │   ├── command_pages_test.go
│       │   ├── command_root.go
│       │   ├── command_stats.go
│       │   ├── command_stats_test.go
│       │   ├── command_surgery.go
│       │   ├── command_surgery_freelist.go
│       │   ├── command_surgery_freelist_test.go
│       │   ├── command_surgery_meta.go
│       │   ├── command_surgery_meta_test.go
│       │   ├── command_surgery_test.go
│       │   ├── command_version.go
│       │   ├── errors.go
│       │   ├── utils.go
│       │   └── utils_test.go
│       └── main.go
├── code-of-conduct.md
├── compact.go
├── concurrent_test.go
├── cursor.go
├── cursor_test.go
├── db.go
├── db_test.go
├── db_whitebox_test.go
├── doc.go
├── errors/
│   └── errors.go
├── errors.go
├── go.mod
├── go.sum
├── internal/
│   ├── btesting/
│   │   └── btesting.go
│   ├── common/
│   │   ├── bolt_386.go
│   │   ├── bolt_amd64.go
│   │   ├── bolt_arm.go
│   │   ├── bolt_arm64.go
│   │   ├── bolt_loong64.go
│   │   ├── bolt_mips64x.go
│   │   ├── bolt_mipsx.go
│   │   ├── bolt_ppc.go
│   │   ├── bolt_ppc64.go
│   │   ├── bolt_ppc64le.go
│   │   ├── bolt_riscv64.go
│   │   ├── bolt_s390x.go
│   │   ├── bucket.go
│   │   ├── inode.go
│   │   ├── meta.go
│   │   ├── page.go
│   │   ├── page_test.go
│   │   ├── types.go
│   │   ├── unsafe.go
│   │   ├── utils.go
│   │   └── verify.go
│   ├── freelist/
│   │   ├── array.go
│   │   ├── array_test.go
│   │   ├── freelist.go
│   │   ├── freelist_test.go
│   │   ├── hashmap.go
│   │   ├── hashmap_test.go
│   │   └── shared.go
│   ├── guts_cli/
│   │   └── guts_cli.go
│   ├── surgeon/
│   │   ├── surgeon.go
│   │   ├── surgeon_test.go
│   │   ├── xray.go
│   │   └── xray_test.go
│   └── tests/
│       └── tx_check_test.go
├── logger.go
├── manydbs_test.go
├── mlock_unix.go
├── mlock_windows.go
├── movebucket_test.go
├── node.go
├── node_test.go
├── quick_test.go
├── scripts/
│   ├── compare_benchmarks.sh
│   ├── fix.sh
│   └── release.sh
├── simulation_no_freelist_sync_test.go
├── simulation_test.go
├── tests/
│   ├── dmflakey/
│   │   ├── dmflakey.go
│   │   ├── dmflakey_test.go
│   │   ├── dmsetup.go
│   │   └── loopback.go
│   ├── failpoint/
│   │   └── db_failpoint_test.go
│   ├── robustness/
│   │   ├── main_test.go
│   │   └── powerfailure_test.go
│   └── utils/
│       └── helpers.go
├── tx.go
├── tx_check.go
├── tx_check_test.go
├── tx_stats_test.go
├── tx_test.go
├── unix_test.go
├── utils_test.go
└── version/
    └── version.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# ensure that line endings for Windows builds are properly formatted
# see https://github.com/golangci/golangci-lint-action?tab=readme-ov-file#how-to-use
# at "Multiple OS Example" section
*.go text eol=lf


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: weekly

  - package-ecosystem: gomod
    directory: /
    schedule:
      interval: weekly


================================================
FILE: .github/workflows/benchmark-pr.yaml
================================================
---
name: Benchmarks on PRs (AMD64)
permissions: read-all
on: [pull_request]
jobs:
  amd64:
    uses: ./.github/workflows/benchmark-template.yaml
    with:
      benchGitRef: ${{ github.event.pull_request.base.sha }}


================================================
FILE: .github/workflows/benchmark-releases.yaml
================================================
---
name: Nightly Benchmarks against last release (AMD64)
permissions: read-all
on:
  schedule:
    - cron: '10 5 * * *' # runs every day at 05:10 UTC
  # workflow_dispatch enables manual testing of this job by maintainers
  workflow_dispatch:
jobs:
  amd64:
    uses: ./.github/workflows/benchmark-template.yaml
    with:
      benchGitRef: release-1.3


================================================
FILE: .github/workflows/benchmark-template.yaml
================================================
---
name: Reusable Benchmark Template
on:
  workflow_call:
    inputs:
      # which git reference to benchmark against
      benchGitRef:
        required: true
        type: string
      maxAcceptableDifferencePercent:
        required: false
        type: number
        default: 5
      runs-on:
        required: false
        type: string
        default: "['ubuntu-latest']"
permissions: read-all

jobs:
  benchmark:
    runs-on: ${{ fromJson(inputs.runs-on) }}
    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      with:
        fetch-depth: 0
    - id: goversion
      run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
    - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
      with:
        go-version: ${{ steps.goversion.outputs.goversion }}
    - name: Run Benchmarks
      run: |
        BENCHSTAT_OUTPUT_FILE=result.txt make test-benchmark-compare REF=${{ inputs.benchGitRef }}
    - run: |
        echo "\`\`\`" >> "$GITHUB_STEP_SUMMARY"
        cat result.txt >> "$GITHUB_STEP_SUMMARY"
        echo "\`\`\`" >> "$GITHUB_STEP_SUMMARY"
        cat <<EOL >> "$GITHUB_STEP_SUMMARY"
        <hr />
        The table shows the median and 90% confidence interval (CI) summaries for each benchmark comparing the HEAD and the BASE, and an A/B comparison under "vs base". The last column shows the statistical p-value with ten runs (n=10).
        The last row has the Geometric Mean (geomean) for the given rows in the table.
        Refer to [benchstat's documentation](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat) for more help.
        EOL
    - name: Validate results under acceptable limit
      run: |
        export MAX_ACCEPTABLE_DIFFERENCE=${{ inputs.maxAcceptableDifferencePercent }}
        while IFS= read -r line; do
          # Get fourth value, which is the comparison with the base.
          value="$(echo "$line" | awk '{print $4}')"
          if [[ "$value" = +* ]] || [[ "$value" = -* ]]; then
            if (( $(echo "${value//[^0-9.]/}"'>'"$MAX_ACCEPTABLE_DIFFERENCE" | bc -l) )); then
              echo "::error::$value is above the maximum acceptable difference ($MAX_ACCEPTABLE_DIFFERENCE)"
              exit 1
            fi
          fi
        done < <(grep geomean result.txt)


================================================
FILE: .github/workflows/cross-arch-template.yaml
================================================
---
name: Reusable Cross-Platform Build Workflow
on:
  workflow_call:
    inputs:
      archs:
        required: true
        type: string
      os:
        required: true
        type: string
permissions: read-all

jobs:
  cross-build:
    strategy:
      matrix:
        arch: ${{ fromJSON(inputs.archs) }}
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
    - id: goversion
      run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
    - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
      with:
        go-version: ${{ steps.goversion.outputs.goversion }}
    - name: Build for ${{ inputs.os }}/${{ matrix.arch }}
      run: |
        GOOS=${{ inputs.os }} GOARCH=${{ matrix.arch }} go build ./...


================================================
FILE: .github/workflows/cross-arch-test.yaml
================================================
---
name: Cross-Platform Build Tests
permissions: read-all
on: [push, pull_request]

jobs:
  build-aix:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: aix
      archs: "['ppc64']"
  build-android:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: android
      archs: "['arm64']"
  build-linux:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: linux
      archs: "['386','amd64','arm','arm64','loong64','mips','mips64','mips64le','mipsle','ppc64','ppc64le','riscv64','s390x']"
  build-openbsd:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: openbsd
      archs: "['386','amd64','arm','arm64','ppc64','riscv64']"
  build-solaris:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: solaris
      archs: "['amd64']"
  build-windows:
    uses: ./.github/workflows/cross-arch-template.yaml
    with:
      os: windows
      archs: "['386','amd64','arm64']"


================================================
FILE: .github/workflows/failpoint_test.yaml
================================================
---
name: Failpoint test
on: [push, pull_request]
permissions: read-all
jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6
      - run: |
          make gofail-enable
          make test-failpoint


================================================
FILE: .github/workflows/gh-workflow-approve.yaml
================================================
---
name: Approve GitHub Workflows
permissions: read-all
on:
  pull_request_target:
    types:
      - labeled
      - synchronize
    branches:
      - main
      - release-1.3

jobs:
  approve:
    name: Approve ok-to-test
    if: contains(github.event.pull_request.labels.*.name, 'ok-to-test')
    runs-on: ubuntu-latest
    permissions:
      actions: write
    steps:
      - name: Update PR
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
        continue-on-error: true
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          debug: ${{ secrets.ACTIONS_RUNNER_DEBUG == 'true' }}
          script: |
            const result = await github.rest.actions.listWorkflowRunsForRepo({
              owner: context.repo.owner,
              repo: context.repo.repo,
              event: "pull_request",
              status: "action_required",
              head_sha: context.payload.pull_request.head.sha,
              per_page: 100
            });
            for (var run of result.data.workflow_runs) {
              await github.rest.actions.approveWorkflowRun({
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: run.id
              });
            }


================================================
FILE: .github/workflows/robustness_nightly.yaml
================================================
---
name: Robustness Nightly
permissions: read-all
on:
  schedule:
    - cron: '25 9 * * *' # runs every day at 09:25 UTC
  # workflow_dispatch enables manual testing of this job by maintainers
  workflow_dispatch:

jobs:
  amd64:
    # GHA has a maximum amount of 6h execution time, we try to get done within 3h
    uses: ./.github/workflows/robustness_template.yaml
    with:
      count: 100
      testTimeout: 200m
      runs-on: "['ubuntu-latest']"


================================================
FILE: .github/workflows/robustness_template.yaml
================================================
---
name: Reusable Robustness Workflow
on:
  workflow_call:
    inputs:
      count:
        required: true
        type: number
      testTimeout:
        required: false
        type: string
        default: '30m'
      runs-on:
        required: false
        type: string
        default: "['ubuntu-latest']"
permissions: read-all

jobs:
  test:
    # this is to prevent the job to run at forked projects
    if: github.repository == 'etcd-io/bbolt'
    timeout-minutes: 210
    runs-on: ${{ fromJson(inputs.runs-on) }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6
      - name: test-robustness
        run: |
          set -euo pipefail
          sudo apt-get install -y dmsetup xfsprogs

          ROBUSTNESS_TESTFLAGS="--count ${{ inputs.count }} --timeout ${{ inputs.testTimeout }} -failfast" make test-robustness

      - name: Host Status
        if: always()
        run: |
          set -x
          mount
          df
          losetup -l
      - name: Kernel Message
        if: failure()
        run: |
          sudo lsmod
          sudo dmesg -T -f kern


================================================
FILE: .github/workflows/robustness_test.yaml
================================================
name: Robustness Test
on: [push, pull_request]
permissions: read-all
jobs:
  amd64:
    uses: ./.github/workflows/robustness_template.yaml
    with:
      count: 10
      testTimeout: 30m
      runs-on: "['ubuntu-latest']"
  arm64:
    uses: ./.github/workflows/robustness_template.yaml
    with:
      count: 10
      testTimeout: 30m
      runs-on: "['ubuntu-24.04-arm']"


================================================
FILE: .github/workflows/stale.yaml
================================================
name: 'Close stale issues and PRs'
on:
  schedule:
    - cron: '0 0 * * *'  # every day at 00:00 UTC

permissions:
  issues: write
  pull-requests: write

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
        with:
          days-before-stale: 90
          days-before-close: 21
          stale-issue-label: stale
          stale-pr-label: stale


================================================
FILE: .github/workflows/tests-template.yml
================================================
---
name: Reusable unit test Workflow
on:
  workflow_call:
    inputs:
      runs-on:
        required: false
        type: string
        default: ubuntu-latest
      targets:
        required: false
        type: string
        default: "['linux-unit-test-1-cpu','linux-unit-test-2-cpu','linux-unit-test-4-cpu']"
permissions: read-all

jobs:
  test-linux:
    strategy:
      fail-fast: false
      matrix:
        target: ${{ fromJSON(inputs.targets) }}
    runs-on: ${{ inputs.runs-on }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - run: make fmt
      - env:
          TARGET: ${{ matrix.target }}
        run: |
          case "${TARGET}" in
            linux-unit-test-1-cpu)
              CPU=1 make test
              ;;
            linux-unit-test-2-cpu)
              CPU=2 make test
              ;;
            linux-unit-test-4-cpu)
              CPU=4 make test
              ;;
            linux-unit-test-4-cpu-race)
              CPU=4 ENABLE_RACE=true make test
              ;;
            *)
              echo "Failed to find target"
              exit 1
              ;;
          esac
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6


================================================
FILE: .github/workflows/tests_amd64.yaml
================================================
---
name: Tests AMD64
permissions: read-all
on: [push, pull_request]
jobs:
  test-linux-amd64:
    uses: ./.github/workflows/tests-template.yml
  test-linux-amd64-race:
    uses: ./.github/workflows/tests-template.yml
    with:
      runs-on: ubuntu-latest
      targets: "['linux-unit-test-4-cpu-race']"

  coverage:
    needs:
      - test-linux-amd64
      - test-linux-amd64-race
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6
      - run: make coverage


================================================
FILE: .github/workflows/tests_arm64.yaml
================================================
---
name: Tests ARM64
permissions: read-all
on: [push, pull_request]
jobs:
  test-linux-arm64:
    uses: ./.github/workflows/tests-template.yml
    with:
      runs-on: ubuntu-24.04-arm
  test-linux-arm64-race:
    uses: ./.github/workflows/tests-template.yml
    with:
      runs-on: ubuntu-24.04-arm
      targets: "['linux-unit-test-4-cpu-race']"

  coverage:
    needs:
      - test-linux-arm64
      - test-linux-arm64-race
    runs-on: ubuntu-24.04-arm
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6
      - run: make coverage


================================================
FILE: .github/workflows/tests_windows.yml
================================================
---
name: Tests
on: [push, pull_request]
permissions: read-all
jobs:
  test-windows:
    strategy:
      fail-fast: false
      matrix:
        target:
          - windows-amd64-unit-test-4-cpu
        # FIXME(fuweid):
        #
        # The windows will throws the following error when enable race.
        # We skip it until we have solution.
        #
        #   ThreadSanitizer failed to allocate 0x000200000000 (8589934592) bytes at 0x0400c0000000 (error code: 1455)
        #
        # - windows-amd64-unit-test-4-cpu-race
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - run: make fmt
      - env:
          TARGET: ${{ matrix.target }}
        run: |
          case "${TARGET}" in
            windows-amd64-unit-test-4-cpu)
              CPU=4 TIMEOUT=60m make test
              ;;
            *)
              echo "Failed to find target"
              exit 1
              ;;
          esac
        shell: bash
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6

  coverage:
    needs: ["test-windows"]
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
      - id: goversion
        run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
      - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
        with:
          go-version: ${{ steps.goversion.outputs.goversion }}
      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
        with:
          version: v2.1.6
      - run: make coverage
        env:
          TIMEOUT: 60m


================================================
FILE: .gitignore
================================================
*.prof
*.test
*.swp
/bin/
cover.out
cover-*.out
/.idea
*.iml
/bbolt
/cmd/bbolt/bbolt
.DS_Store



================================================
FILE: .go-version
================================================
1.24.13


================================================
FILE: .golangci.yaml
================================================
formatters:
  enable:
    - gci
    - gofmt
    - goimports
  settings: # please keep this alphabetized
    gci:
      sections:
        - standard
        - default
        - prefix(go.etcd.io)
    goimports:
      local-prefixes:
        - go.etcd.io # Put imports beginning with prefix after 3rd-party packages.
issues:
  max-same-issues: 0
linters:
  default: none
  enable: # please keep this alphabetized
    - errcheck
    - govet
    - ineffassign
    - staticcheck
    - unused
  exclusions:
    presets:
      - comments
      - common-false-positives
      - legacy
      - std-error-handling
  settings: # please keep this alphabetized
    staticcheck:
      checks:
        - all
        - -QF1003 # Convert if/else-if chain to tagged switch
        - -QF1010 # Convert slice of bytes to string when printing it
        - -ST1003 # Poorly chosen identifier
        - -ST1005 # Incorrectly formatted error string
        - -ST1012 # Poorly chosen name for error variable
version: "2"


================================================
FILE: CHANGELOG/CHANGELOG-1.3.md
================================================
Note that we start to track changes starting from v1.3.7.

<hr>

## v1.3.12(2025-08-19)

### BoltDB
- [Add protection on meta page when it's being written](https://github.com/etcd-io/bbolt/pull/1006)
- Fix [potential data corruption in `(*Tx)WriteTo` if underlying db file is overwritten](https://github.com/etcd-io/bbolt/pull/1059)

<hr>

## v1.3.11(2024-08-21)

### BoltDB
- Fix [the `freelist.allocs` isn't rollbacked when a tx is rollbacked](https://github.com/etcd-io/bbolt/pull/823).

### CMD
- Add [`-gobench-output` option for bench command to adapt to benchstat](https://github.com/etcd-io/bbolt/pull/802).

### Other
- [Bump go version to 1.22.x](https://github.com/etcd-io/bbolt/pull/822).
- This patch also added `dmflakey` package, which can be reused by other projects. See https://github.com/etcd-io/bbolt/pull/812.

<hr>

## v1.3.10(2024-05-06)

### BoltDB
- [Remove deprecated `UnsafeSlice` and use `unsafe.Slice`](https://github.com/etcd-io/bbolt/pull/717)
- [Stabilize the behaviour of Prev when the cursor already points to the first element](https://github.com/etcd-io/bbolt/pull/744)

### Other
- [Bump go version to 1.21.9](https://github.com/etcd-io/bbolt/pull/713)

<hr>

## v1.3.9(2024-02-24)

### BoltDB
- [Clone the key before operating data in bucket against the key](https://github.com/etcd-io/bbolt/pull/639)

### CMD
- [Fix `bbolt keys` and `bbolt get` to prevent them from panicking when no parameter provided](https://github.com/etcd-io/bbolt/pull/683)

<hr>

## v1.3.8(2023-10-26)

### BoltDB
- Fix [db.close() doesn't unlock the db file if db.munnmap() fails](https://github.com/etcd-io/bbolt/pull/439).
- [Avoid syscall.Syscall use on OpenBSD](https://github.com/etcd-io/bbolt/pull/406).
- Fix [rollback panicking after mlock failed or both meta pages corrupted](https://github.com/etcd-io/bbolt/pull/444).
- Fix [bbolt panicking due to 64bit unaligned on arm32](https://github.com/etcd-io/bbolt/pull/584).

### CMD
- [Update the usage of surgery command](https://github.com/etcd-io/bbolt/pull/411).

<hr>

## v1.3.7(2023-01-31)

### BoltDB
- Add [recursive checker to confirm database consistency](https://github.com/etcd-io/bbolt/pull/225).
- Add [support to get the page size from the second meta page if the first one is invalid](https://github.com/etcd-io/bbolt/pull/294).
- Add [support for loong64 arch](https://github.com/etcd-io/bbolt/pull/303).
- Add [internal iterator to Bucket that goes over buckets](https://github.com/etcd-io/bbolt/pull/356).
- Add [validation on page read and write](https://github.com/etcd-io/bbolt/pull/358).
- Add [PreLoadFreelist option to support loading free pages in readonly mode](https://github.com/etcd-io/bbolt/pull/381).
- Add [(*Tx) CheckWithOption to support generating human-readable diagnostic messages](https://github.com/etcd-io/bbolt/pull/395).
- Fix [Use `golang.org/x/sys/windows` for `FileLockEx`/`UnlockFileEx`](https://github.com/etcd-io/bbolt/pull/283).
- Fix [readonly file mapping on windows](https://github.com/etcd-io/bbolt/pull/307).
- Fix [the "Last" method might return no data due to not skipping the empty pages](https://github.com/etcd-io/bbolt/pull/341).
- Fix [panic on db.meta when rollback](https://github.com/etcd-io/bbolt/pull/362).

### CMD
- Add [support for get keys in sub buckets in `bbolt get` command](https://github.com/etcd-io/bbolt/pull/295).
- Add [support for `--format` flag for `bbolt keys` command](https://github.com/etcd-io/bbolt/pull/306).
- Add [safeguards to bbolt CLI commands](https://github.com/etcd-io/bbolt/pull/354).
- Add [`bbolt page` supports --all and --value-format=redacted formats](https://github.com/etcd-io/bbolt/pull/359).
- Add [`bbolt surgery` commands](https://github.com/etcd-io/bbolt/issues/370).
- Fix [open db file readonly mode for commands which shouldn't update the db file](https://github.com/etcd-io/bbolt/pull/365), see also [pull/292](https://github.com/etcd-io/bbolt/pull/292).

### Other
- [Build bbolt CLI tool, test and format the source code using golang 1.17.13](https://github.com/etcd-io/bbolt/pull/297).
- [Bump golang.org/x/sys to v0.4.0](https://github.com/etcd-io/bbolt/pull/397).

### Summary
Release v1.3.7 contains following critical fixes:
- fix to problem that `Last` method might return incorrect value ([#341](https://github.com/etcd-io/bbolt/pull/341))
- fix of potential panic when performing transaction's rollback ([#362](https://github.com/etcd-io/bbolt/pull/362))

Other changes focused on defense-in-depth ([#358](https://github.com/etcd-io/bbolt/pull/358), [#294](https://github.com/etcd-io/bbolt/pull/294), [#225](https://github.com/etcd-io/bbolt/pull/225), [#395](https://github.com/etcd-io/bbolt/pull/395))

`bbolt` command line tool was expanded to:
- allow fixing simple corruptions by `bbolt surgery` ([#370](https://github.com/etcd-io/bbolt/pull/370))
- be flexible about output formatting ([#306](https://github.com/etcd-io/bbolt/pull/306), [#359](https://github.com/etcd-io/bbolt/pull/359))
- allow accessing data in subbuckets ([#295](https://github.com/etcd-io/bbolt/pull/295))


================================================
FILE: CHANGELOG/CHANGELOG-1.4.md
================================================

<hr>

## v1.4.3(2025-08-19)

### BoltDB
- Fix [potential data corruption in `(*Tx)WriteTo` if underlying db file is overwritten](https://github.com/etcd-io/bbolt/pull/1058)

<hr>

## v1.4.2(2025-06-27)

### BoltDB
- [Fix the compilation issue on aix, android and solaris due to wrong use of `maxMapSize`](https://github.com/etcd-io/bbolt/pull/990)
- [Add protection on meta page when it's being written](https://github.com/etcd-io/bbolt/pull/1005)

<hr>

## v1.4.1(2025-06-10)

### BoltDB
- [Correct the incorrect usage of debug method](https://github.com/etcd-io/bbolt/pull/905)
- [Add clarification on the option `InitialMmapSize`](https://github.com/etcd-io/bbolt/pull/943)
- [Fix the crash when writing huge values](https://github.com/etcd-io/bbolt/pull/978)

<hr>

## v1.4.0(2025-02-05)
There isn't any production code change since v1.4.0-beta.0. Only some dependencies
are bumped, also updated some typos in comment and readme, and removed the legacy
build tag `// +build` in https://github.com/etcd-io/bbolt/pull/879.

<hr>

## v1.4.0-beta.0(2024-11-04)

### BoltDB
- Reorganized the directory structure of freelist source code
  - [Move array related freelist source code into a separate file](https://github.com/etcd-io/bbolt/pull/777)
  - [Move method `freePages` into freelist.go](https://github.com/etcd-io/bbolt/pull/783)
  - [Add an interface for freelist](https://github.com/etcd-io/bbolt/pull/775)
- [Rollback alloc map when a transaction is rollbacked](https://github.com/etcd-io/bbolt/pull/819)
- [No handling freelist as a special case when freeing a page](https://github.com/etcd-io/bbolt/pull/788)
- [Ensure hashmap init method clears the data structures](https://github.com/etcd-io/bbolt/pull/794)
- [Panicking when a write transaction tries to free a page allocated by itself](https://github.com/etcd-io/bbolt/pull/792)

### CMD
- [Add `-gobench-output` flag for `bbolt bench` command](https://github.com/etcd-io/bbolt/pull/765)

### Other
- [Bump go version to 1.23.x](https://github.com/etcd-io/bbolt/pull/821)

<hr>

## v1.4.0-alpha.1(2024-05-06)

### BoltDB
- [Enhance check functionality to support checking starting from a pageId](https://github.com/etcd-io/bbolt/pull/659)
- [Optimize the logger performance for frequent called methods](https://github.com/etcd-io/bbolt/pull/741)
- [Stabilize the behaviour of Prev when the cursor already points to the first element](https://github.com/etcd-io/bbolt/pull/734)

### CMD
- [Fix `bbolt keys` and `bbolt get` to prevent them from panicking when no parameter provided](https://github.com/etcd-io/bbolt/pull/682)
- [Fix surgery freelist command in info logs](https://github.com/etcd-io/bbolt/pull/700)
- [Remove txid references in surgery meta command's comment and description](https://github.com/etcd-io/bbolt/pull/703)
- [Add rnd read capabilities to bbolt bench](https://github.com/etcd-io/bbolt/pull/711)
- [Use `cobra.ExactArgs` to simplify the argument number check](https://github.com/etcd-io/bbolt/pull/728)
- [Migrate `bbolt check` command to cobra style](https://github.com/etcd-io/bbolt/pull/723)
- [Simplify the naming of cobra commands](https://github.com/etcd-io/bbolt/pull/732)
- [Aggregate adding completed ops for read test of the `bbolt bench` command](https://github.com/etcd-io/bbolt/pull/721)
- [Add `--from-page` flag to `bbolt check` command](https://github.com/etcd-io/bbolt/pull/737)

### Document
- [Add document for a known issue on the writing a value with a length of 0](https://github.com/etcd-io/bbolt/pull/730)

### Test
- [Enhance robustness test to cover XFS](https://github.com/etcd-io/bbolt/pull/707)

### Other
- [Bump go toolchain version to 1.22.2](https://github.com/etcd-io/bbolt/pull/712)

<hr>

## v1.4.0-alpha.0(2024-01-12)

### BoltDB
- [Improve the performance of hashmapGetFreePageIDs](https://github.com/etcd-io/bbolt/pull/419)
- [Improve CreateBucketIfNotExists to avoid double searching the same key](https://github.com/etcd-io/bbolt/pull/532)
- [Support Android platform](https://github.com/etcd-io/bbolt/pull/571)
- [Record the count of free page to improve the performance of hashmapFreeCount](https://github.com/etcd-io/bbolt/pull/585)
- [Add logger to bbolt](https://github.com/etcd-io/bbolt/issues/509)
- [Support moving bucket inside the same db](https://github.com/etcd-io/bbolt/pull/635)
- [Support inspecting database structure](https://github.com/etcd-io/bbolt/pull/674)

### CMD
- [Add `surgery clear-page-elements` command](https://github.com/etcd-io/bbolt/pull/417)
- [Add `surgery abandon-freelist` command](https://github.com/etcd-io/bbolt/pull/443)
- [Add `bbolt version` command](https://github.com/etcd-io/bbolt/pull/552)
- [Add `bbolt inspect` command](https://github.com/etcd-io/bbolt/pull/674)
- [Add `--no-sync` option to `bbolt compact` command](https://github.com/etcd-io/bbolt/pull/290)


================================================
FILE: CHANGELOG/CHANGELOG-1.5.md
================================================
<hr>

## v1.5.0(TBD)

### BoltDB
- [Add support for data file size limit](https://github.com/etcd-io/bbolt/pull/929)
- [Remove the unused txs list](https://github.com/etcd-io/bbolt/pull/973)
- [Add option `NoStatistics` to make the statistics optional](https://github.com/etcd-io/bbolt/pull/977)
- [Move panic handling from goroutine to the parent function](https://github.com/etcd-io/bbolt/pull/1153)
- [Recover from panics in tx.check](https://github.com/etcd-io/bbolt/pull/1164)

<hr>

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2013 Ben Johnson

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
BRANCH=`git rev-parse --abbrev-ref HEAD`
COMMIT=`git rev-parse --short HEAD`
GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)"
GOFILES = $(shell find . -name \*.go)

TESTFLAGS_RACE=-race=false
ifdef ENABLE_RACE
	TESTFLAGS_RACE=-race=true
endif

TESTFLAGS_CPU=
ifdef CPU
	TESTFLAGS_CPU=-cpu=$(CPU)
endif
TESTFLAGS = $(TESTFLAGS_RACE) $(TESTFLAGS_CPU) $(EXTRA_TESTFLAGS)

TESTFLAGS_TIMEOUT=30m
ifdef TIMEOUT
	TESTFLAGS_TIMEOUT=$(TIMEOUT)
endif

TESTFLAGS_ENABLE_STRICT_MODE=false
ifdef ENABLE_STRICT_MODE
	TESTFLAGS_ENABLE_STRICT_MODE=$(ENABLE_STRICT_MODE)
endif

.EXPORT_ALL_VARIABLES:
TEST_ENABLE_STRICT_MODE=${TESTFLAGS_ENABLE_STRICT_MODE}

.PHONY: fmt
fmt:
	@echo "Verifying gofmt, failures can be fixed with ./scripts/fix.sh"
	@!(gofmt -l -s -d ${GOFILES} | grep '[a-z]')

	@echo "Verifying goimports, failures can be fixed with ./scripts/fix.sh"
	@!(go tool golang.org/x/tools/cmd/goimports -l -d ${GOFILES} | grep '[a-z]')

.PHONY: lint
lint:
	golangci-lint run ./...

.PHONY: test
test:
	@echo "hashmap freelist test"
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=hashmap go test -v ${TESTFLAGS} -timeout ${TESTFLAGS_TIMEOUT}
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=hashmap go test -v ${TESTFLAGS} ./internal/...
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=hashmap go test -v ${TESTFLAGS} ./cmd/bbolt/...

	@echo "array freelist test"
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=array go test -v ${TESTFLAGS} -timeout ${TESTFLAGS_TIMEOUT}
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=array go test -v ${TESTFLAGS} ./internal/...
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=array go test -v ${TESTFLAGS} ./cmd/bbolt/...

.PHONY: coverage
coverage:
	@echo "hashmap freelist test"
	TEST_FREELIST_TYPE=hashmap go test -v -timeout ${TESTFLAGS_TIMEOUT} \
		-coverprofile cover-freelist-hashmap.out -covermode atomic

	@echo "array freelist test"
	TEST_FREELIST_TYPE=array go test -v -timeout ${TESTFLAGS_TIMEOUT} \
		-coverprofile cover-freelist-array.out -covermode atomic

BOLT_CMD=bbolt

build:
	go build -o bin/${BOLT_CMD} ./cmd/${BOLT_CMD}

.PHONY: clean
clean: # Clean binaries
	rm -f ./bin/${BOLT_CMD}

.PHONY: gofail-enable
gofail-enable:
	go tool go.etcd.io/gofail enable .

.PHONY: gofail-disable
gofail-disable:
	go tool go.etcd.io/gofail disable .

.PHONY: test-failpoint
test-failpoint:
	@echo "[failpoint] hashmap freelist test"
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=hashmap go test -v ${TESTFLAGS} -timeout 30m ./tests/failpoint

	@echo "[failpoint] array freelist test"
	BBOLT_VERIFY=all TEST_FREELIST_TYPE=array go test -v ${TESTFLAGS} -timeout 30m ./tests/failpoint

.PHONY: test-robustness # Running robustness tests requires root permission for now
# TODO: Remove sudo once we fully migrate to the prow infrastructure
test-robustness: gofail-enable build
	sudo env PATH=$$PATH go test -v ${TESTFLAGS} ./tests/dmflakey -test.root
	sudo env PATH=$(PWD)/bin:$$PATH go test -v ${TESTFLAGS} ${ROBUSTNESS_TESTFLAGS} ./tests/robustness -test.root

.PHONY: test-benchmark-compare
# Runs benchmark tests on the current git ref and the given REF, and compares
# the two.
test-benchmark-compare:
	@git fetch
	./scripts/compare_benchmarks.sh $(REF)


================================================
FILE: OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners

approvers:
  - ahrtr           # Benjamin Wang <benjamin.ahrtr@gmail.com> <benjamin.wang@broadcom.com>
  - serathius       # Marek Siarkowicz <siarkowicz@google.com> <marek.siarkowicz@gmail.com>
  - ptabor          # Piotr Tabor <piotr.tabor@gmail.com>
  - spzala          # Sahdev Zala <spzala@us.ibm.com>
reviewers:
  - elbehery        # Mustafa Elbehery <elbeherymustafa@gmail.com>
  - fuweid          # Wei Fu <fuweid89@gmail.com>
  - tjungblu        # Thomas Jungblut <tjungblu@redhat.com>


================================================
FILE: README.md
================================================
bbolt
=====

[![Go Report Card](https://goreportcard.com/badge/go.etcd.io/bbolt?style=flat-square)](https://goreportcard.com/report/go.etcd.io/bbolt)
[![Go Reference](https://pkg.go.dev/badge/go.etcd.io/bbolt.svg)](https://pkg.go.dev/go.etcd.io/bbolt)
[![Releases](https://img.shields.io/github/release/etcd-io/bbolt/all.svg?style=flat-square)](https://github.com/etcd-io/bbolt/releases)
[![LICENSE](https://img.shields.io/github/license/etcd-io/bbolt.svg?style=flat-square)](https://github.com/etcd-io/bbolt/blob/master/LICENSE)

bbolt is a fork of [Ben Johnson's][gh_ben] [Bolt][bolt] key/value
store. The purpose of this fork is to provide the Go community with an active
maintenance and development target for Bolt; the goal is improved reliability
and stability. bbolt includes bug fixes, performance enhancements, and features
not found in Bolt while preserving backwards compatibility with the Bolt API.

Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas]
[LMDB project][lmdb]. The goal of the project is to provide a simple,
fast, and reliable database for projects that don't require a full database
server such as Postgres or MySQL.

Since Bolt is meant to be used as such a low-level piece of functionality,
simplicity is key. The API will be small and only focus on getting values
and setting values. That's it.

[gh_ben]: https://github.com/benbjohnson
[bolt]: https://github.com/boltdb/bolt
[hyc_symas]: https://twitter.com/hyc_symas
[lmdb]: https://www.symas.com/symas-embedded-database-lmdb

## Project Status

Bolt is stable, the API is fixed, and the file format is fixed. Full unit
test coverage and randomized black box testing are used to ensure database
consistency and thread safety. Bolt is currently used in high-load production
environments serving databases as large as 1TB. Many companies such as
Shopify and Heroku use Bolt-backed services every day.

## Project versioning

bbolt uses [semantic versioning](http://semver.org).
API should not change between patch and minor releases.
New minor versions may add additional features to the API.

## Table of Contents

  - [Getting Started](#getting-started)
    - [Installing](#installing)
    - [Opening a database](#opening-a-database)
    - [Transactions](#transactions)
      - [Read-write transactions](#read-write-transactions)
      - [Read-only transactions](#read-only-transactions)
      - [Batch read-write transactions](#batch-read-write-transactions)
      - [Managing transactions manually](#managing-transactions-manually)
    - [Using buckets](#using-buckets)
    - [Using key/value pairs](#using-keyvalue-pairs)
    - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket)
    - [Iterating over keys](#iterating-over-keys)
      - [Prefix scans](#prefix-scans)
      - [Range scans](#range-scans)
      - [ForEach()](#foreach)
    - [Nested buckets](#nested-buckets)
    - [Database backups](#database-backups)
    - [Statistics](#statistics)
    - [Read-Only Mode](#read-only-mode)
    - [Mobile Use (iOS/Android)](#mobile-use-iosandroid)
  - [Resources](#resources)
  - [Comparison with other databases](#comparison-with-other-databases)
    - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases)
    - [LevelDB, RocksDB](#leveldb-rocksdb)
    - [LMDB](#lmdb)
  - [Caveats & Limitations](#caveats--limitations)
  - [Reading the Source](#reading-the-source)
  - [Known Issues](#known-issues)
  - [Other Projects Using Bolt](#other-projects-using-bolt)

## Getting Started

### Installing

To start using `bbolt`, install Go and run `go get`:
```sh
$ go get go.etcd.io/bbolt@latest
```

This will retrieve the library and update your `go.mod` and `go.sum` files.

To run the command line utility, execute:
```sh
$ go run go.etcd.io/bbolt/cmd/bbolt@latest
```

Run `go install` to install the `bbolt` command line utility into
your `$GOBIN` path, which defaults to `$GOPATH/bin` or `$HOME/go/bin` if the
`GOPATH` environment variable is not set.
```sh
$ go install go.etcd.io/bbolt/cmd/bbolt@latest
```

### Importing bbolt

To use bbolt as an embedded key-value store, import as:

```go
import bolt "go.etcd.io/bbolt"

db, err := bolt.Open(path, 0600, nil)
if err != nil {
  return err
}
defer db.Close()
```


### Opening a database

The top-level object in Bolt is a `DB`. It is represented as a single file on
your disk and represents a consistent snapshot of your data.

To open your database, simply use the `bolt.Open()` function:

```go
package main

import (
	"log"

	bolt "go.etcd.io/bbolt"
)

func main() {
	// Open the my.db data file in your current directory.
	// It will be created if it doesn't exist.
	db, err := bolt.Open("my.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	...
}
```

Please note that Bolt obtains a file lock on the data file so multiple processes
cannot open the same database at the same time. Opening an already open Bolt
database will cause it to hang until the other process closes it. To prevent
an indefinite wait you can pass a timeout option to the `Open()` function:

```go
db, err := bolt.Open("my.db", 0600, &bolt.Options{Timeout: 1 * time.Second})
```


### Transactions

Bolt allows only one read-write transaction at a time but allows as many
read-only transactions as you want at a time. Each transaction has a consistent
view of the data as it existed when the transaction started.

Individual transactions and all objects created from them (e.g. buckets, keys)
are not thread safe. To work with data in multiple goroutines you must start
a transaction for each one or use locking to ensure only one goroutine accesses
a transaction at a time. Creating transaction from the `DB` is thread safe.

Transactions should not depend on one another and generally shouldn't be opened
simultaneously in the same goroutine. This can cause a deadlock as the read-write
transaction needs to periodically re-map the data file but it cannot do so while
any read-only transaction is open. Even a nested read-only transaction can cause
a deadlock, as the child transaction can block the parent transaction from releasing
its resources.

#### Read-write transactions

To start a read-write transaction, you can use the `DB.Update()` function:

```go
err := db.Update(func(tx *bolt.Tx) error {
	...
	return nil
})
```

Inside the closure, you have a consistent view of the database. You commit the
transaction by returning `nil` at the end. You can also rollback the transaction
at any point by returning an error. All database operations are allowed inside
a read-write transaction.

Always check the return error as it will report any disk failures that can cause
your transaction to not complete. If you return an error within your closure
it will be passed through.


#### Read-only transactions

To start a read-only transaction, you can use the `DB.View()` function:

```go
err := db.View(func(tx *bolt.Tx) error {
	...
	return nil
})
```

You also get a consistent view of the database within this closure, however,
no mutating operations are allowed within a read-only transaction. You can only
retrieve buckets, retrieve values, and copy the database within a read-only
transaction.


#### Batch read-write transactions

Each `DB.Update()` waits for disk to commit the writes. This overhead
can be minimized by combining multiple updates with the `DB.Batch()`
function:

```go
err := db.Batch(func(tx *bolt.Tx) error {
	...
	return nil
})
```

Concurrent Batch calls are opportunistically combined into larger
transactions. Batch is only useful when there are multiple goroutines
calling it.

The trade-off is that `Batch` can call the given
function multiple times, if parts of the transaction fail. The
function must be idempotent and side effects must take effect only
after a successful return from `DB.Batch()`.

For example: don't display messages from inside the function, instead
set variables in the enclosing scope:

```go
var id uint64
err := db.Batch(func(tx *bolt.Tx) error {
	// Find last key in bucket, decode as bigendian uint64, increment
	// by one, encode back to []byte, and add new key.
	...
	id = newValue
	return nil
})
if err != nil {
	return ...
}
fmt.Println("Allocated ID %d", id)
```


#### Managing transactions manually

The `DB.View()` and `DB.Update()` functions are wrappers around the `DB.Begin()`
function. These helper functions will start the transaction, execute a function,
and then safely close your transaction if an error is returned. This is the
recommended way to use Bolt transactions.

However, sometimes you may want to manually start and end your transactions.
You can use the `DB.Begin()` function directly but **please** be sure to close
the transaction.

```go
// Start a writable transaction.
tx, err := db.Begin(true)
if err != nil {
    return err
}
defer tx.Rollback()

// Use the transaction...
_, err := tx.CreateBucket([]byte("MyBucket"))
if err != nil {
    return err
}

// Commit the transaction and check for error.
if err := tx.Commit(); err != nil {
    return err
}
```

The first argument to `DB.Begin()` is a boolean stating if the transaction
should be writable.


### Using buckets

Buckets are collections of key/value pairs within the database. All keys in a
bucket must be unique. You can create a bucket using the `Tx.CreateBucket()`
function:

```go
db.Update(func(tx *bolt.Tx) error {
	b, err := tx.CreateBucket([]byte("MyBucket"))
	if err != nil {
		return fmt.Errorf("create bucket: %s", err)
	}
	return nil
})
```

You can retrieve an existing bucket using the `Tx.Bucket()` function:
```go
db.Update(func(tx *bolt.Tx) error {
	b := tx.Bucket([]byte("MyBucket"))
	if b == nil {
		return errors.New("bucket does not exist")
	}
	return nil
})
```

You can also create a bucket only if it doesn't exist by using the
`Tx.CreateBucketIfNotExists()` function. It's a common pattern to call this
function for all your top-level buckets after you open your database so you can
guarantee that they exist for future transactions.

To delete a bucket, simply call the `Tx.DeleteBucket()` function.

You can also iterate over all existing top-level buckets with `Tx.ForEach()`:

```go
db.View(func(tx *bolt.Tx) error {
	tx.ForEach(func(name []byte, b *bolt.Bucket) error {
		fmt.Println(string(name))
		return nil
	})
	return nil
})
```

### Using key/value pairs

To save a key/value pair to a bucket, use the `Bucket.Put()` function:

```go
db.Update(func(tx *bolt.Tx) error {
	b := tx.Bucket([]byte("MyBucket"))
	err := b.Put([]byte("answer"), []byte("42"))
	return err
})
```

This will set the value of the `"answer"` key to `"42"` in the `MyBucket`
bucket. To retrieve this value, we can use the `Bucket.Get()` function:

```go
db.View(func(tx *bolt.Tx) error {
	b := tx.Bucket([]byte("MyBucket"))
	v := b.Get([]byte("answer"))
	fmt.Printf("The answer is: %s\n", v)
	return nil
})
```

The `Get()` function does not return an error because its operation is
guaranteed to work (unless there is some kind of system failure). If the key
exists then it will return its byte slice value. If it doesn't exist then it
will return `nil`. It's important to note that you can have a zero-length value
set to a key which is different than the key not existing.

Use the `Bucket.Delete()` function to delete a key from the bucket:

```go
db.Update(func (tx *bolt.Tx) error {
    b := tx.Bucket([]byte("MyBucket"))
    err := b.Delete([]byte("answer"))
    return err
})
```

This will delete the key `answers` from the bucket `MyBucket`.

Please note that values returned from `Get()` are only valid while the
transaction is open. If you need to use a value outside of the transaction
then you must use `copy()` to copy it to another byte slice.


### Autoincrementing integer for the bucket
By using the `NextSequence()` function, you can let Bolt determine a sequence
which can be used as the unique identifier for your key/value pairs. See the
example below.

```go
// CreateUser saves u to the store. The new user ID is set on u once the data is persisted.
func (s *Store) CreateUser(u *User) error {
    return s.db.Update(func(tx *bolt.Tx) error {
        // Retrieve the users bucket.
        // This should be created when the DB is first opened.
        b := tx.Bucket([]byte("users"))

        // Generate ID for the user.
        // This returns an error only if the Tx is closed or not writeable.
        // That can't happen in an Update() call so I ignore the error check.
        id, _ := b.NextSequence()
        u.ID = int(id)

        // Marshal user data into bytes.
        buf, err := json.Marshal(u)
        if err != nil {
            return err
        }

        // Persist bytes to users bucket.
        return b.Put(itob(u.ID), buf)
    })
}

// itob returns an 8-byte big endian representation of v.
func itob(v int) []byte {
    b := make([]byte, 8)
    binary.BigEndian.PutUint64(b, uint64(v))
    return b
}

type User struct {
    ID int
    ...
}
```

### Iterating over keys

Bolt stores its keys in byte-sorted order within a bucket. This makes sequential
iteration over these keys extremely fast. To iterate over keys we'll use a
`Cursor`:

```go
db.View(func(tx *bolt.Tx) error {
	// Assume bucket exists and has keys
	b := tx.Bucket([]byte("MyBucket"))

	c := b.Cursor()

	for k, v := c.First(); k != nil; k, v = c.Next() {
		fmt.Printf("key=%s, value=%s\n", k, v)
	}

	return nil
})
```

The cursor allows you to move to a specific point in the list of keys and move
forward or backward through the keys one at a time.

The following functions are available on the cursor:

```
First()  Move to the first key.
Last()   Move to the last key.
Seek()   Move to a specific key.
Next()   Move to the next key.
Prev()   Move to the previous key.
```

Each of those functions has a return signature of `(key []byte, value []byte)`.
You must seek to a position using `First()`, `Last()`, or `Seek()` before calling
`Next()` or `Prev()`. If you do not seek to a position then these functions will
return a `nil` key.

When you have iterated to the end of the cursor, then `Next()` will return a
`nil` key and the cursor still points to the last element if present. When you
have iterated to the beginning of the cursor, then `Prev()` will return a `nil`
key and the cursor still points to the first element if present.

If you remove key/value pairs during iteration, the cursor may automatically
move to the next position if present in current node each time removing a key.
When you call `c.Next()` after removing a key, it may skip one key/value pair.
Refer to [pull/611](https://github.com/etcd-io/bbolt/pull/611) to get more detailed info.

During iteration, if the key is non-`nil` but the value is `nil`, that means
the key refers to a bucket rather than a value.  Use `Bucket.Bucket()` to
access the sub-bucket.


#### Prefix scans

To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`:

```go
db.View(func(tx *bolt.Tx) error {
	// Assume bucket exists and has keys
	c := tx.Bucket([]byte("MyBucket")).Cursor()

	prefix := []byte("1234")
	for k, v := c.Seek(prefix); k != nil && bytes.HasPrefix(k, prefix); k, v = c.Next() {
		fmt.Printf("key=%s, value=%s\n", k, v)
	}

	return nil
})
```

#### Range scans

Another common use case is scanning over a range such as a time range. If you
use a sortable time encoding such as RFC3339 then you can query a specific
date range like this:

```go
db.View(func(tx *bolt.Tx) error {
	// Assume our events bucket exists and has RFC3339 encoded time keys.
	c := tx.Bucket([]byte("Events")).Cursor()

	// Our time range spans the 90's decade.
	min := []byte("1990-01-01T00:00:00Z")
	max := []byte("2000-01-01T00:00:00Z")

	// Iterate over the 90's.
	for k, v := c.Seek(min); k != nil && bytes.Compare(k, max) <= 0; k, v = c.Next() {
		fmt.Printf("%s: %s\n", k, v)
	}

	return nil
})
```

Note that, while RFC3339 is sortable, the Golang implementation of RFC3339Nano does not use a fixed number of digits after the decimal point and is therefore not sortable.


#### ForEach()

You can also use the function `ForEach()` if you know you'll be iterating over
all the keys in a bucket:

```go
db.View(func(tx *bolt.Tx) error {
	// Assume bucket exists and has keys
	b := tx.Bucket([]byte("MyBucket"))

	b.ForEach(func(k, v []byte) error {
		fmt.Printf("key=%s, value=%s\n", k, v)
		return nil
	})
	return nil
})
```

Please note that keys and values in `ForEach()` are only valid while
the transaction is open. If you need to use a key or value outside of
the transaction, you must use `copy()` to copy it to another byte
slice.

### Nested buckets

You can also store a bucket in a key to create nested buckets. The API is the
same as the bucket management API on the `DB` object:

```go
func (*Bucket) CreateBucket(key []byte) (*Bucket, error)
func (*Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error)
func (*Bucket) DeleteBucket(key []byte) error
```

Say you had a multi-tenant application where the root level bucket was the account bucket. Inside of this bucket was a sequence of accounts which themselves are buckets. And inside the sequence bucket you could have many buckets pertaining to the Account itself (Users, Notes, etc) isolating the information into logical groupings.

```go

// createUser creates a new user in the given account.
func createUser(accountID int, u *User) error {
    // Start the transaction.
    tx, err := db.Begin(true)
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // Retrieve the root bucket for the account.
    // Assume this has already been created when the account was set up.
    root := tx.Bucket([]byte(strconv.FormatUint(accountID, 10)))

    // Setup the users bucket.
    bkt, err := root.CreateBucketIfNotExists([]byte("USERS"))
    if err != nil {
        return err
    }

    // Generate an ID for the new user.
    userID, err := bkt.NextSequence()
    if err != nil {
        return err
    }
    u.ID = userID

    // Marshal and save the encoded user.
    if buf, err := json.Marshal(u); err != nil {
        return err
    } else if err := bkt.Put([]byte(strconv.FormatUint(u.ID, 10)), buf); err != nil {
        return err
    }

    // Commit the transaction.
    if err := tx.Commit(); err != nil {
        return err
    }

    return nil
}

```




### Database backups

Bolt is a single file so it's easy to backup. You can use the `Tx.WriteTo()`
function to write a consistent view of the database to a writer. If you call
this from a read-only transaction, it will perform a hot backup and not block
your other database reads and writes.

By default, it will use a regular file handle which will utilize the operating
system's page cache. See the [`Tx`](https://godoc.org/go.etcd.io/bbolt#Tx)
documentation for information about optimizing for larger-than-RAM datasets.

One common use case is to backup over HTTP so you can use tools like `cURL` to
do database backups:

```go
func BackupHandleFunc(w http.ResponseWriter, req *http.Request) {
	err := db.View(func(tx *bolt.Tx) error {
		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("Content-Disposition", `attachment; filename="my.db"`)
		w.Header().Set("Content-Length", strconv.Itoa(int(tx.Size())))
		_, err := tx.WriteTo(w)
		return err
	})
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
```

Then you can backup using this command:

```sh
$ curl http://localhost/backup > my.db
```

Or you can open your browser to `http://localhost/backup` and it will download
automatically.

If you want to backup to another file you can use the `Tx.CopyFile()` helper
function.


### Statistics

The database keeps a running count of many of the internal operations it
performs so you can better understand what's going on. By grabbing a snapshot
of these stats at two points in time we can see what operations were performed
in that time range.

For example, we could start a goroutine to log stats every 10 seconds:

```go
go func() {
	// Grab the initial stats.
	prev := db.Stats()

	for {
		// Wait for 10s.
		time.Sleep(10 * time.Second)

		// Grab the current stats and diff them.
		stats := db.Stats()
		diff := stats.Sub(&prev)

		// Encode stats to JSON and print to STDERR.
		json.NewEncoder(os.Stderr).Encode(diff)

		// Save stats for the next loop.
		prev = stats
	}
}()
```

It's also useful to pipe these stats to a service such as statsd for monitoring
or to provide an HTTP endpoint that will perform a fixed-length sample.


### Read-Only Mode

Sometimes it is useful to create a shared, read-only Bolt database. To this,
set the `Options.ReadOnly` flag when opening your database. Read-only mode
uses a shared lock to allow multiple processes to read from the database but
it will block any processes from opening the database in read-write mode.

```go
db, err := bolt.Open("my.db", 0600, &bolt.Options{ReadOnly: true})
if err != nil {
	log.Fatal(err)
}
```

### Mobile Use (iOS/Android)

Bolt is able to run on mobile devices by leveraging the binding feature of the
[gomobile](https://github.com/golang/mobile) tool. Create a struct that will
contain your database logic and a reference to a `*bolt.DB` with a initializing
constructor that takes in a filepath where the database file will be stored.
Neither Android nor iOS require extra permissions or cleanup from using this method.

```go
func NewBoltDB(filepath string) *BoltDB {
	db, err := bolt.Open(filepath+"/demo.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	return &BoltDB{db}
}

type BoltDB struct {
	db *bolt.DB
	...
}

func (b *BoltDB) Path() string {
	return b.db.Path()
}

func (b *BoltDB) Close() {
	b.db.Close()
}
```

Database logic should be defined as methods on this wrapper struct.

To initialize this struct from the native language (both platforms now sync
their local storage to the cloud. These snippets disable that functionality for the
database file):

#### Android

```java
String path;
if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){
    path = getNoBackupFilesDir().getAbsolutePath();
} else{
    path = getFilesDir().getAbsolutePath();
}
Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path)
```

#### iOS

```objc
- (void)demo {
    NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
                                                          NSUserDomainMask,
                                                          YES) objectAtIndex:0];
	GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path);
	[self addSkipBackupAttributeToItemAtPath:demo.path];
	//Some DB Logic would go here
	[demo close];
}

- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
{
    NSURL* URL= [NSURL fileURLWithPath: filePathString];
    assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);

    NSError *error = nil;
    BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
                                  forKey: NSURLIsExcludedFromBackupKey error: &error];
    if(!success){
        NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
    }
    return success;
}

```

## Resources

For more information on getting started with Bolt, check out the following articles:

* [Intro to BoltDB: Painless Performant Persistence](http://npf.io/2014/07/intro-to-boltdb-painless-performant-persistence/) by [Nate Finch](https://github.com/natefinch).
* [Bolt -- an embedded key/value database for Go](https://www.progville.com/go/bolt-embedded-db-golang/) by Progville


## Comparison with other databases

### Postgres, MySQL, & other relational databases

Relational databases structure data into rows and are only accessible through
the use of SQL. This approach provides flexibility in how you store and query
your data but also incurs overhead in parsing and planning SQL statements. Bolt
accesses all data by a byte slice key. This makes Bolt fast to read and write
data by key but provides no built-in support for joining values together.

Most relational databases (with the exception of SQLite) are standalone servers
that run separately from your application. This gives your systems
flexibility to connect multiple application servers to a single database
server but also adds overhead in serializing and transporting data over the
network. Bolt runs as a library included in your application so all data access
has to go through your application's process. This brings data closer to your
application but limits multi-process access to the data.


### LevelDB, RocksDB

LevelDB and its derivatives (RocksDB, HyperLevelDB) are similar to Bolt in that
they are libraries bundled into the application, however, their underlying
structure is a log-structured merge-tree (LSM tree). An LSM tree optimizes
random writes by using a write ahead log and multi-tiered, sorted files called
SSTables. Bolt uses a B+tree internally and only a single file. Both approaches
have trade-offs.

If you require a high random write throughput (>10,000 w/sec) or you need to use
spinning disks then LevelDB could be a good choice. If your application is
read-heavy or does a lot of range scans then Bolt could be a good choice.

One other important consideration is that LevelDB does not have transactions.
It supports batch writing of key/values pairs and it supports read snapshots
but it will not give you the ability to do a compare-and-swap operation safely.
Bolt supports fully serializable ACID transactions.


### LMDB

Bolt was originally a port of LMDB so it is architecturally similar. Both use
a B+tree, have ACID semantics with fully serializable transactions, and support
lock-free MVCC using a single writer and multiple readers.

The two projects have somewhat diverged. LMDB heavily focuses on raw performance
while Bolt has focused on simplicity and ease of use. For example, LMDB allows
several unsafe actions such as direct writes for the sake of performance. Bolt
opts to disallow actions which can leave the database in a corrupted state. The
only exception to this in Bolt is `DB.NoSync`.

There are also a few differences in API. LMDB requires a maximum mmap size when
opening an `mdb_env` whereas Bolt will handle incremental mmap resizing
automatically. LMDB overloads the getter and setter functions with multiple
flags whereas Bolt splits these specialized cases into their own functions.


## Caveats & Limitations

It's important to pick the right tool for the job and Bolt is no exception.
Here are a few things to note when evaluating and using Bolt:

* Bolt is good for read intensive workloads. Sequential write performance is
  also fast but random writes can be slow. You can use `DB.Batch()` or add a
  write-ahead log to help mitigate this issue.

* Bolt uses a B+tree internally so there can be a lot of random page access.
  SSDs provide a significant performance boost over spinning disks.

* Try to avoid long running read transactions. Bolt uses copy-on-write so
  old pages cannot be reclaimed while an old transaction is using them.

* Byte slices returned from Bolt are only valid during a transaction. Once the
  transaction has been committed or rolled back then the memory they point to
  can be reused by a new page or can be unmapped from virtual memory and you'll
  see an `unexpected fault address` panic when accessing it.

* Bolt uses an exclusive write lock on the database file so it cannot be
  shared by multiple processes.

* Be careful when using `Bucket.FillPercent`. Setting a high fill percent for
  buckets that have random inserts will cause your database to have very poor
  page utilization.

* Use larger buckets in general. Smaller buckets causes poor page utilization
  once they become larger than the page size (typically 4KB).

* Bulk loading a lot of random writes into a new bucket can be slow as the
  page will not split until the transaction is committed. Randomly inserting
  more than 100,000 key/value pairs into a single new bucket in a single
  transaction is not advised.

* Bolt uses a memory-mapped file so the underlying operating system handles the
  caching of the data. Typically, the OS will cache as much of the file as it
  can in memory and will release memory as needed to other processes. This means
  that Bolt can show very high memory usage when working with large databases.
  However, this is expected and the OS will release memory as needed. Bolt can
  handle databases much larger than the available physical RAM, provided its
  memory-map fits in the process virtual address space. It may be problematic
  on 32-bits systems.

* The data structures in the Bolt database are memory mapped so the data file
  will be endian specific. This means that you cannot copy a Bolt file from a
  little endian machine to a big endian machine and have it work. For most
  users this is not a concern since most modern CPUs are little endian.

* Because of the way pages are laid out on disk, Bolt cannot truncate data files
  and return free pages back to the disk. Instead, Bolt maintains a free list
  of unused pages within its data file. These free pages can be reused by later
  transactions. This works well for many use cases as databases generally tend
  to grow. However, it's important to note that deleting large chunks of data
  will not allow you to reclaim that space on disk.

  For more information on page allocation, [see this comment][page-allocation].

* Removing key/values pairs in a bucket during iteration on the bucket using
  cursor may not work properly. Each time when removing a key/value pair, the
  cursor may automatically move to the next position if present. When users
  call `c.Next()` after removing a key, it may skip one key/value pair.
  Refer to https://github.com/etcd-io/bbolt/pull/611 for more detailed info.

* Bolt db can be corrupted during the initialization phase due to abrupt power failure.
  - Please note: This issue can only be reproduced during the very first initialization phase, when there is
  no existing data in bolt database.
  - In normal production environment, it is difficult to reproduce this. Once the database file has been initialized, it can no longer occur.
  - Please refer to this issue for more details: https://github.com/etcd-io/etcd/issues/16596.

[page-allocation]: https://github.com/boltdb/bolt/issues/308#issuecomment-74811638


## Reading the Source

Bolt is a relatively small code base (<5KLOC) for an embedded, serializable,
transactional key/value database so it can be a good starting point for people
interested in how databases work.

The best places to start are the main entry points into Bolt:

- `Open()` - Initializes the reference to the database. It's responsible for
  creating the database if it doesn't exist, obtaining an exclusive lock on the
  file, reading the meta pages, & memory-mapping the file.

- `DB.Begin()` - Starts a read-only or read-write transaction depending on the
  value of the `writable` argument. This requires briefly obtaining the "meta"
  lock to keep track of open transactions. Only one read-write transaction can
  exist at a time so the "rwlock" is acquired during the life of a read-write
  transaction.

- `Bucket.Put()` - Writes a key/value pair into a bucket. After validating the
  arguments, a cursor is used to traverse the B+tree to the page and position
  where the key & value will be written. Once the position is found, the bucket
  materializes the underlying page and the page's parent pages into memory as
  "nodes". These nodes are where mutations occur during read-write transactions.
  These changes get flushed to disk during commit.

- `Bucket.Get()` - Retrieves a key/value pair from a bucket. This uses a cursor
  to move to the page & position of a key/value pair. During a read-only
  transaction, the key and value data is returned as a direct reference to the
  underlying mmap file so there's no allocation overhead. For read-write
  transactions, this data may reference the mmap file or one of the in-memory
  node values.

- `Cursor` - This object is simply for traversing the B+tree of on-disk pages
  or in-memory nodes. It can seek to a specific key, move to the first or last
  value, or it can move forward or backward. The cursor handles the movement up
  and down the B+tree transparently to the end user.

- `Tx.Commit()` - Converts the in-memory dirty nodes and the list of free pages
  into pages to be written to disk. Writing to disk then occurs in two phases.
  First, the dirty pages are written to disk and an `fsync()` occurs. Second, a
  new meta page with an incremented transaction ID is written and another
  `fsync()` occurs. This two phase write ensures that partially written data
  pages are ignored in the event of a crash since the meta page pointing to them
  is never written. Partially written meta pages are invalidated because they
  are written with a checksum.

If you have additional notes that could be helpful for others, please submit
them via pull request.

## Known Issues

- bbolt might run into data corruption issue on Linux when the feature
  [ext4: fast commit](https://lwn.net/Articles/842385/), which was introduced in
  linux kernel version v5.10, is enabled. The fixes to the issue are included in
  stable LTS patchlevels 5.10.94+ and 5.15.17+ (ftruncate tracking), plus
  5.15.27+ (ineligible-commit fallback). Linux 5.17 includes these fixes as
  well, but 5.17 is not an LTS release. Please refer to links below,

  * [ext4: fast commit may miss tracking unwritten range during ftruncate](https://lore.kernel.org/linux-ext4/20211223032337.5198-3-yinxin.x@bytedance.com/)
    * [5.10.94 stable backport](https://lore.kernel.org/stable/20220124184041.063143682@linuxfoundation.org/)
    * [5.15.17 stable backport](https://lore.kernel.org/stable/20220124184125.887304707@linuxfoundation.org/)
  * [ext4: fast commit may not fallback for ineligible commit](https://lore.kernel.org/lkml/202201091544.W5HHEXAp-lkp@intel.com/T/#ma0768815e4b5f671e9e451d578256ef9a76fe30e)
    * [5.15.27 stable backport](https://lore.kernel.org/stable/20220307091703.544901888@linuxfoundation.org/)
  * [ext4 updates for 5.17](https://lore.kernel.org/lkml/YdyxjTFaLWif6BCM@mit.edu/)

  Please also refer to the discussion in https://github.com/etcd-io/bbolt/issues/562.

- Writing a value with a length of 0 will always result in reading back an empty `[]byte{}` value.
  Please refer to [issues/726#issuecomment-2061694802](https://github.com/etcd-io/bbolt/issues/726#issuecomment-2061694802).

## Other Projects Using Bolt

Below is a list of public, open source projects that use Bolt:

* [Algernon](https://github.com/xyproto/algernon) - A HTTP/2 web server with built-in support for Lua. Uses BoltDB as the default database backend.
* [Bazil](https://bazil.org/) - A file system that lets your data reside where it is most convenient for it to reside.
* [bolter](https://github.com/hasit/bolter) - Command-line app for viewing BoltDB file in your terminal.
* [boltcli](https://github.com/spacewander/boltcli) - the redis-cli for boltdb with Lua script support.
* [BoltHold](https://github.com/timshannon/bolthold) - An embeddable NoSQL store for Go types built on BoltDB
* [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt.
* [Boltdb Boilerplate](https://github.com/bobintornado/boltdb-boilerplate) - Boilerplate wrapper around bolt aiming to make simple calls one-liners.
* [BoltDbWeb](https://github.com/evnix/boltdbweb) - A web based GUI for BoltDB files.
* [BoltDB Viewer](https://github.com/zc310/rich_boltdb) - A BoltDB Viewer Can run on Windows、Linux、Android system.
* [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend.
* [bstore](https://github.com/mjl-/bstore) - Database library storing Go values, with referential/unique/nonzero constraints, indices, automatic schema management with struct tags, and a query API.
* [btcwallet](https://github.com/btcsuite/btcwallet) - A bitcoin wallet.
* [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining
  simple tx and key scans.
* [Buildkit](https://github.com/moby/buildkit) - concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit
* [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend.
* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
* [🌰 Chestnut](https://github.com/jrapoport/chestnut) - Chestnut is encrypted storage for Go.
* [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware.
* [Containerd](https://github.com/containerd/containerd) - An open and reliable container runtime
* [DVID](https://github.com/janelia-flyem/dvid) - Added Bolt as optional storage engine and testing it against Basho-tuned leveldb.
* [dcrwallet](https://github.com/decred/dcrwallet) - A wallet for the Decred cryptocurrency.
* [drive](https://github.com/odeke-em/drive) - drive is an unofficial Google Drive command line client for \*NIX operating systems.
* [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka.
* [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data.
* [Go Report Card](https://goreportcard.com/) - Go code quality report cards as a (free and open source) service.
* [GoWebApp](https://github.com/josephspurrier/gowebapp) - A basic MVC web application in Go using BoltDB.
* [GoShort](https://github.com/pankajkhairnar/goShort) - GoShort is a URL shortener written in Golang and BoltDB for persistent key/value storage and for routing it's using high performent HTTPRouter.
* [gopherpit](https://github.com/gopherpit/gopherpit) - A web service to manage Go remote import paths with custom domains
* [gokv](https://github.com/philippgille/gokv) - Simple key-value store abstraction and implementations for Go (Redis, Consul, etcd, bbolt, BadgerDB, LevelDB, Memcached, DynamoDB, S3, PostgreSQL, MongoDB, CockroachDB and many more)
* [goraphdb](https://github.com/mstrYoda/goraphdb) - A graph database provides Cypher query, fluent builder and management UI.
* [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
* [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
* [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed.
* [Ironsmith](https://github.com/timshannon/ironsmith) - A simple, script-driven continuous integration (build - > test -> release) tool, with no external dependencies
* [Kala](https://github.com/ajvb/kala) - Kala is a modern job scheduler optimized to run on a single node. It is persistent, JSON over HTTP API, ISO 8601 duration notation, and dependent jobs.
* [Key Value Access Language (KVAL)](https://github.com/kval-access-language) - A proposed grammar for key-value datastores offering a bbolt binding.
* [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage.
* [lru](https://github.com/crowdriff/lru) - Easy to use Bolt-backed Least-Recently-Used (LRU) read-through cache with chainable remote stores.
* [mbuckets](https://github.com/abhigupta912/mbuckets) - A Bolt wrapper that allows easy operations on multi level (nested) buckets.
* [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
* [MuLiFS](https://github.com/dankomiocevic/mulifs) - Music Library Filesystem creates a filesystem to organise your music files.
* [NATS](https://github.com/nats-io/nats-streaming-server) - NATS Streaming uses bbolt for message and metadata storage.
* [Portainer](https://github.com/portainer/portainer) - A lightweight service delivery platform for containerized applications that can be used to manage Docker, Swarm, Kubernetes and ACI environments.
* [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
* [Rain](https://github.com/cenkalti/rain) - BitTorrent client and library.
* [reef-pi](https://github.com/reef-pi/reef-pi) - reef-pi is an award winning, modular, DIY reef tank controller using easy to learn electronics based on a Raspberry Pi.
* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service
* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read.
* [stow](https://github.com/djherbis/stow) -  a persistence manager for objects
  backed by boltdb.
* [Storm](https://github.com/asdine/storm) - Simple and powerful ORM for BoltDB.
* [SimpleBolt](https://github.com/xyproto/simplebolt) - A simple way to use BoltDB. Deals mainly with strings.
* [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics.
* [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects.
* [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server.
* [torrent](https://github.com/anacrolix/torrent) - Full-featured BitTorrent client package and utilities in Go. BoltDB is a storage backend in development.
* [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday.

If you are using Bolt in a project please send a pull request to add it to the list.


================================================
FILE: allocate_test.go
================================================
package bbolt

import (
	"testing"

	"go.etcd.io/bbolt/internal/common"
	"go.etcd.io/bbolt/internal/freelist"
)

func TestTx_allocatePageStats(t *testing.T) {
	for n, f := range map[string]freelist.Interface{"hashmap": freelist.NewHashMapFreelist(), "array": freelist.NewArrayFreelist()} {
		t.Run(n, func(t *testing.T) {
			ids := []common.Pgid{2, 3}
			f.Init(ids)

			tx := &Tx{
				db: &DB{
					freelist: f,
					pageSize: common.DefaultPageSize,
				},
				meta:  &common.Meta{},
				pages: make(map[common.Pgid]*common.Page),
			}

			txStats := tx.Stats()
			prePageCnt := txStats.GetPageCount()
			allocateCnt := f.FreeCount()

			if _, err := tx.allocate(allocateCnt); err != nil {
				t.Fatal(err)
			}

			txStats = tx.Stats()
			if txStats.GetPageCount() != prePageCnt+int64(allocateCnt) {
				t.Errorf("Allocated %d but got %d page in stats", allocateCnt, txStats.GetPageCount())
			}
		})
	}
}


================================================
FILE: bolt_aix.go
================================================
//go:build aix

package bbolt

import (
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"

	"go.etcd.io/bbolt/internal/common"
)

// flock acquires an advisory lock on a file descriptor.
func flock(db *DB, exclusive bool, timeout time.Duration) error {
	var t time.Time
	if timeout != 0 {
		t = time.Now()
	}
	fd := db.file.Fd()
	var lockType int16
	if exclusive {
		lockType = syscall.F_WRLCK
	} else {
		lockType = syscall.F_RDLCK
	}
	for {
		// Attempt to obtain an exclusive lock.
		lock := syscall.Flock_t{Type: lockType}
		err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
		if err == nil {
			return nil
		} else if err != syscall.EAGAIN {
			return err
		}

		// If we timed out then return an error.
		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
			return ErrTimeout
		}

		// Wait for a bit and try again.
		time.Sleep(flockRetryTimeout)
	}
}

// funlock releases an advisory lock on a file descriptor.
func funlock(db *DB) error {
	var lock syscall.Flock_t
	lock.Start = 0
	lock.Len = 0
	lock.Type = syscall.F_UNLCK
	lock.Whence = 0
	return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
}

// mmap memory maps a DB's data file.
func mmap(db *DB, sz int) error {
	// Map the data file to memory.
	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
	if err != nil {
		return err
	}

	// Advise the kernel that the mmap is accessed randomly.
	if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
		return fmt.Errorf("madvise: %s", err)
	}

	// Save the original byte slice and convert to a byte array pointer.
	db.dataref = b
	db.data = (*[common.MaxMapSize]byte)(unsafe.Pointer(&b[0]))
	db.datasz = sz
	return nil
}

// munmap unmaps a DB's data file from memory.
func munmap(db *DB) error {
	// Ignore the unmap if we have no mapped data.
	if db.dataref == nil {
		return nil
	}

	// Unmap using the original byte slice.
	err := unix.Munmap(db.dataref)
	db.dataref = nil
	db.data = nil
	db.datasz = 0
	return err
}


================================================
FILE: bolt_android.go
================================================
package bbolt

import (
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"

	"go.etcd.io/bbolt/internal/common"
)

// flock acquires an advisory lock on a file descriptor.
func flock(db *DB, exclusive bool, timeout time.Duration) error {
	var t time.Time
	if timeout != 0 {
		t = time.Now()
	}
	fd := db.file.Fd()
	var lockType int16
	if exclusive {
		lockType = syscall.F_WRLCK
	} else {
		lockType = syscall.F_RDLCK
	}
	for {
		// Attempt to obtain an exclusive lock.
		lock := syscall.Flock_t{Type: lockType}
		err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
		if err == nil {
			return nil
		} else if err != syscall.EAGAIN {
			return err
		}

		// If we timed out then return an error.
		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
			return ErrTimeout
		}

		// Wait for a bit and try again.
		time.Sleep(flockRetryTimeout)
	}
}

// funlock releases an advisory lock on a file descriptor.
func funlock(db *DB) error {
	var lock syscall.Flock_t
	lock.Start = 0
	lock.Len = 0
	lock.Type = syscall.F_UNLCK
	lock.Whence = 0
	return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
}

// mmap memory maps a DB's data file.
func mmap(db *DB, sz int) error {
	// Map the data file to memory.
	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
	if err != nil {
		return err
	}

	// Advise the kernel that the mmap is accessed randomly.
	err = unix.Madvise(b, syscall.MADV_RANDOM)
	if err != nil && err != syscall.ENOSYS {
		// Ignore not implemented error in kernel because it still works.
		return fmt.Errorf("madvise: %s", err)
	}

	// Save the original byte slice and convert to a byte array pointer.
	db.dataref = b
	db.data = (*[common.MaxMapSize]byte)(unsafe.Pointer(&b[0]))
	db.datasz = sz
	return nil
}

// munmap unmaps a DB's data file from memory.
func munmap(db *DB) error {
	// Ignore the unmap if we have no mapped data.
	if db.dataref == nil {
		return nil
	}

	// Unmap using the original byte slice.
	err := unix.Munmap(db.dataref)
	db.dataref = nil
	db.data = nil
	db.datasz = 0
	return err
}


================================================
FILE: bolt_linux.go
================================================
package bbolt

import (
	"syscall"
)

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
	return syscall.Fdatasync(int(db.file.Fd()))
}


================================================
FILE: bolt_openbsd.go
================================================
package bbolt

import (
	"golang.org/x/sys/unix"
)

func msync(db *DB) error {
	return unix.Msync(db.data[:db.datasz], unix.MS_INVALIDATE)
}

func fdatasync(db *DB) error {
	if db.data != nil {
		return msync(db)
	}
	return db.file.Sync()
}


================================================
FILE: bolt_solaris.go
================================================
package bbolt

import (
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"

	"go.etcd.io/bbolt/internal/common"
)

// flock acquires an advisory lock on a file descriptor.
func flock(db *DB, exclusive bool, timeout time.Duration) error {
	var t time.Time
	if timeout != 0 {
		t = time.Now()
	}
	fd := db.file.Fd()
	var lockType int16
	if exclusive {
		lockType = syscall.F_WRLCK
	} else {
		lockType = syscall.F_RDLCK
	}
	for {
		// Attempt to obtain an exclusive lock.
		lock := syscall.Flock_t{Type: lockType}
		err := syscall.FcntlFlock(fd, syscall.F_SETLK, &lock)
		if err == nil {
			return nil
		} else if err != syscall.EAGAIN {
			return err
		}

		// If we timed out then return an error.
		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
			return ErrTimeout
		}

		// Wait for a bit and try again.
		time.Sleep(flockRetryTimeout)
	}
}

// funlock releases an advisory lock on a file descriptor.
func funlock(db *DB) error {
	var lock syscall.Flock_t
	lock.Start = 0
	lock.Len = 0
	lock.Type = syscall.F_UNLCK
	lock.Whence = 0
	return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
}

// mmap memory maps a DB's data file.
func mmap(db *DB, sz int) error {
	// Map the data file to memory.
	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
	if err != nil {
		return err
	}

	// Advise the kernel that the mmap is accessed randomly.
	if err := unix.Madvise(b, syscall.MADV_RANDOM); err != nil {
		return fmt.Errorf("madvise: %s", err)
	}

	// Save the original byte slice and convert to a byte array pointer.
	db.dataref = b
	db.data = (*[common.MaxMapSize]byte)(unsafe.Pointer(&b[0]))
	db.datasz = sz
	return nil
}

// munmap unmaps a DB's data file from memory.
func munmap(db *DB) error {
	// Ignore the unmap if we have no mapped data.
	if db.dataref == nil {
		return nil
	}

	// Unmap using the original byte slice.
	err := unix.Munmap(db.dataref)
	db.dataref = nil
	db.data = nil
	db.datasz = 0
	return err
}


================================================
FILE: bolt_unix.go
================================================
//go:build !windows && !plan9 && !solaris && !aix && !android

package bbolt

import (
	"fmt"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/unix"

	"go.etcd.io/bbolt/errors"
	"go.etcd.io/bbolt/internal/common"
)

// flock acquires an advisory lock on a file descriptor.
func flock(db *DB, exclusive bool, timeout time.Duration) error {
	var t time.Time
	if timeout != 0 {
		t = time.Now()
	}
	fd := db.file.Fd()
	flag := syscall.LOCK_NB
	if exclusive {
		flag |= syscall.LOCK_EX
	} else {
		flag |= syscall.LOCK_SH
	}
	for {
		// Attempt to obtain an exclusive lock.
		err := syscall.Flock(int(fd), flag)
		if err == nil {
			return nil
		} else if err != syscall.EWOULDBLOCK {
			return err
		}

		// If we timed out then return an error.
		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
			return errors.ErrTimeout
		}

		// Wait for a bit and try again.
		time.Sleep(flockRetryTimeout)
	}
}

// funlock releases an advisory lock on a file descriptor.
func funlock(db *DB) error {
	return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
}

// mmap memory maps a DB's data file.
func mmap(db *DB, sz int) error {
	// Map the data file to memory.
	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
	if err != nil {
		return err
	}

	// Advise the kernel that the mmap is accessed randomly.
	err = unix.Madvise(b, syscall.MADV_RANDOM)
	if err != nil && err != syscall.ENOSYS {
		// Ignore not implemented error in kernel because it still works.
		return fmt.Errorf("madvise: %s", err)
	}

	// Save the original byte slice and convert to a byte array pointer.
	db.dataref = b
	db.data = (*[common.MaxMapSize]byte)(unsafe.Pointer(&b[0]))
	db.datasz = sz
	return nil
}

// munmap unmaps a DB's data file from memory.
func munmap(db *DB) error {
	// Ignore the unmap if we have no mapped data.
	if db.dataref == nil {
		return nil
	}

	// Unmap using the original byte slice.
	err := unix.Munmap(db.dataref)
	db.dataref = nil
	db.data = nil
	db.datasz = 0
	return err
}


================================================
FILE: bolt_windows.go
================================================
package bbolt

import (
	"fmt"
	"os"
	"syscall"
	"time"
	"unsafe"

	"golang.org/x/sys/windows"

	"go.etcd.io/bbolt/errors"
	"go.etcd.io/bbolt/internal/common"
)

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
	return db.file.Sync()
}

// flock acquires an advisory lock on a file descriptor.
func flock(db *DB, exclusive bool, timeout time.Duration) error {
	var t time.Time
	if timeout != 0 {
		t = time.Now()
	}
	var flags uint32 = windows.LOCKFILE_FAIL_IMMEDIATELY
	if exclusive {
		flags |= windows.LOCKFILE_EXCLUSIVE_LOCK
	}
	for {
		// Fix for https://github.com/etcd-io/bbolt/issues/121. Use byte-range
		// -1..0 as the lock on the database file.
		var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
		err := windows.LockFileEx(windows.Handle(db.file.Fd()), flags, 0, 1, 0, &windows.Overlapped{
			Offset:     m1,
			OffsetHigh: m1,
		})

		if err == nil {
			return nil
		} else if err != windows.ERROR_LOCK_VIOLATION {
			return err
		}

		// If we timed oumercit then return an error.
		if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout {
			return errors.ErrTimeout
		}

		// Wait for a bit and try again.
		time.Sleep(flockRetryTimeout)
	}
}

// funlock releases an advisory lock on a file descriptor.
func funlock(db *DB) error {
	var m1 uint32 = (1 << 32) - 1 // -1 in a uint32
	return windows.UnlockFileEx(windows.Handle(db.file.Fd()), 0, 1, 0, &windows.Overlapped{
		Offset:     m1,
		OffsetHigh: m1,
	})
}

// mmap memory maps a DB's data file.
// Based on: https://github.com/edsrzf/mmap-go
func mmap(db *DB, sz int) error {
	var sizelo, sizehi uint32

	if !db.readOnly {
		if db.MaxSize > 0 && sz > db.MaxSize {
			// The max size only limits future writes; however, we don’t block opening
			// and mapping the database if it already exceeds the limit.
			fileSize, err := db.fileSize()
			if err != nil {
				return fmt.Errorf("could not check existing db file size: %s", err)
			}

			if sz > fileSize {
				return errors.ErrMaxSizeReached
			}
		}

		// Truncate the database to the size of the mmap.
		if err := db.file.Truncate(int64(sz)); err != nil {
			return fmt.Errorf("truncate: %s", err)
		}
		sizehi = uint32(sz >> 32)
		sizelo = uint32(sz)
	}

	// Open a file mapping handle.
	h, errno := syscall.CreateFileMapping(syscall.Handle(db.file.Fd()), nil, syscall.PAGE_READONLY, sizehi, sizelo, nil)
	if h == 0 {
		return os.NewSyscallError("CreateFileMapping", errno)
	}

	// Create the memory map.
	addr, errno := syscall.MapViewOfFile(h, syscall.FILE_MAP_READ, 0, 0, 0)
	if addr == 0 {
		// Do our best and report error returned from MapViewOfFile.
		_ = syscall.CloseHandle(h)
		return os.NewSyscallError("MapViewOfFile", errno)
	}

	// Close mapping handle.
	if err := syscall.CloseHandle(syscall.Handle(h)); err != nil {
		return os.NewSyscallError("CloseHandle", err)
	}

	// Convert to a byte array.
	db.data = (*[common.MaxMapSize]byte)(unsafe.Pointer(addr))
	db.datasz = sz

	return nil
}

// munmap unmaps a pointer from a file.
// Based on: https://github.com/edsrzf/mmap-go
func munmap(db *DB) error {
	if db.data == nil {
		return nil
	}

	addr := (uintptr)(unsafe.Pointer(&db.data[0]))
	var err1 error
	if err := syscall.UnmapViewOfFile(addr); err != nil {
		err1 = os.NewSyscallError("UnmapViewOfFile", err)
	}
	db.data = nil
	db.datasz = 0
	return err1
}


================================================
FILE: boltsync_unix.go
================================================
//go:build !windows && !plan9 && !linux && !openbsd

package bbolt

// fdatasync flushes written data to a file descriptor.
func fdatasync(db *DB) error {
	return db.file.Sync()
}


================================================
FILE: bucket.go
================================================
package bbolt

import (
	"bytes"
	"fmt"
	"unsafe"

	"go.etcd.io/bbolt/errors"
	"go.etcd.io/bbolt/internal/common"
)

const (
	// MaxKeySize is the maximum length of a key, in bytes.
	MaxKeySize = 32768

	// MaxValueSize is the maximum length of a value, in bytes.
	MaxValueSize = (1 << 31) - 2
)

const (
	minFillPercent = 0.1
	maxFillPercent = 1.0
)

// DefaultFillPercent is the percentage that split pages are filled.
// This value can be changed by setting Bucket.FillPercent.
const DefaultFillPercent = 0.5

// Bucket represents a collection of key/value pairs inside the database.
type Bucket struct {
	*common.InBucket
	tx       *Tx                   // the associated transaction
	buckets  map[string]*Bucket    // subbucket cache
	page     *common.Page          // inline page reference
	rootNode *node                 // materialized node for the root page.
	nodes    map[common.Pgid]*node // node cache

	// Sets the threshold for filling nodes when they split. By default,
	// the bucket will fill to 50% but it can be useful to increase this
	// amount if you know that your write workloads are mostly append-only.
	//
	// This is non-persisted across transactions so it must be set in every Tx.
	FillPercent float64
}

// newBucket returns a new bucket associated with a transaction.
func newBucket(tx *Tx) Bucket {
	var b = Bucket{tx: tx, FillPercent: DefaultFillPercent}
	if tx.writable {
		b.buckets = make(map[string]*Bucket)
		b.nodes = make(map[common.Pgid]*node)
	}
	return b
}

// Tx returns the tx of the bucket.
func (b *Bucket) Tx() *Tx {
	return b.tx
}

// Root returns the root of the bucket.
func (b *Bucket) Root() common.Pgid {
	return b.RootPage()
}

// Writable returns whether the bucket is writable.
func (b *Bucket) Writable() bool {
	return b.tx.writable
}

// Cursor creates a cursor associated with the bucket.
// The cursor is only valid as long as the transaction is open.
// Do not use a cursor after the transaction is closed.
func (b *Bucket) Cursor() *Cursor {
	// Update transaction statistics.
	b.tx.stats.IncCursorCount(1)

	// Allocate and return a cursor.
	return &Cursor{
		bucket: b,
		stack:  make([]elemRef, 0),
	}
}

// Bucket retrieves a nested bucket by name.
// Returns nil if the bucket does not exist.
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) Bucket(name []byte) *Bucket {
	if b.buckets != nil {
		if child := b.buckets[string(name)]; child != nil {
			return child
		}
	}

	// Move cursor to key.
	c := b.Cursor()
	k, v, flags := c.seek(name)

	// Return nil if the key doesn't exist or it is not a bucket.
	if !bytes.Equal(name, k) || (flags&common.BucketLeafFlag) == 0 {
		return nil
	}

	// Otherwise create a bucket and cache it.
	var child = b.openBucket(v)
	if b.buckets != nil {
		b.buckets[string(name)] = child
	}

	return child
}

// Helper method that re-interprets a sub-bucket value
// from a parent into a Bucket
func (b *Bucket) openBucket(value []byte) *Bucket {
	var child = newBucket(b.tx)

	// Unaligned access requires a copy to be made.
	const unalignedMask = unsafe.Alignof(struct {
		common.InBucket
		common.Page
	}{}) - 1
	unaligned := uintptr(unsafe.Pointer(&value[0]))&unalignedMask != 0
	if unaligned {
		value = cloneBytes(value)
	}

	// If this is a writable transaction then we need to copy the bucket entry.
	// Read-only transactions can point directly at the mmap entry.
	if b.tx.writable && !unaligned {
		child.InBucket = &common.InBucket{}
		*child.InBucket = *(*common.InBucket)(unsafe.Pointer(&value[0]))
	} else {
		child.InBucket = (*common.InBucket)(unsafe.Pointer(&value[0]))
	}

	// Save a reference to the inline page if the bucket is inline.
	if child.RootPage() == 0 {
		child.page = (*common.Page)(unsafe.Pointer(&value[common.BucketHeaderSize]))
	}

	return &child
}

// CreateBucket creates a new bucket at the given key and returns the new bucket.
// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long.
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) CreateBucket(key []byte) (rb *Bucket, err error) {
	if lg := b.tx.db.Logger(); lg != discardLogger {
		lg.Debugf("Creating bucket %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Creating bucket %q failed: %v", key, err)
			} else {
				lg.Debugf("Creating bucket %q successfully", key)
			}
		}()
	}
	if b.tx.db == nil {
		return nil, errors.ErrTxClosed
	} else if !b.tx.writable {
		return nil, errors.ErrTxNotWritable
	} else if len(key) == 0 {
		return nil, errors.ErrBucketNameRequired
	}

	// Insert into node.
	// Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent
	// it from being marked as leaking, and accordingly cannot be allocated on stack.
	newKey := cloneBytes(key)

	// Move cursor to correct position.
	c := b.Cursor()
	k, _, flags := c.seek(newKey)

	// Return an error if there is an existing key.
	if bytes.Equal(newKey, k) {
		if (flags & common.BucketLeafFlag) != 0 {
			return nil, errors.ErrBucketExists
		}
		return nil, errors.ErrIncompatibleValue
	}

	// Create empty, inline bucket.
	var bucket = Bucket{
		InBucket:    &common.InBucket{},
		rootNode:    &node{isLeaf: true},
		FillPercent: DefaultFillPercent,
	}
	var value = bucket.write()

	c.node().put(newKey, newKey, value, 0, common.BucketLeafFlag)

	// Since subbuckets are not allowed on inline buckets, we need to
	// dereference the inline page, if it exists. This will cause the bucket
	// to be treated as a regular, non-inline bucket for the rest of the tx.
	b.page = nil

	return b.Bucket(newKey), nil
}

// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it.
// Returns an error if the bucket name is blank, or if the bucket name is too long.
// The bucket instance is only valid for the lifetime of the transaction.
func (b *Bucket) CreateBucketIfNotExists(key []byte) (rb *Bucket, err error) {
	if lg := b.tx.db.Logger(); lg != discardLogger {
		lg.Debugf("Creating bucket if not exist %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Creating bucket if not exist %q failed: %v", key, err)
			} else {
				lg.Debugf("Creating bucket if not exist %q successfully", key)
			}
		}()
	}

	if b.tx.db == nil {
		return nil, errors.ErrTxClosed
	} else if !b.tx.writable {
		return nil, errors.ErrTxNotWritable
	} else if len(key) == 0 {
		return nil, errors.ErrBucketNameRequired
	}

	// Insert into node.
	// Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent
	// it from being marked as leaking, and accordingly cannot be allocated on stack.
	newKey := cloneBytes(key)

	if b.buckets != nil {
		if child := b.buckets[string(newKey)]; child != nil {
			return child, nil
		}
	}

	// Move cursor to correct position.
	c := b.Cursor()
	k, v, flags := c.seek(newKey)

	// Return an error if there is an existing non-bucket key.
	if bytes.Equal(newKey, k) {
		if (flags & common.BucketLeafFlag) != 0 {
			var child = b.openBucket(v)
			if b.buckets != nil {
				b.buckets[string(newKey)] = child
			}

			return child, nil
		}
		return nil, errors.ErrIncompatibleValue
	}

	// Create empty, inline bucket.
	var bucket = Bucket{
		InBucket:    &common.InBucket{},
		rootNode:    &node{isLeaf: true},
		FillPercent: DefaultFillPercent,
	}
	var value = bucket.write()

	c.node().put(newKey, newKey, value, 0, common.BucketLeafFlag)

	// Since subbuckets are not allowed on inline buckets, we need to
	// dereference the inline page, if it exists. This will cause the bucket
	// to be treated as a regular, non-inline bucket for the rest of the tx.
	b.page = nil

	return b.Bucket(newKey), nil
}

// DeleteBucket deletes a bucket at the given key.
// Returns an error if the bucket does not exist, or if the key represents a non-bucket value.
func (b *Bucket) DeleteBucket(key []byte) (err error) {
	if lg := b.tx.db.Logger(); lg != discardLogger {
		lg.Debugf("Deleting bucket %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Deleting bucket %q failed: %v", key, err)
			} else {
				lg.Debugf("Deleting bucket %q successfully", key)
			}
		}()
	}

	if b.tx.db == nil {
		return errors.ErrTxClosed
	} else if !b.Writable() {
		return errors.ErrTxNotWritable
	}

	newKey := cloneBytes(key)

	// Move cursor to correct position.
	c := b.Cursor()
	k, _, flags := c.seek(newKey)

	// Return an error if bucket doesn't exist or is not a bucket.
	if !bytes.Equal(newKey, k) {
		return errors.ErrBucketNotFound
	} else if (flags & common.BucketLeafFlag) == 0 {
		return errors.ErrIncompatibleValue
	}

	// Recursively delete all child buckets.
	child := b.Bucket(newKey)
	err = child.ForEachBucket(func(k []byte) error {
		if err := child.DeleteBucket(k); err != nil {
			return fmt.Errorf("delete bucket: %s", err)
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Remove cached copy.
	delete(b.buckets, string(newKey))

	// Release all bucket pages to freelist.
	child.nodes = nil
	child.rootNode = nil
	child.free()

	// Delete the node if we have a matching key.
	c.node().del(newKey)

	return nil
}

// MoveBucket moves a sub-bucket from the source bucket to the destination bucket.
// Returns an error if
//  1. the sub-bucket cannot be found in the source bucket;
//  2. or the key already exists in the destination bucket;
//  3. or the key represents a non-bucket value;
//  4. the source and destination buckets are the same.
func (b *Bucket) MoveBucket(key []byte, dstBucket *Bucket) (err error) {
	lg := b.tx.db.Logger()
	if lg != discardLogger {
		lg.Debugf("Moving bucket %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Moving bucket %q failed: %v", key, err)
			} else {
				lg.Debugf("Moving bucket %q successfully", key)
			}
		}()
	}

	if b.tx.db == nil || dstBucket.tx.db == nil {
		return errors.ErrTxClosed
	} else if !b.Writable() || !dstBucket.Writable() {
		return errors.ErrTxNotWritable
	}

	if b.tx.db.Path() != dstBucket.tx.db.Path() || b.tx != dstBucket.tx {
		lg.Errorf("The source and target buckets are not in the same db file, source bucket in %s and target bucket in %s", b.tx.db.Path(), dstBucket.tx.db.Path())
		return errors.ErrDifferentDB
	}

	newKey := cloneBytes(key)

	// Move cursor to correct position.
	c := b.Cursor()
	k, v, flags := c.seek(newKey)

	// Return an error if bucket doesn't exist or is not a bucket.
	if !bytes.Equal(newKey, k) {
		return errors.ErrBucketNotFound
	} else if (flags & common.BucketLeafFlag) == 0 {
		lg.Errorf("An incompatible key %s exists in the source bucket", newKey)
		return errors.ErrIncompatibleValue
	}

	// Do nothing (return true directly) if the source bucket and the
	// destination bucket are actually the same bucket.
	if b == dstBucket || (b.RootPage() == dstBucket.RootPage() && b.RootPage() != 0) {
		lg.Errorf("The source bucket (%s) and the target bucket (%s) are the same bucket", b, dstBucket)
		return errors.ErrSameBuckets
	}

	// check whether the key already exists in the destination bucket
	curDst := dstBucket.Cursor()
	k, _, flags = curDst.seek(newKey)

	// Return an error if there is an existing key in the destination bucket.
	if bytes.Equal(newKey, k) {
		if (flags & common.BucketLeafFlag) != 0 {
			return errors.ErrBucketExists
		}
		lg.Errorf("An incompatible key %s exists in the target bucket", newKey)
		return errors.ErrIncompatibleValue
	}

	// remove the sub-bucket from the source bucket
	delete(b.buckets, string(newKey))
	c.node().del(newKey)

	// add te sub-bucket to the destination bucket
	newValue := cloneBytes(v)
	curDst.node().put(newKey, newKey, newValue, 0, common.BucketLeafFlag)

	return nil
}

// Inspect returns the structure of the bucket.
func (b *Bucket) Inspect() BucketStructure {
	return b.recursivelyInspect([]byte("root"))
}

func (b *Bucket) recursivelyInspect(name []byte) BucketStructure {
	bs := BucketStructure{Name: string(name)}

	keyN := 0
	c := b.Cursor()
	for k, _, flags := c.first(); k != nil; k, _, flags = c.next() {
		if flags&common.BucketLeafFlag != 0 {
			childBucket := b.Bucket(k)
			childBS := childBucket.recursivelyInspect(k)
			bs.Children = append(bs.Children, childBS)
		} else {
			keyN++
		}
	}
	bs.KeyN = keyN

	return bs
}

// Get retrieves the value for a key in the bucket.
// Returns a nil value if the key does not exist or if the key is a nested bucket.
// The returned value is only valid for the life of the transaction.
// The returned memory is owned by bbolt and must never be modified; writing to this memory might corrupt the database.
func (b *Bucket) Get(key []byte) []byte {
	k, v, flags := b.Cursor().seek(key)

	// Return nil if this is a bucket.
	if (flags & common.BucketLeafFlag) != 0 {
		return nil
	}

	// If our target node isn't the same key as what's passed in then return nil.
	if !bytes.Equal(key, k) {
		return nil
	}
	return v
}

// Put sets the value for a key in the bucket.
// If the key exist then its previous value will be overwritten.
// Supplied value must remain valid for the life of the transaction.
// Returns an error if the bucket was created from a read-only transaction, if the key is blank, if the key is too large, or if the value is too large.
func (b *Bucket) Put(key []byte, value []byte) (err error) {
	if lg := b.tx.db.Logger(); lg != discardLogger {
		lg.Debugf("Putting key %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Putting key %q failed: %v", key, err)
			} else {
				lg.Debugf("Putting key %q successfully", key)
			}
		}()
	}
	if b.tx.db == nil {
		return errors.ErrTxClosed
	} else if !b.Writable() {
		return errors.ErrTxNotWritable
	} else if len(key) == 0 {
		return errors.ErrKeyRequired
	} else if len(key) > MaxKeySize {
		return errors.ErrKeyTooLarge
	} else if int64(len(value)) > MaxValueSize {
		return errors.ErrValueTooLarge
	}

	// Insert into node.
	// Tip: Use a new variable `newKey` instead of reusing the existing `key` to prevent
	// it from being marked as leaking, and accordingly cannot be allocated on stack.
	newKey := cloneBytes(key)

	// Move cursor to correct position.
	c := b.Cursor()
	k, _, flags := c.seek(newKey)

	// Return an error if there is an existing key with a bucket value.
	if bytes.Equal(newKey, k) && (flags&common.BucketLeafFlag) != 0 {
		return errors.ErrIncompatibleValue
	}

	// gofail: var beforeBucketPut struct{}

	c.node().put(newKey, newKey, value, 0, 0)

	return nil
}

// Delete removes a key from the bucket.
// If the key does not exist then nothing is done and a nil error is returned.
// Returns an error if the bucket was created from a read-only transaction.
func (b *Bucket) Delete(key []byte) (err error) {
	if lg := b.tx.db.Logger(); lg != discardLogger {
		lg.Debugf("Deleting key %q", key)
		defer func() {
			if err != nil {
				lg.Errorf("Deleting key %q failed: %v", key, err)
			} else {
				lg.Debugf("Deleting key %q successfully", key)
			}
		}()
	}

	if b.tx.db == nil {
		return errors.ErrTxClosed
	} else if !b.Writable() {
		return errors.ErrTxNotWritable
	}

	// Move cursor to correct position.
	c := b.Cursor()
	k, _, flags := c.seek(key)

	// Return nil if the key doesn't exist.
	if !bytes.Equal(key, k) {
		return nil
	}

	// Return an error if there is already existing bucket value.
	if (flags & common.BucketLeafFlag) != 0 {
		return errors.ErrIncompatibleValue
	}

	// Delete the node if we have a matching key.
	c.node().del(key)

	return nil
}

// Sequence returns the current integer for the bucket without incrementing it.
func (b *Bucket) Sequence() uint64 {
	return b.InSequence()
}

// SetSequence updates the sequence number for the bucket.
func (b *Bucket) SetSequence(v uint64) error {
	if b.tx.db == nil {
		return errors.ErrTxClosed
	} else if !b.Writable() {
		return errors.ErrTxNotWritable
	}

	// Materialize the root node if it hasn't been already so that the
	// bucket will be saved during commit.
	if b.rootNode == nil {
		_ = b.node(b.RootPage(), nil)
	}

	// Set the sequence.
	b.SetInSequence(v)
	return nil
}

// NextSequence returns an autoincrementing integer for the bucket.
func (b *Bucket) NextSequence() (uint64, error) {
	if b.tx.db == nil {
		return 0, errors.ErrTxClosed
	} else if !b.Writable() {
		return 0, errors.ErrTxNotWritable
	}

	// Materialize the root node if it hasn't been already so that the
	// bucket will be saved during commit.
	if b.rootNode == nil {
		_ = b.node(b.RootPage(), nil)
	}

	// Increment and return the sequence.
	b.IncSequence()
	return b.Sequence(), nil
}

// ForEach executes a function for each key/value pair in a bucket.
// Because ForEach uses a Cursor, the iteration over keys is in lexicographical order.
// If the provided function returns an error then the iteration is stopped and
// the error is returned to the caller. The provided function must not modify
// the bucket; this will result in undefined behavior.
func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
	if b.tx.db == nil {
		return errors.ErrTxClosed
	}
	c := b.Cursor()
	for k, v := c.First(); k != nil; k, v = c.Next() {
		if err := fn(k, v); err != nil {
			return err
		}
	}
	return nil
}

func (b *Bucket) ForEachBucket(fn func(k []byte) error) error {
	if b.tx.db == nil {
		return errors.ErrTxClosed
	}
	c := b.Cursor()
	for k, _, flags := c.first(); k != nil; k, _, flags = c.next() {
		if flags&common.BucketLeafFlag != 0 {
			if err := fn(k); err != nil {
				return err
			}
		}
	}
	return nil
}

// Stats returns stats on a bucket.
func (b *Bucket) Stats() BucketStats {
	var s, subStats BucketStats
	pageSize := b.tx.db.pageSize
	s.BucketN += 1
	if b.RootPage() == 0 {
		s.InlineBucketN += 1
	}
	b.forEachPage(func(p *common.Page, depth int, pgstack []common.Pgid) {
		if p.IsLeafPage() {
			s.KeyN += int(p.Count())

			// used totals the used bytes for the page
			used := common.PageHeaderSize

			if p.Count() != 0 {
				// If page has any elements, add all element headers.
				used += common.LeafPageElementSize * uintptr(p.Count()-1)

				// Add all element key, value sizes.
				// The computation takes advantage of the fact that the position
				// of the last element's key/value equals to the total of the sizes
				// of all previous elements' keys and values.
				// It also includes the last element's header.
				lastElement := p.LeafPageElement(p.Count() - 1)
				used += uintptr(lastElement.Pos() + lastElement.Ksize() + lastElement.Vsize())
			}

			if b.RootPage() == 0 {
				// For inlined bucket just update the inline stats
				s.InlineBucketInuse += int(used)
			} else {
				// For non-inlined bucket update all the leaf stats
				s.LeafPageN++
				s.LeafInuse += int(used)
				s.LeafOverflowN += int(p.Overflow())

				// Collect stats from sub-buckets.
				// Do that by iterating over all element headers
				// looking for the ones with the bucketLeafFlag.
				for i := uint16(0); i < p.Count(); i++ {
					e := p.LeafPageElement(i)
					if (e.Flags() & common.BucketLeafFlag) != 0 {
						// For any bucket element, open the element value
						// and recursively call Stats on the contained bucket.
						subStats.Add(b.openBucket(e.Value()).Stats())
					}
				}
			}
		} else if p.IsBranchPage() {
			s.BranchPageN++
			lastElement := p.BranchPageElement(p.Count() - 1)

			// used totals the used bytes for the page
			// Add header and all element headers.
			used := common.PageHeaderSize + (common.BranchPageElementSize * uintptr(p.Count()-1))

			// Add size of all keys and values.
			// Again, use the fact that last element's position equals to
			// the total of key, value sizes of all previous elements.
			used += uintptr(lastElement.Pos() + lastElement.Ksize())
			s.BranchInuse += int(used)
			s.BranchOverflowN += int(p.Overflow())
		}

		// Keep track of maximum page depth.
		if depth+1 > s.Depth {
			s.Depth = depth + 1
		}
	})

	// Alloc stats can be computed from page counts and pageSize.
	s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize
	s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize

	// Add the max depth of sub-buckets to get total nested depth.
	s.Depth += subStats.Depth
	// Add the stats for all sub-buckets
	s.Add(subStats)
	return s
}

// forEachPage iterates over every page in a bucket, including inline pages.
func (b *Bucket) forEachPage(fn func(*common.Page, int, []common.Pgid)) {
	// If we have an inline page then just use that.
	if b.page != nil {
		fn(b.page, 0, []common.Pgid{b.RootPage()})
		return
	}

	// Otherwise traverse the page hierarchy.
	b.tx.forEachPage(b.RootPage(), fn)
}

// forEachPageNode iterates over every page (or node) in a bucket.
// This also includes inline pages.
func (b *Bucket) forEachPageNode(fn func(*common.Page, *node, int)) {
	// If we have an inline page or root node then just use that.
	if b.page != nil {
		fn(b.page, nil, 0)
		return
	}
	b._forEachPageNode(b.RootPage(), 0, fn)
}

func (b *Bucket) _forEachPageNode(pgId common.Pgid, depth int, fn func(*common.Page, *node, int)) {
	var p, n = b.pageNode(pgId)

	// Execute function.
	fn(p, n, depth)

	// Recursively loop over children.
	if p != nil {
		if p.IsBranchPage() {
			for i := 0; i < int(p.Count()); i++ {
				elem := p.BranchPageElement(uint16(i))
				b._forEachPageNode(elem.Pgid(), depth+1, fn)
			}
		}
	} else {
		if !n.isLeaf {
			for _, inode := range n.inodes {
				b._forEachPageNode(inode.Pgid(), depth+1, fn)
			}
		}
	}
}

// spill writes all the nodes for this bucket to dirty pages.
func (b *Bucket) spill() error {
	// Spill all child buckets first.
	for name, child := range b.buckets {
		// If the child bucket is small enough and it has no child buckets then
		// write it inline into the parent bucket's page. Otherwise spill it
		// like a normal bucket and make the parent value a pointer to the page.
		var value []byte
		if child.inlineable() {
			child.free()
			value = child.write()
		} else {
			if err := child.spill(); err != nil {
				return err
			}

			// Update the child bucket header in this bucket.
			value = make([]byte, unsafe.Sizeof(common.InBucket{}))
			var bucket = (*common.InBucket)(unsafe.Pointer(&value[0]))
			*bucket = *child.InBucket
		}

		// Skip writing the bucket if there are no materialized nodes.
		if child.rootNode == nil {
			continue
		}

		// Update parent node.
		var c = b.Cursor()
		k, _, flags := c.seek([]byte(name))
		if !bytes.Equal([]byte(name), k) {
			panic(fmt.Sprintf("misplaced bucket header: %x -> %x", []byte(name), k))
		}
		if flags&common.BucketLeafFlag == 0 {
			panic(fmt.Sprintf("unexpected bucket header flag: %x", flags))
		}
		c.node().put([]byte(name), []byte(name), value, 0, common.BucketLeafFlag)
	}

	// Ignore if there's not a materialized root node.
	if b.rootNode == nil {
		return nil
	}

	// Spill nodes.
	if err := b.rootNode.spill(); err != nil {
		return err
	}
	b.rootNode = b.rootNode.root()

	// Update the root node for this bucket.
	if b.rootNode.pgid >= b.tx.meta.Pgid() {
		panic(fmt.Sprintf("pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.Pgid()))
	}
	b.SetRootPage(b.rootNode.pgid)

	return nil
}

// inlineable returns true if a bucket is small enough to be written inline
// and if it contains no subbuckets. Otherwise, returns false.
func (b *Bucket) inlineable() bool {
	var n = b.rootNode

	// Bucket must only contain a single leaf node.
	if n == nil || !n.isLeaf {
		return false
	}

	// Bucket is not inlineable if it contains subbuckets or if it goes beyond
	// our threshold for inline bucket size.
	var size = common.PageHeaderSize
	for _, inode := range n.inodes {
		size += common.LeafPageElementSize + uintptr(len(inode.Key())) + uintptr(len(inode.Value()))

		if inode.Flags()&common.BucketLeafFlag != 0 {
			return false
		} else if size > b.maxInlineBucketSize() {
			return false
		}
	}

	return true
}

// Returns the maximum total size of a bucket to make it a candidate for inlining.
func (b *Bucket) maxInlineBucketSize() uintptr {
	return uintptr(b.tx.db.pageSize / 4)
}

// write allocates and writes a bucket to a byte slice.
func (b *Bucket) write() []byte {
	// Allocate the appropriate size.
	var n = b.rootNode
	var value = make([]byte, common.BucketHeaderSize+n.size())

	// Write a bucket header.
	var bucket = (*common.InBucket)(unsafe.Pointer(&value[0]))
	*bucket = *b.InBucket

	// Convert byte slice to a fake page and write the root node.
	var p = (*common.Page)(unsafe.Pointer(&value[common.BucketHeaderSize]))
	n.write(p)

	return value
}

// rebalance attempts to balance all nodes.
func (b *Bucket) rebalance() {
	for _, n := range b.nodes {
		n.rebalance()
	}
	for _, child := range b.buckets {
		child.rebalance()
	}
}

// node creates a node from a page and associates it with a given parent.
func (b *Bucket) node(pgId common.Pgid, parent *node) *node {
	common.Assert(b.nodes != nil, "nodes map expected")

	// Retrieve node if it's already been created.
	if n := b.nodes[pgId]; n != nil {
		return n
	}

	// Otherwise create a node and cache it.
	n := &node{bucket: b, parent: parent}
	if parent == nil {
		b.rootNode = n
	} else {
		parent.children = append(parent.children, n)
	}

	// Use the inline page if this is an inline bucket.
	var p = b.page
	if p == nil {
		p = b.tx.page(pgId)
	} else {
		// if p isn't nil, then it's an inline bucket.
		// The pgId must be 0 in this case.
		common.Verify(func() {
			common.Assert(pgId == 0, "The page ID (%d) isn't 0 for an inline bucket", pgId)
		})
	}

	// Read the page into the node and cache it.
	n.read(p)
	b.nodes[pgId] = n

	// Update statistics.
	b.tx.stats.IncNodeCount(1)

	return n
}

// free recursively frees all pages in the bucket.
func (b *Bucket) free() {
	if b.RootPage() == 0 {
		return
	}

	var tx = b.tx
	b.forEachPageNode(func(p *common.Page, n *node, _ int) {
		if p != nil {
			tx.db.freelist.Free(tx.meta.Txid(), p)
		} else {
			n.free()
		}
	})
	b.SetRootPage(0)
}

// dereference removes all references to the old mmap.
func (b *Bucket) dereference() {
	if b.rootNode != nil {
		b.rootNode.root().dereference()
	}

	for _, child := range b.buckets {
		child.dereference()
	}
}

// pageNode returns the in-memory node, if it exists.
// Otherwise, returns the underlying page.
func (b *Bucket) pageNode(id common.Pgid) (*common.Page, *node) {
	// Inline buckets have a fake page embedded in their value so treat them
	// differently. We'll return the rootNode (if available) or the fake page.
	if b.RootPage() == 0 {
		if id != 0 {
			panic(fmt.Sprintf("inline bucket non-zero page access(2): %d != 0", id))
		}
		if b.rootNode != nil {
			return nil, b.rootNode
		}
		return b.page, nil
	}

	// Check the node cache for non-inline buckets.
	if b.nodes != nil {
		if n := b.nodes[id]; n != nil {
			return nil, n
		}
	}

	// Finally lookup the page from the transaction if no node is materialized.
	return b.tx.page(id), nil
}

// BucketStats records statistics about resources used by a bucket.
type BucketStats struct {
	// Page count statistics.
	BranchPageN     int // number of logical branch pages
	BranchOverflowN int // number of physical branch overflow pages
	LeafPageN       int // number of logical leaf pages
	LeafOverflowN   int // number of physical leaf overflow pages

	// Tree statistics.
	KeyN  int // number of keys/value pairs
	Depth int // number of levels in B+tree

	// Page size utilization.
	BranchAlloc int // bytes allocated for physical branch pages
	BranchInuse int // bytes actually used for branch data
	LeafAlloc   int // bytes allocated for physical leaf pages
	LeafInuse   int // bytes actually used for leaf data

	// Bucket statistics
	BucketN           int // total number of buckets including the top bucket
	InlineBucketN     int // total number on inlined buckets
	InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse)
}

func (s *BucketStats) Add(other BucketStats) {
	s.BranchPageN += other.BranchPageN
	s.BranchOverflowN += other.BranchOverflowN
	s.LeafPageN += other.LeafPageN
	s.LeafOverflowN += other.LeafOverflowN
	s.KeyN += other.KeyN
	if s.Depth < other.Depth {
		s.Depth = other.Depth
	}
	s.BranchAlloc += other.BranchAlloc
	s.BranchInuse += other.BranchInuse
	s.LeafAlloc += other.LeafAlloc
	s.LeafInuse += other.LeafInuse

	s.BucketN += other.BucketN
	s.InlineBucketN += other.InlineBucketN
	s.InlineBucketInuse += other.InlineBucketInuse
}

// cloneBytes returns a copy of a given slice.
func cloneBytes(v []byte) []byte {
	var clone = make([]byte, len(v))
	copy(clone, v)
	return clone
}

type BucketStructure struct {
	Name     string            `json:"name"`              // name of the bucket
	KeyN     int               `json:"keyN"`              // number of key/value pairs
	Children []BucketStructure `json:"buckets,omitempty"` // child buckets
}


================================================
FILE: bucket_test.go
================================================
package bbolt_test

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"testing"
	"testing/quick"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	bolt "go.etcd.io/bbolt"
	berrors "go.etcd.io/bbolt/errors"
	"go.etcd.io/bbolt/internal/btesting"
)

// Ensure that a bucket that gets a non-existent key returns nil.
func TestBucket_Get_NonExistent(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if v := b.Get([]byte("foo")); v != nil {
			t.Fatal("expected nil value")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can read a value that is not flushed yet.
func TestBucket_Get_FromNode(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) {
			t.Fatalf("unexpected value: %v", v)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket retrieved via Get() returns a nil.
func TestBucket_Get_IncompatibleValue(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
			t.Fatal(err)
		}

		if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil {
			t.Fatal("expected nil value")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a slice returned from a bucket has a capacity equal to its length.
// This also allows slices to be appended to since it will require a realloc by Go.
//
// https://github.com/boltdb/bolt/issues/544
func TestBucket_Get_Capacity(t *testing.T) {
	db := btesting.MustCreateDB(t)

	// Write key to a bucket.
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("bucket"))
		if err != nil {
			return err
		}
		return b.Put([]byte("key"), []byte("val"))
	}); err != nil {
		t.Fatal(err)
	}

	// Retrieve value and attempt to append to it.
	if err := db.Update(func(tx *bolt.Tx) error {
		k, v := tx.Bucket([]byte("bucket")).Cursor().First()

		// Verify capacity.
		if len(k) != cap(k) {
			t.Fatalf("unexpected key slice capacity: %d", cap(k))
		} else if len(v) != cap(v) {
			t.Fatalf("unexpected value slice capacity: %d", cap(v))
		}

		// Ensure slice can be appended to without a segfault.
		k = append(k, []byte("123")...)
		v = append(v, []byte("123")...)
		_, _ = k, v // to pass ineffassign

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can write a key/value.
func TestBucket_Put(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}

		v := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
		if !bytes.Equal([]byte("bar"), v) {
			t.Fatalf("unexpected value: %v", v)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can rewrite a key in the same transaction.
func TestBucket_Put_Repeat(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("baz")); err != nil {
			t.Fatal(err)
		}

		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
		if !bytes.Equal([]byte("baz"), value) {
			t.Fatalf("unexpected value: %v", value)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can write a bunch of large values.
func TestBucket_Put_Large(t *testing.T) {
	db := btesting.MustCreateDB(t)

	count, factor := 100, 200
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		for i := 1; i < count; i++ {
			if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil {
				t.Fatal(err)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		for i := 1; i < count; i++ {
			value := b.Get([]byte(strings.Repeat("0", i*factor)))
			if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) {
				t.Fatalf("unexpected value: %v", value)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a database can perform multiple large appends safely.
func TestDB_Put_VeryLarge(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	n, batchN := 400000, 200000
	ksize, vsize := 8, 500

	db := btesting.MustCreateDB(t)

	for i := 0; i < n; i += batchN {
		if err := db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
			if err != nil {
				t.Fatal(err)
			}
			for j := 0; j < batchN; j++ {
				k, v := make([]byte, ksize), make([]byte, vsize)
				binary.BigEndian.PutUint32(k, uint32(i+j))
				if err := b.Put(k, v); err != nil {
					t.Fatal(err)
				}
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}
}

// Ensure that a setting a value on a key with a bucket value returns an error.
func TestBucket_Put_IncompatibleValue(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b0, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil {
			t.Fatal(err)
		}
		if err := b0.Put([]byte("foo"), []byte("bar")); err != berrors.ErrIncompatibleValue {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a setting a value while the transaction is closed returns an error.
func TestBucket_Put_Closed(t *testing.T) {
	db := btesting.MustCreateDB(t)
	tx, err := db.Begin(true)
	if err != nil {
		t.Fatal(err)
	}

	b, err := tx.CreateBucket([]byte("widgets"))
	if err != nil {
		t.Fatal(err)
	}

	if err := tx.Rollback(); err != nil {
		t.Fatal(err)
	}

	if err := b.Put([]byte("foo"), []byte("bar")); err != berrors.ErrTxClosed {
		t.Fatalf("unexpected error: %s", err)
	}
}

// Ensure that setting a value on a read-only bucket returns an error.
func TestBucket_Put_ReadOnly(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		if err := b.Put([]byte("foo"), []byte("bar")); err != berrors.ErrTxNotWritable {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can delete an existing key.
func TestBucket_Delete(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if err := b.Delete([]byte("foo")); err != nil {
			t.Fatal(err)
		}
		if v := b.Get([]byte("foo")); v != nil {
			t.Fatalf("unexpected value: %v", v)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a large set of keys will work correctly.
func TestBucket_Delete_Large(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		for i := 0; i < 100; i++ {
			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil {
				t.Fatal(err)
			}
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		for i := 0; i < 100; i++ {
			if err := b.Delete([]byte(strconv.Itoa(i))); err != nil {
				t.Fatal(err)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		for i := 0; i < 100; i++ {
			if v := b.Get([]byte(strconv.Itoa(i))); v != nil {
				t.Fatalf("unexpected value: %v, i=%d", v, i)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Deleting a very large list of keys will cause the freelist to use overflow.
func TestBucket_Delete_FreelistOverflow(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	db := btesting.MustCreateDB(t)

	k := make([]byte, 16)
	// The bigger the pages - the more values we need to write.
	for i := uint64(0); i < 2*uint64(db.Info().PageSize); i++ {
		if err := db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("0"))
			if err != nil {
				t.Fatalf("bucket error: %s", err)
			}

			for j := uint64(0); j < 1000; j++ {
				binary.BigEndian.PutUint64(k[:8], i)
				binary.BigEndian.PutUint64(k[8:], j)
				if err := b.Put(k, nil); err != nil {
					t.Fatalf("put error: %s", err)
				}
			}

			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}

	// Delete all of them in one large transaction
	if err := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("0"))
		c := b.Cursor()
		for k, _ := c.First(); k != nil; k, _ = c.Next() {
			if err := c.Delete(); err != nil {
				t.Fatal(err)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	// Check more than an overflow's worth of pages are freed.
	stats := db.Stats()
	freePages := stats.FreePageN + stats.PendingPageN
	if freePages <= 0xFFFF {
		t.Fatalf("expected more than 0xFFFF free pages, got %v", freePages)
	}

	// Free page count should be preserved on reopen.
	db.MustClose()
	db.MustReopen()
	if reopenFreePages := db.Stats().FreePageN; freePages != reopenFreePages {
		t.Fatalf("expected %d free pages, got %+v", freePages, db.Stats())
	}
	if reopenPendingPages := db.Stats().PendingPageN; reopenPendingPages != 0 {
		t.Fatalf("expected no pending pages, got %+v", db.Stats())
	}
}

// Ensure that deleting of non-existing key is a no-op.
func TestBucket_Delete_NonExisting(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		if _, err = b.CreateBucket([]byte("nested")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		if err := b.Delete([]byte("foo")); err != nil {
			t.Fatal(err)
		}
		if b.Bucket([]byte("nested")) == nil {
			t.Fatal("nested bucket has been deleted")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that accessing and updating nested buckets is ok across transactions.
func TestBucket_Nested(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		// Create a widgets bucket.
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		// Create a widgets/foo bucket.
		_, err = b.CreateBucket([]byte("foo"))
		if err != nil {
			t.Fatal(err)
		}

		// Create a widgets/bar key.
		if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
			t.Fatal(err)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
	db.MustCheck()

	// Update widgets/bar.
	if err := db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
	db.MustCheck()

	// Cause a split.
	if err := db.Update(func(tx *bolt.Tx) error {
		var b = tx.Bucket([]byte("widgets"))
		for i := 0; i < 10000; i++ {
			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
				t.Fatal(err)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
	db.MustCheck()

	// Insert into widgets/foo/baz.
	if err := db.Update(func(tx *bolt.Tx) error {
		var b = tx.Bucket([]byte("widgets"))
		if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
	db.MustCheck()

	// Verify.
	if err := db.View(func(tx *bolt.Tx) error {
		var b = tx.Bucket([]byte("widgets"))
		if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) {
			t.Fatalf("unexpected value: %v", v)
		}
		if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) {
			t.Fatalf("unexpected value: %v", v)
		}
		for i := 0; i < 10000; i++ {
			if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) {
				t.Fatalf("unexpected value: %v", v)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a bucket using Delete() returns an error.
func TestBucket_Delete_Bucket(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if _, err := b.CreateBucket([]byte("foo")); err != nil {
			t.Fatal(err)
		}
		if err := b.Delete([]byte("foo")); err != berrors.ErrIncompatibleValue {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a key on a read-only bucket returns an error.
func TestBucket_Delete_ReadOnly(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != berrors.ErrTxNotWritable {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a deleting value while the transaction is closed returns an error.
func TestBucket_Delete_Closed(t *testing.T) {
	db := btesting.MustCreateDB(t)

	tx, err := db.Begin(true)
	if err != nil {
		t.Fatal(err)
	}

	b, err := tx.CreateBucket([]byte("widgets"))
	if err != nil {
		t.Fatal(err)
	}

	if err := tx.Rollback(); err != nil {
		t.Fatal(err)
	}
	if err := b.Delete([]byte("foo")); err != berrors.ErrTxClosed {
		t.Fatalf("unexpected error: %s", err)
	}
}

// Ensure that deleting a bucket causes nested buckets to be deleted.
func TestBucket_DeleteBucket_Nested(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		foo, err := widgets.CreateBucket([]byte("foo"))
		if err != nil {
			t.Fatal(err)
		}

		bar, err := foo.CreateBucket([]byte("bar"))
		if err != nil {
			t.Fatal(err)
		}
		if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
			t.Fatal(err)
		}
		if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
func TestBucket_DeleteBucket_Nested2(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		foo, err := widgets.CreateBucket([]byte("foo"))
		if err != nil {
			t.Fatal(err)
		}

		bar, err := foo.CreateBucket([]byte("bar"))
		if err != nil {
			t.Fatal(err)
		}

		if err := bar.Put([]byte("baz"), []byte("bat")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets := tx.Bucket([]byte("widgets"))
		if widgets == nil {
			t.Fatal("expected widgets bucket")
		}

		foo := widgets.Bucket([]byte("foo"))
		if foo == nil {
			t.Fatal("expected foo bucket")
		}

		bar := foo.Bucket([]byte("bar"))
		if bar == nil {
			t.Fatal("expected bar bucket")
		}

		if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) {
			t.Fatalf("unexpected value: %v", v)
		}
		if err := tx.DeleteBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		if tx.Bucket([]byte("widgets")) != nil {
			t.Fatal("expected bucket to be deleted")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly.
func TestBucket_DeleteBucket_Large(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		foo, err := widgets.CreateBucket([]byte("foo"))
		if err != nil {
			t.Fatal(err)
		}

		for i := 0; i < 1000; i++ {
			if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil {
				t.Fatal(err)
			}
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		if err := tx.DeleteBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a simple value retrieved via Bucket() returns a nil.
func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil {
			t.Fatal("expected nil bucket")
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that creating a bucket on an existing non-bucket key returns an error.
func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}

		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if _, err := widgets.CreateBucket([]byte("foo")); err != berrors.ErrIncompatibleValue {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that deleting a bucket on an existing non-bucket key returns an error.
func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}
		if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != berrors.ErrIncompatibleValue {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure bucket can set and update its sequence number.
func TestBucket_Sequence(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		bkt, err := tx.CreateBucket([]byte("0"))
		if err != nil {
			t.Fatal(err)
		}

		// Retrieve sequence.
		if v := bkt.Sequence(); v != 0 {
			t.Fatalf("unexpected sequence: %d", v)
		}

		// Update sequence.
		if err := bkt.SetSequence(1000); err != nil {
			t.Fatal(err)
		}

		// Read sequence again.
		if v := bkt.Sequence(); v != 1000 {
			t.Fatalf("unexpected sequence: %d", v)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}

	// Verify sequence in separate transaction.
	if err := db.View(func(tx *bolt.Tx) error {
		if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 {
			t.Fatalf("unexpected sequence: %d", v)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can return an autoincrementing sequence.
func TestBucket_NextSequence(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		widgets, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		woojits, err := tx.CreateBucket([]byte("woojits"))
		if err != nil {
			t.Fatal(err)
		}

		// Make sure sequence increments.
		if seq, err := widgets.NextSequence(); err != nil {
			t.Fatal(err)
		} else if seq != 1 {
			t.Fatalf("unexpecte sequence: %d", seq)
		}

		if seq, err := widgets.NextSequence(); err != nil {
			t.Fatal(err)
		} else if seq != 2 {
			t.Fatalf("unexpected sequence: %d", seq)
		}

		// Buckets should be separate.
		if seq, err := woojits.NextSequence(); err != nil {
			t.Fatal(err)
		} else if seq != 1 {
			t.Fatalf("unexpected sequence: %d", 1)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket will persist an autoincrementing sequence even if its
// the only thing updated on the bucket.
// https://github.com/boltdb/bolt/issues/296
func TestBucket_NextSequence_Persist(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.Update(func(tx *bolt.Tx) error {
		seq, err := tx.Bucket([]byte("widgets")).NextSequence()
		if err != nil {
			t.Fatalf("unexpected error: %s", err)
		} else if seq != 2 {
			t.Fatalf("unexpected sequence: %d", seq)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that retrieving the next sequence on a read-only bucket returns an error.
func TestBucket_NextSequence_ReadOnly(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	if err := db.View(func(tx *bolt.Tx) error {
		_, err := tx.Bucket([]byte("widgets")).NextSequence()
		if err != berrors.ErrTxNotWritable {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that retrieving the next sequence for a bucket on a closed database return an error.
func TestBucket_NextSequence_Closed(t *testing.T) {
	db := btesting.MustCreateDB(t)
	tx, err := db.Begin(true)
	if err != nil {
		t.Fatal(err)
	}
	b, err := tx.CreateBucket([]byte("widgets"))
	if err != nil {
		t.Fatal(err)
	}
	if err := tx.Rollback(); err != nil {
		t.Fatal(err)
	}
	if _, err := b.NextSequence(); err != berrors.ErrTxClosed {
		t.Fatal(err)
	}
}

// Ensure a user can loop over all key/value pairs in a bucket.
func TestBucket_ForEach(t *testing.T) {
	db := btesting.MustCreateDB(t)

	type kv struct {
		k []byte
		v []byte
	}

	expectedItems := []kv{
		{k: []byte("bar"), v: []byte("0002")},
		{k: []byte("baz"), v: []byte("0001")},
		{k: []byte("csubbucket"), v: nil},
		{k: []byte("foo"), v: []byte("0000")},
	}

	verifyReads := func(b *bolt.Bucket) {
		var items []kv
		err := b.ForEach(func(k, v []byte) error {
			items = append(items, kv{k: k, v: v})
			return nil
		})
		assert.NoErrorf(t, err, "b.ForEach failed")
		assert.Equal(t, expectedItems, items, "what we iterated (ForEach) is not what we put")
	}

	err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		require.NoError(t, err, "bucket creation failed")

		require.NoErrorf(t, b.Put([]byte("foo"), []byte("0000")), "put 'foo' failed")
		require.NoErrorf(t, b.Put([]byte("baz"), []byte("0001")), "put 'baz' failed")
		require.NoErrorf(t, b.Put([]byte("bar"), []byte("0002")), "put 'bar' failed")
		_, err = b.CreateBucket([]byte("csubbucket"))
		require.NoErrorf(t, err, "creation of subbucket failed")

		verifyReads(b)

		return nil
	})
	require.NoErrorf(t, err, "db.Update failed")
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		require.NotNil(t, b, "bucket opening failed")
		verifyReads(b)
		return nil
	})
	assert.NoErrorf(t, err, "db.View failed")
}

func TestBucket_ForEachBucket(t *testing.T) {
	db := btesting.MustCreateDB(t)

	expectedItems := [][]byte{
		[]byte("csubbucket"),
		[]byte("zsubbucket"),
	}

	verifyReads := func(b *bolt.Bucket) {
		var items [][]byte
		err := b.ForEachBucket(func(k []byte) error {
			items = append(items, k)
			return nil
		})
		assert.NoErrorf(t, err, "b.ForEach failed")
		assert.Equal(t, expectedItems, items, "what we iterated (ForEach) is not what we put")
	}

	err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		require.NoError(t, err, "bucket creation failed")

		require.NoErrorf(t, b.Put([]byte("foo"), []byte("0000")), "put 'foo' failed")
		_, err = b.CreateBucket([]byte("zsubbucket"))
		require.NoErrorf(t, err, "creation of subbucket failed")
		require.NoErrorf(t, b.Put([]byte("baz"), []byte("0001")), "put 'baz' failed")
		require.NoErrorf(t, b.Put([]byte("bar"), []byte("0002")), "put 'bar' failed")
		_, err = b.CreateBucket([]byte("csubbucket"))
		require.NoErrorf(t, err, "creation of subbucket failed")

		verifyReads(b)

		return nil
	})
	assert.NoErrorf(t, err, "db.Update failed")
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		require.NotNil(t, b, "bucket opening failed")
		verifyReads(b)
		return nil
	})
	assert.NoErrorf(t, err, "db.View failed")
}

func TestBucket_ForEachBucket_NoBuckets(t *testing.T) {
	db := btesting.MustCreateDB(t)

	verifyReads := func(b *bolt.Bucket) {
		var items [][]byte
		err := b.ForEachBucket(func(k []byte) error {
			items = append(items, k)
			return nil
		})
		assert.NoErrorf(t, err, "b.ForEach failed")
		assert.Emptyf(t, items, "what we iterated (ForEach) is not what we put")
	}

	err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		require.NoError(t, err, "bucket creation failed")

		require.NoErrorf(t, b.Put([]byte("foo"), []byte("0000")), "put 'foo' failed")
		require.NoErrorf(t, err, "creation of subbucket failed")
		require.NoErrorf(t, b.Put([]byte("baz"), []byte("0001")), "put 'baz' failed")
		require.NoErrorf(t, err, "creation of subbucket failed")

		verifyReads(b)

		return nil
	})
	require.NoErrorf(t, err, "db.Update failed")

	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("widgets"))
		require.NotNil(t, b, "bucket opening failed")
		verifyReads(b)
		return nil
	})
	assert.NoErrorf(t, err, "db.View failed")
}

// Ensure a database can stop iteration early.
func TestBucket_ForEach_ShortCircuit(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("bar"), []byte("0000")); err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("baz"), []byte("0000")); err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("0000")); err != nil {
			t.Fatal(err)
		}

		var index int
		if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
			index++
			if bytes.Equal(k, []byte("baz")) {
				return errors.New("marker")
			}
			return nil
		}); err == nil || err.Error() != "marker" {
			t.Fatalf("unexpected error: %s", err)
		}
		if index != 2 {
			t.Fatalf("unexpected index: %d", index)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that looping over a bucket on a closed database returns an error.
func TestBucket_ForEach_Closed(t *testing.T) {
	db := btesting.MustCreateDB(t)

	tx, err := db.Begin(true)
	if err != nil {
		t.Fatal(err)
	}

	b, err := tx.CreateBucket([]byte("widgets"))
	if err != nil {
		t.Fatal(err)
	}

	if err := tx.Rollback(); err != nil {
		t.Fatal(err)
	}

	if err := b.ForEach(func(k, v []byte) error { return nil }); err != berrors.ErrTxClosed {
		t.Fatalf("unexpected error: %s", err)
	}
}

// Ensure that an error is returned when inserting with an empty key.
func TestBucket_Put_EmptyKey(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte(""), []byte("bar")); err != berrors.ErrKeyRequired {
			t.Fatalf("unexpected error: %s", err)
		}
		if err := b.Put(nil, []byte("bar")); err != berrors.ErrKeyRequired {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that an error is returned when inserting with a key that's too large.
func TestBucket_Put_KeyTooLarge(t *testing.T) {
	db := btesting.MustCreateDB(t)
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put(make([]byte, 32769), []byte("bar")); err != berrors.ErrKeyTooLarge {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that an error is returned when inserting a value that's too large.
func TestBucket_Put_ValueTooLarge(t *testing.T) {
	// Skip this test on DroneCI because the machine is resource constrained.
	if os.Getenv("DRONE") == "true" {
		t.Skip("not enough RAM for test")
	}

	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != berrors.ErrValueTooLarge {
			t.Fatalf("unexpected error: %s", err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure a bucket can calculate stats.
func TestBucket_Stats(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode")
	}

	db := btesting.MustCreateDB(t)

	// Add bucket with fewer keys but one big value.
	bigKey := []byte("really-big-value")
	for i := 0; i < 500; i++ {
		if err := db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
			if err != nil {
				t.Fatal(err)
			}

			if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil {
				t.Fatal(err)
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}
	longKeyLength := 10*db.Info().PageSize + 17
	if err := db.Update(func(tx *bolt.Tx) error {
		if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", longKeyLength))); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	db.MustCheck()

	pageSize2stats := map[int]bolt.BucketStats{
		4096: {
			BranchPageN:     1,
			BranchOverflowN: 0,
			LeafPageN:       7,
			LeafOverflowN:   10,
			KeyN:            501,
			Depth:           2,
			BranchAlloc:     4096,
			BranchInuse:     149,
			LeafAlloc:       69632,
			LeafInuse: 0 +
				7*16 + // leaf page header (x LeafPageN)
				501*16 + // leaf elements
				500*3 + len(bigKey) + // leaf keys
				1*10 + 2*90 + 3*400 + longKeyLength, // leaf values: 10 * 1digit, 90*2digits, ...
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
		16384: {
			BranchPageN:     1,
			BranchOverflowN: 0,
			LeafPageN:       3,
			LeafOverflowN:   10,
			KeyN:            501,
			Depth:           2,
			BranchAlloc:     16384,
			BranchInuse:     73,
			LeafAlloc:       212992,
			LeafInuse: 0 +
				3*16 + // leaf page header (x LeafPageN)
				501*16 + // leaf elements
				500*3 + len(bigKey) + // leaf keys
				1*10 + 2*90 + 3*400 + longKeyLength, // leaf values: 10 * 1digit, 90*2digits, ...
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
		65536: {
			BranchPageN:     1,
			BranchOverflowN: 0,
			LeafPageN:       2,
			LeafOverflowN:   10,
			KeyN:            501,
			Depth:           2,
			BranchAlloc:     65536,
			BranchInuse:     54,
			LeafAlloc:       786432,
			LeafInuse: 0 +
				2*16 + // leaf page header (x LeafPageN)
				501*16 + // leaf elements
				500*3 + len(bigKey) + // leaf keys
				1*10 + 2*90 + 3*400 + longKeyLength, // leaf values: 10 * 1digit, 90*2digits, ...
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
	}

	if err := db.View(func(tx *bolt.Tx) error {
		stats := tx.Bucket([]byte("woojits")).Stats()
		t.Logf("Stats: %#v", stats)
		if expected, ok := pageSize2stats[db.Info().PageSize]; ok {
			assert.EqualValues(t, expected, stats, "stats differs from expectations")
		} else {
			t.Skipf("No expectations for page size: %d", db.Info().PageSize)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure a bucket with random insertion utilizes fill percentage correctly.
func TestBucket_Stats_RandomFill(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	} else if os.Getpagesize() != 4096 {
		t.Skip("invalid page size for test")
	}

	db := btesting.MustCreateDB(t)

	// Add a set of values in random order. It will be the same random
	// order so we can maintain consistency between test runs.
	var count int
	rand := rand.New(rand.NewSource(42))
	for _, i := range rand.Perm(1000) {
		if err := db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("woojits"))
			if err != nil {
				t.Fatal(err)
			}
			b.FillPercent = 0.9
			for _, j := range rand.Perm(100) {
				index := (j * 10000) + i
				if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil {
					t.Fatal(err)
				}
				count++
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}

	db.MustCheck()

	if err := db.View(func(tx *bolt.Tx) error {
		stats := tx.Bucket([]byte("woojits")).Stats()
		if stats.KeyN != 100000 {
			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
		}

		if stats.BranchPageN != 98 {
			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
		} else if stats.BranchOverflowN != 0 {
			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
		} else if stats.BranchInuse != 130984 {
			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
		} else if stats.BranchAlloc != 401408 {
			t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
		}

		if stats.LeafPageN != 3412 {
			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
		} else if stats.LeafOverflowN != 0 {
			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
		} else if stats.LeafInuse != 4742482 {
			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
		} else if stats.LeafAlloc != 13975552 {
			t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure a bucket can calculate stats.
func TestBucket_Stats_Small(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		// Add a bucket that fits on a single root leaf.
		b, err := tx.CreateBucket([]byte("whozawhats"))
		if err != nil {
			t.Fatal(err)
		}
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			t.Fatal(err)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}

	db.MustCheck()

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("whozawhats"))
		stats := b.Stats()
		if stats.BranchPageN != 0 {
			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
		} else if stats.BranchOverflowN != 0 {
			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
		} else if stats.LeafPageN != 0 {
			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
		} else if stats.LeafOverflowN != 0 {
			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
		} else if stats.KeyN != 1 {
			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
		} else if stats.Depth != 1 {
			t.Fatalf("unexpected Depth: %d", stats.Depth)
		} else if stats.BranchInuse != 0 {
			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
		} else if stats.LeafInuse != 0 {
			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
		}

		if db.Info().PageSize == 4096 {
			if stats.BranchAlloc != 0 {
				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
			} else if stats.LeafAlloc != 0 {
				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
			}
		}

		if stats.BucketN != 1 {
			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
		} else if stats.InlineBucketN != 1 {
			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
		} else if stats.InlineBucketInuse != 16+16+6 {
			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

func TestBucket_Stats_EmptyBucket(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		// Add a bucket that fits on a single root leaf.
		if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil {
			t.Fatal(err)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}

	db.MustCheck()

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("whozawhats"))
		stats := b.Stats()
		if stats.BranchPageN != 0 {
			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
		} else if stats.BranchOverflowN != 0 {
			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
		} else if stats.LeafPageN != 0 {
			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
		} else if stats.LeafOverflowN != 0 {
			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
		} else if stats.KeyN != 0 {
			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
		} else if stats.Depth != 1 {
			t.Fatalf("unexpected Depth: %d", stats.Depth)
		} else if stats.BranchInuse != 0 {
			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
		} else if stats.LeafInuse != 0 {
			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
		}

		if db.Info().PageSize == 4096 {
			if stats.BranchAlloc != 0 {
				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
			} else if stats.LeafAlloc != 0 {
				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
			}
		}

		if stats.BucketN != 1 {
			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
		} else if stats.InlineBucketN != 1 {
			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
		} else if stats.InlineBucketInuse != 16 {
			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure a bucket can calculate stats.
func TestBucket_Stats_Nested(t *testing.T) {
	db := btesting.MustCreateDB(t)

	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("foo"))
		if err != nil {
			t.Fatal(err)
		}
		for i := 0; i < 100; i++ {
			if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil {
				t.Fatal(err)
			}
		}

		bar, err := b.CreateBucket([]byte("bar"))
		if err != nil {
			t.Fatal(err)
		}
		for i := 0; i < 10; i++ {
			if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
				t.Fatal(err)
			}
		}

		baz, err := bar.CreateBucket([]byte("baz"))
		if err != nil {
			t.Fatal(err)
		}
		for i := 0; i < 10; i++ {
			if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
				t.Fatal(err)
			}
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}

	db.MustCheck()

	if err := db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("foo"))
		stats := b.Stats()
		if stats.BranchPageN != 0 {
			t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN)
		} else if stats.BranchOverflowN != 0 {
			t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN)
		} else if stats.LeafPageN != 2 {
			t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN)
		} else if stats.LeafOverflowN != 0 {
			t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN)
		} else if stats.KeyN != 122 {
			t.Fatalf("unexpected KeyN: %d", stats.KeyN)
		} else if stats.Depth != 3 {
			t.Fatalf("unexpected Depth: %d", stats.Depth)
		} else if stats.BranchInuse != 0 {
			t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse)
		}

		foo := 16            // foo (pghdr)
		foo += 101 * 16      // foo leaf elements
		foo += 100*2 + 100*2 // foo leaf key/values
		foo += 3 + 16        // foo -> bar key/value

		bar := 16      // bar (pghdr)
		bar += 11 * 16 // bar leaf elements
		bar += 10 + 10 // bar leaf key/values
		bar += 3 + 16  // bar -> baz key/value

		baz := 16      // baz (inline) (pghdr)
		baz += 10 * 16 // baz leaf elements
		baz += 10 + 10 // baz leaf key/values

		if stats.LeafInuse != foo+bar+baz {
			t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
		}

		if db.Info().PageSize == 4096 {
			if stats.BranchAlloc != 0 {
				t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
			} else if stats.LeafAlloc != 8192 {
				t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc)
			}
		}

		if stats.BucketN != 3 {
			t.Fatalf("unexpected BucketN: %d", stats.BucketN)
		} else if stats.InlineBucketN != 1 {
			t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN)
		} else if stats.InlineBucketInuse != baz {
			t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse)
		}

		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

func TestBucket_Inspect(t *testing.T) {
	db := btesting.MustCreateDB(t)

	expectedStructure := bolt.BucketStructure{
		Name: "root",
		KeyN: 0,
		Children: []bolt.BucketStructure{
			{
				Name: "b1",
				KeyN: 3,
				Children: []bolt.BucketStructure{
					{
						Name: "b1_1",
						KeyN: 6,
					},
					{
						Name: "b1_2",
						KeyN: 7,
					},
					{
						Name: "b1_3",
						KeyN: 8,
					},
				},
			},
			{
				Name: "b2",
				KeyN: 4,
				Children: []bolt.BucketStructure{
					{
						Name: "b2_1",
						KeyN: 10,
					},
					{
						Name: "b2_2",
						KeyN: 12,
						Children: []bolt.BucketStructure{
							{
								Name: "b2_2_1",
								KeyN: 2,
							},
							{
								Name: "b2_2_2",
								KeyN: 3,
							},
						},
					},
					{
						Name: "b2_3",
						KeyN: 11,
					},
				},
			},
		},
	}

	type bucketItem struct {
		b  *bolt.Bucket
		bs bolt.BucketStructure
	}

	t.Log("Populating the database")
	err := db.Update(func(tx *bolt.Tx) error {
		queue := []bucketItem{
			{
				b:  nil,
				bs: expectedStructure,
			},
		}

		for len(queue) > 0 {
			item := queue[0]
			queue = queue[1:]

			if item.b != nil {
				for i := 0; i < item.bs.KeyN; i++ {
					err := item.b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i)))
					require.NoError(t, err)
				}

				for _, child := range item.bs.Children {
					childBucket, err := item.b.CreateBucket([]byte(child.Name))
					require.NoError(t, err)
					queue = append(queue, bucketItem{b: childBucket, bs: child})
				}
			} else {
				for _, child := range item.bs.Children {
					childBucket, err := tx.CreateBucket([]byte(child.Name))
					require.NoError(t, err)
					queue = append(queue, bucketItem{b: childBucket, bs: child})
				}
			}
		}
		return nil
	})
	require.NoError(t, err)

	t.Log("Inspecting the database")
	_ = db.View(func(tx *bolt.Tx) error {
		actualStructure := tx.Inspect()
		assert.Equal(t, expectedStructure, actualStructure)
		return nil
	})
}

// Ensure a large bucket can calculate stats.
func TestBucket_Stats_Large(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	db := btesting.MustCreateDB(t)

	var index int
	for i := 0; i < 100; i++ {
		// Add bucket with lots of keys.
		if err := db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
			if err != nil {
				t.Fatal(err)
			}
			for i := 0; i < 1000; i++ {
				if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil {
					t.Fatal(err)
				}
				index++
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}
	}

	db.MustCheck()

	pageSize2stats := map[int]bolt.BucketStats{
		4096: {
			BranchPageN:       13,
			BranchOverflowN:   0,
			LeafPageN:         1196,
			LeafOverflowN:     0,
			KeyN:              100000,
			Depth:             3,
			BranchAlloc:       53248,
			BranchInuse:       25257,
			LeafAlloc:         4898816,
			LeafInuse:         2596916,
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
		16384: {
			BranchPageN:       1,
			BranchOverflowN:   0,
			LeafPageN:         292,
			LeafOverflowN:     0,
			KeyN:              100000,
			Depth:             2,
			BranchAlloc:       16384,
			BranchInuse:       6094,
			LeafAlloc:         4784128,
			LeafInuse:         2582452,
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
		65536: {
			BranchPageN:       1,
			BranchOverflowN:   0,
			LeafPageN:         73,
			LeafOverflowN:     0,
			KeyN:              100000,
			Depth:             2,
			BranchAlloc:       65536,
			BranchInuse:       1534,
			LeafAlloc:         4784128,
			LeafInuse:         2578948,
			BucketN:           1,
			InlineBucketN:     0,
			InlineBucketInuse: 0},
	}

	if err := db.View(func(tx *bolt.Tx) error {
		stats := tx.Bucket([]byte("widgets")).Stats()
		t.Logf("Stats: %#v", stats)
		if expected, ok := pageSize2stats[db.Info().PageSize]; ok {
			assert.EqualValues(t, expected, stats, "stats differs from expectations")
		} else {
			t.Skipf("No expectations for page size: %d", db.Info().PageSize)
		}
		return nil
	}); err != nil {
		t.Fatal(err)
	}
}

// Ensure that a bucket can write random keys and values across multiple transactions.
func TestBucket_Put_Single(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	index := 0
	if err := quick.Check(func(items testdata) bool {
		db := btesting.MustCreateDB(t)
		defer db.MustClose()

		m := make(map[string][]byte)

		if err := db.Update(func(tx *bolt.Tx) error {
			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
				t.Fatal(err)
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		for _, item := range items {
			if err := db.Update(func(tx *bolt.Tx) error {
				if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil {
					panic("put error: " + err.Error())
				}
				m[string(item.Key)] = item.Value
				return nil
			}); err != nil {
				t.Fatal(err)
			}

			// Verify all key/values so far.
			if err := db.View(func(tx *bolt.Tx) error {
				i := 0
				for k, v := range m {
					value := tx.Bucket([]byte("widgets")).Get([]byte(k))
					if !bytes.Equal(value, v) {
						t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
						db.CopyTempFile()
						t.FailNow()
					}
					i++
				}
				return nil
			}); err != nil {
				t.Fatal(err)
			}
		}

		index++
		return true
	}, qconfig()); err != nil {
		t.Error(err)
	}
}

// Ensure that a transaction can insert multiple key/value pairs at once.
func TestBucket_Put_Multiple(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	if err := quick.Check(func(items testdata) bool {
		db := btesting.MustCreateDB(t)
		defer db.MustClose()

		// Bulk insert all values.
		if err := db.Update(func(tx *bolt.Tx) error {
			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
				t.Fatal(err)
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		if err := db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte("widgets"))
			for _, item := range items {
				if err := b.Put(item.Key, item.Value); err != nil {
					t.Fatal(err)
				}
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		// Verify all items exist.
		if err := db.View(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte("widgets"))
			for _, item := range items {
				value := b.Get(item.Key)
				if !bytes.Equal(item.Value, value) {
					db.CopyTempFile()
					t.Fatalf("exp=%x; got=%x", item.Value, value)
				}
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		return true
	}, qconfig()); err != nil {
		t.Error(err)
	}
}

// Ensure that a transaction can delete all key/value pairs and return to a single leaf page.
func TestBucket_Delete_Quick(t *testing.T) {
	if testing.Short() {
		t.Skip("skipping test in short mode.")
	}

	if err := quick.Check(func(items testdata) bool {
		db := btesting.MustCreateDB(t)
		defer db.MustClose()

		// Bulk insert all values.
		if err := db.Update(func(tx *bolt.Tx) error {
			if _, err := tx.CreateBucket([]byte("widgets")); err != nil {
				t.Fatal(err)
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		if err := db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte("widgets"))
			for _, item := range items {
				if err := b.Put(item.Key, item.Value); err != nil {
					t.Fatal(err)
				}
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		// Remove items one at a time and check consistency.
		for _, item := range items {
			if err := db.Update(func(tx *bolt.Tx) error {
				return tx.Bucket([]byte("widgets")).Delete(item.Key)
			}); err != nil {
				t.Fatal(err)
			}
		}

		// Anything before our deletion index should be nil.
		if err := db.View(func(tx *bolt.Tx) error {
			if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
				t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3))
				return nil
			}); err != nil {
				t.Fatal(err)
			}
			return nil
		}); err != nil {
			t.Fatal(err)
		}

		return true
	}, qconfig()); err != nil {
		t.Error(err)
	}
}

func BenchmarkBucket_CreateBucketIfNotExists(b *testing.B) {
	db := btesting.MustCreateDB(b)
	defer db.MustClose()

	const bucketCount = 1_000_000

	err := db.Update(func(tx *bolt.Tx) error {
		for i := 0; i < bucketCount; i++ {
			bucketName := fmt.Sprintf("bucket_%d", i)
			_, berr := tx.CreateBucket([]byte(bucketName))
			require.NoError(b, berr)
		}
		return nil
	})
	require.NoError(b, err)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		err := db.Update(func(tx *bolt.Tx) error {
			_, berr := tx.CreateBucketIfNotExists([]byte("bucket_100"))
			return berr
		})
		require.NoError(b, err)
	}
}

func ExampleBucket_Put() {
	// Open the database.
	db, err := bolt.Open(tempfile(), 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(db.Path())

	// Start a write transaction.
	if err := db.Update(func(tx *bolt.Tx) error {
		// Create a bucket.
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			return err
		}

		// Set the value "bar" for the key "foo".
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			return err
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	// Read value back in a different read-only transaction.
	if err := db.View(func(tx *bolt.Tx) error {
		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
		fmt.Printf("The value of 'foo' is: %s\n", value)
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	// Close database to release file lock.
	if err := db.Close(); err != nil {
		log.Fatal(err)
	}

	// Output:
	// The value of 'foo' is: bar
}

func ExampleBucket_Delete() {
	// Open the database.
	db, err := bolt.Open(tempfile(), 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(db.Path())

	// Start a write transaction.
	if err := db.Update(func(tx *bolt.Tx) error {
		// Create a bucket.
		b, err := tx.CreateBucket([]byte("widgets"))
		if err != nil {
			return err
		}

		// Set the value "bar" for the key "foo".
		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
			return err
		}

		// Retrieve the key back from the database and verify it.
		value := b.Get([]byte("foo"))
		fmt.Printf("The value of 'foo' was: %s\n", value)

		return nil
	}); err != nil {
		log.Fatal(err)
	}

	// Delete the key in a different write transaction.
	if err := db.Update(func(tx *bolt.Tx) error {
		return tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
	}); err != nil {
		log.Fatal(err)
	}

	// Retrieve the key again.
	if err := db.View(func(tx *bolt.Tx) error {
		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
		if value == nil {
			fmt.Printf("The value of 'foo' is now: nil\n")
		}
		return nil
	}); err != nil {
		log.Fatal(err)
	}

	// Close database to release file lock.
	if err := db.Close(); err != nil {
		log.Fatal(err)
	}

	// Output:
	// The value of 'foo' was: bar
	// The value of 'foo' is now: nil
}

func ExampleBucket_ForEach() {
	// Open the database.
	db, err := bolt.Open(tempfile(), 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(db.Path())

	// Insert data into a bucket.
	if err := db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucket([]byte("animals"))
		if err != nil {
			return err
		}

		if err := b.Put([]byte("dog"), []byte("fun")); err != nil {
			return err
		}
		if err := b.Put([]byte("cat"), []byte("lame")); err != nil {
			return err
		}
		if err := b.Put([]byte("liger"), []byte("awesome")); err != nil {
			return err
		}

		// Iterate over items in sorted key order.
		if err := b.ForEach(func(k, v []byte) error {
			fmt.Printf("A %s is %s.\n", k, v)
			return nil
		}); err != nil {
			return err
		}

		return nil
	}); err != nil {
		log.Fatal(err)
	}

	// Close database to release file lock.
	if err := db.Close(); err != nil {
		log.Fatal(err)
	}

	// Output:
	// A cat is lame.
	// A dog is fun.
	// A liger is awesome.
}


================================================
FILE: cmd/bbolt/OWNERS
================================================
# See the OWNERS docs at https://go.k8s.io/owners

approvers:
  - ahrtr           # Benjamin Wang <benjamin.ahrtr@gmail.com> <benjamin.wang@broadcom.com>
  - elbehery        # Mustafa Elbehery <elbeherymustafa@gmail.com>
  - fuweid          # Wei Fu <fuweid89@gmail.com>
  - serathius       # Marek Siarkowicz <siarkowicz@google.com> <marek.siarkowicz@gmail.com>
  - ptabor          # Piotr Tabor <piotr.tabor@gmail.com>
  - spzala          # Sahdev Zala <spzala@us.ibm.com>
  - tjungblu        # Thomas Jungblut <tjungblu@redhat.com>
reviewers:
  - ivanvc          # Ivan Valdes <ivan@vald.es> 


================================================
FILE: cmd/bbolt/README.md
================================================
# Introduction to bbolt command line

`bbolt` provides a command line utility for inspecting and manipulating bbolt database files. To install bbolt command-line please refer [here](https://github.com/etcd-io/bbolt#installing)

**Note**: [etcd](https://github.com/etcd-io/etcd) uses bbolt as its backend storage engine. In this document, we take etcd as an example to demonstrate the usage of bbolt commands. Refer to [install etcd](https://etcd.io/docs/v3.5/install/) for installing etcd.

1. Start a single member etcd cluster with this command below:

    ```bash
    $etcd
    ```

    It will create a directory `default.etcd` by default under current working directory, and the directory structure will look like this:

    ```bash
    $tree default.etcd
    default.etcd
    └── member
        ├── snap
        │   └── db // this is bbolt database file
        └── wal
            └── 0000000000000000-0000000000000000.wal

    3 directories, 2 files
    ```

2. Put some dummy data using [etcdctl](https://github.com/etcd-io/etcd/tree/main/etcdctl).
3. Stop the etcd instance. Note a bbolt database file can only be opened by one read-write process, because it is exclusively locked when opened.

## Usage

- `bbolt command [arguments]`

### help

- help will print information about that command

  ```bash
  $bbolt help

  The commands are:

      version     prints the current version of bbolt
      bench       run synthetic benchmark against bbolt
      buckets     print a list of buckets
      check       verifies integrity of bbolt database
      compact     copies a bbolt database, compacting it in the process
      dump        print a hexadecimal dump of a single page
      get         print the value of a key in a bucket
      info        print basic info
      keys        print a list of keys in a bucket
      help        print this screen
      page        print one or more pages in human readable format
      pages       print list of pages with their types
      page-item   print the key and value of a page item.
      stats       iterate over all pages and generate usage stats
      surgery     perform surgery on bbolt database
  ```

- you can use `help` with any command: `bbolt [command] -h` for more information about command.

## Analyse bbolt database with bbolt command line

### version

- `version` print the current version information of bbolt command-line.
- usage:
  `bbolt version`

  Example:
  
  ```bash
  $bbolt version
  bbolt version: 1.3.7
  Go Version: go1.21.6
  Go OS/Arch: darwin/arm64
  ```

### info

- `info` print the basic information about the given Bbolt database.
- usage:
  `bbolt info [path to the bbolt database]`

    Example:

    ```bash
    $bbolt info ~/default.etcd/member/snap/db
    Page Size: 4096
    ```

  - **note**: page size is given in bytes
  - Bbolt database is using page size of 4KB

### buckets

- `buckets` print a list of buckets of Bbolt database is currently having. Find more information on buckets [here](https://github.com/etcd-io/bbolt#using-buckets)
- usage:
  `bbolt buckets [path to the bbolt database]`

    Example:

    ```bash
    $bbolt buckets ~/default.etcd/member/snap/db
    alarm
    auth
    authRoles
    authUsers
    cluster
    key
    lease
    members
    members_removed
    meta
    ```

  - It means when you start an etcd, it creates these `10` buckets using bbolt database.

### check

- `check` opens a database at a given `[PATH]` and runs an exhaustive check to verify that all pages are accessible or are marked as freed. It also verifies that no pages are double referenced.
- usage:
  `bbolt check [path to the bbolt database]`

    Example:

    ```bash
    $bbolt check ~/default.etcd/member/snap/db
    ok
    ```

  - It returns `ok` as our database file `db` is not corrupted.

### stats

- To gather essential statistics about the bbolt database: `stats` performs an extensive search of the database to track every page reference. It starts at the current meta page and recursively iterates through every accessible bucket.
- usage:
  `bbolt stats [path to the bbolt database]`

  Example:

  ```bash
  $bbolt stats ~/default.etcd/member/snap/db
  Aggregate statistics for 10 buckets

  Page count statistics
      Number of logical branch pages: 0
      Number of physical branch overflow pages: 0
      Number of logical leaf pages: 0
      Number of physical leaf overflow pages: 0
  Tree statistics
      Number of keys/value pairs: 11
      Number of levels in B+tree: 1
  Page size utilization
      Bytes allocated for physical branch pages: 0
      Bytes actually used for branch data: 0 (0%)
      Bytes allocated for physical leaf pages: 0
      Bytes actually used for leaf data: 0 (0%)
  Bucket statistics
      Total number of buckets: 10
      Total number on inlined buckets: 10 (100%)
      Bytes used for inlined buckets: 780 (0%)
  ```

### inspect
- `inspect` inspect the structure of the database.
- Usage: `bbolt inspect [path to the bbolt database]`

  Example:
```bash
$ ./bbolt inspect ~/default.etcd/member/snap/db
{
    "name": "root",
    "keyN": 0,
    "buckets": [
        {
            "name": "alarm",
            "keyN": 0
        },
        {
            "name": "auth",
            "keyN": 2
        },
        {
            "name": "authRoles",
            "keyN": 1
        },
        {
            "name": "authUsers",
            "keyN": 1
        },
        {
            "name": "cluster",
            "keyN": 1
        },
        {
            "name": "key",
            "keyN": 1285
        },
        {
            "name": "lease",
            "keyN": 2
        },
        {
            "name": "members",
            "keyN": 1
        },
        {
            "name": "members_removed",
            "keyN": 0
        },
        {
            "name": "meta",
            "keyN": 3
        }
    ]
}
```

### pages

- Pages prints a table of pages with their type (meta, leaf, branch, freelist).
- The `meta` will store the metadata information of database.
- The `leaf` and `branch` pages will show a key count in the `items` column.
- The `freelist` will show the number of free pages, which are free for writing again.
- The `overflow` column shows the number of blocks that the page spills over into.
- usage:
  `bbolt pages [path to the bbolt database]`

  Example:

  ```bash
  $bbolt pages ~/default.etcd/member/snap/db
  ID       TYPE       ITEMS  OVRFLW
  ======== ========== ====== ======
  0        meta       0
  1        meta       0
  2        free
  3        leaf       10
  4        freelist   2
  5        free
  ```

### page

- Page prints one or more pages in human readable format.
- usage:

  ```bash
  bolt page [path to the bbolt database] pageid [pageid...]
  or: bolt page --all [path to the bbolt database]

  Additional options include:

  --all
    prints all pages (only skips pages that were considered successful overflow pages)
  --format-value=auto|ascii-encoded|hex|bytes|redacted (default: auto)
    prints values (on the leaf page) using the given format
  ```

  Example:

  ```bash
  $bbolt page ~/default.etcd/member/snap/db 3
  Page ID:    3
  Page Type:  leaf
  Total Size: 4096 bytes
  Overflow pages: 0
  Item Count: 10

  "alarm": <pgid=0,seq=0>
  "auth": <pgid=0,seq=0>
  "authRoles": <pgid=0,seq=0>
  "authUsers": <pgid=0,seq=0>
  "cluster": <pgid=0,seq=0>
  "key": <pgid=0,seq=0>
  "lease": <pgid=0,seq=0>
  "members": <pgid=0,seq=0>
  "members_removed": <pgid=0,seq=0>
  "meta": <pgid=0,seq=0>
  ```

  - It prints information of page `page ID: 3`

### page-item

- page-item prints a page item's key and value.
- usage:

  ```bash
  bolt page-item [options] [path to the bbolt database] <pageId> <itemId>
  Additional options include:

      --key-only
          Print only the key
      --value-only
          Print only the value
      --format
          Output format. One of: auto|ascii-encoded|hex|bytes|redacted (default=auto)
  ```

  Example:

  ```bash
  $bbolt page-item --key-only ~/default.etcd/member/snap/db 3 7
  "members"
  ```

  - It returns the key as `--key-only` flag is passed of `pageID: 3` and `itemID: 7`

### dump

- Dump prints a hexadecimal dump of one or more given pages.
- usage:
  `bolt dump [path to the bbolt database] [pageid...]`

### keys

- Print a list of keys in the given bucket.
- usage:

  ```bash
  bolt keys [path to the bbolt database] [BucketName]

  Additional options include:
  --format
    Output format. One of: auto|ascii-encoded|hex|bytes|redacted (default=auto)
  ```

  Example 1:

  ```bash
  $bbolt keys ~/default.etcd/member/snap/db meta
  confState
  consistent_index
  term
  ```

  - It list all the keys in bucket: `meta`

  Example 2:

  ```bash
  $bbolt keys ~/default.etcd/member/snap/db members
  8e9e05c52164694d
  ```

  - It list all the keys in `members` bucket which is a `memberId` of etcd cluster member.
  - In this case we are running a single member etcd cluster, hence only `one memberId` is present. If we would have run a `3` member etcd cluster then it will return a `3 memberId` as `3 cluster members` would have been present in `members` bucket.

### get

- Print the value of the given key in the given bucket.
- usage:
  
  ```bash
  bolt get [path to the bbolt database] [BucketName] [Key]

  Additional options include:
  --format
    Output format. One of: auto|ascii-encoded|hex|bytes|redacted (default=auto)
  --parse-format
    Input format (of key). One of: ascii-encoded|hex (default=ascii-encoded)"
  ```

  Example 1:

  ```bash
  $bbolt get --format=hex ~/default.etcd/member/snap/db meta term
  0000000000000004
  ```

  - It returns the value present in bucket: `meta` for key: `term` in hexadecimal format.

  Example 2:

  ```bash
  $bbolt get ~/default.etcd/member/snap/db members 8e9e05c52164694d
  {"id":10276657743932975437,"peerURLs":["http://localhost:2380"],"name":"default","clientURLs":["http://localhost:2379"]}
  ```

  - It returns the value present in bucket: `members` for key: `8e9e05c52164694d`.

### compact

- Compact opens a database at given `[Source Path]` and walks it recursively, copying keys as they are found from all buckets, to a newly created database at `[Destination Path]`. The original database is left untouched.
- usage:

  ```bash
  bbolt compact [options] -o [Destination Path] [Source Path]

  Additional options include:

  -tx-max-size NUM
    Specifies the maximum size of individual transactions.
    Defaults to 64KB
  ```

  Example:

  ```bash
  $bbolt compact -o ~/db.compact ~/default.etcd/member/snap/db
  16805888 -> 32768 bytes (gain=512.88x)
  ```

  - It will create a compacted database file: `db.compact` at given path.

### bench

- run synthetic benchmark against bbolt database.
- usage:

    ```bash
    Usage:
    -batch-size int

    -blockprofile string

    -count int
            (default 1000)
    -cpuprofile string

    -fill-percent float
            (default 0.5)
    -key-size int
            (default 8)
    -memprofile string

    -no-sync

    -path string

    -profile-mode string
            (default "rw")
    -read-mode string
            (default "seq")
    -value-size int
            (default 32)
    -work

    -write-mode string
            (default "seq")
    ```

    Example:

    ```bash
    $bbolt bench ~/default.etcd/member/snap/db -batch-size 400 -key-size 16
    # Write	68.523572ms	(68.523µs/op)	(14593 op/sec)
    # Read	1.000015152s	(11ns/op)	(90909090 op/sec)
    ```

  - It runs a benchmark with batch size of `400` and with key size of `16` while for others parameters default value is taken.

### surgery

- `surgery` perform surgery on bbolt database for repair and recovery operations.
- usage:
  `bbolt surgery <subcommand> [arguments]`

  The surgery subcommands are:
  - `revert-meta-page` - revert to previous transaction state
  - `copy-page` - copy page from source to destination
  - `clear-page` - clear all elements from a page
  - `clear-page-elements` - clear specific elements from a page
  - `freelist` - freelist related surgery commands
  - `meta` - meta page related surgery commands

#### surgery revert-meta-page

- `surgery revert-meta-page` reverts to the previous transaction state by replacing the active meta page with the inactive one.
- usage:

  ```bash
  bbolt surgery revert-meta-page [path to the bbolt database] --output [output-file]
  ```

  Example:

  ```bash
  $bbolt surgery revert-meta-page ~/default.etcd/member/snap/db --output reverted.db
  The meta page is reverted.
  ```

  - This is particularly useful when the most recent transaction has corrupted the database and you need to roll back to the previous consistent state.

#### surgery copy-page

- `surgery copy-page` copies content from one page to another.
- usage:

  ```bash
  bbolt surgery copy-page [path to the bbolt database] --output [output-file] --from-page [source-id] --to-page [destination-id]
  ```

  Example:

  ```bash
  $bbolt surgery copy-page ~/default.etcd/member/snap/db --output copied.db --from-page 3 --to-page 2
  The page 3 was successfully copied to page 2
  WARNING: the free list might have changed.
  Please consider executing `./bbolt surgery freelist abandon ...`
  ```

  - This command is useful for recovering data from damaged pages or creating page backups.

#### surgery clear-page

- `surgery clear-page` removes all elements from a branch or leaf page.
- usage:

  ```bash
  bbolt surgery clear-page [path to the bbolt database] --output [output-file] --pageId [page-id]
  ```

  Example:

  ```bash
  $bbolt surgery clear-page ~/default.etcd/member/snap/db --output cleared.db --pageId 3
  The page (3) was cleared
  WARNING: The clearing has abandoned some pages that are not yet referenced from free list.
  Please consider executing `./bbolt surgery freelist abandon ...`
  ```

  - The pageId must be at least 2 (meta pages 0 and 1 cannot be cleared).

#### surgery clear-page-elements

- `surgery clear-page-elements` removes specific elements from a branch or leaf page by index range.
- usage:

  ```bash
  bbolt surgery clear-page-elements [path to the bbolt database] --output [output-file] --pageId [page-id] --from-index [start] --to-index [end]
  ```

  Example:

  ```bash
  $bbolt surgery clear-page-elements ~/default.etcd/member/snap/db --output partial.db --pageId 3 --from-index 1 --to-index 4
  All elements in [1, 4) in page 3 were cleared
  WARNING: The clearing has abandoned some pages that are not yet referenced from free list.
  Please consider executing `./bbolt surgery freelist abandon ...`
  ```

  - Use `--to-index -1` to clear elements to the end of the page.

#### surgery freelist

- `surgery freelist` provides commands for managing the database's free page list.
- usage:

  ```bash
  bbolt surgery freelist <subcommand> [arguments]
  ```

  The freelist subcommands are:

  - `abandon` - remove freelist references from meta pages
  - `rebuild` - rebuild the freelist by scanning the database

##### surgery freelist abandon

- `surgery freelist abandon` removes freelist references from both meta pages, forcing Bbolt to reconstruct the freelist when the database is next opened.
- usage:

  ```bash
  bbolt surgery freelist abandon [path to the bbolt database] --output [output-file]
  ```

  Example:

  ```bash
  $bbolt surgery freelist abandon ~/default.etcd/member/snap/db --output abandoned.db
  The freelist was abandoned in both meta pages.
  It may cause some delay on next startup because bbolt needs to scan the whole db to reconstruct the free list.
  ```

  - This sets the freelist page ID to a special value indicating the freelist is not present.

##### surgery freelist rebuild

- `surgery freelist rebuild` rebuilds the freelist in a database where the freelist has been abandoned.
- usage:

  ```bash
  bbolt surgery freelist rebuild [path to the bbolt database] --output [output-file]
  ```

  Example:

  ```bash
  $bbolt surgery freelist rebuild ~/default.etcd/member/snap/db --output rebuilt.db
  The freelist was successfully rebuilt.
  ```

  - This command opens the database and lets Bbolt automatically reconstruct and sync the freelist.

#### surgery meta

- `surgery meta` provides commands for working with database metadata pages.
- usage:

  ```bash
  bbolt surgery meta <subcommand> [arguments]
  ```
  
  The meta subcommands are:
  - `validate` - validate integrity of meta pages
  - `update` - update specific fields in meta pages

##### surgery meta validate

- `surgery meta validate` validates the integrity of both meta pages in the database.
- usage:

  ```bash
  bbolt surgery meta validate [path to the bbolt database]
  ```

  Example:

  ```bash
  $bbolt surgery meta validate ~/default.etcd/member/snap/db
  The meta page 0 is valid!
  The meta page 1 is valid!
  ```

  - It checks magic number values, version compatibility, checksum integrity, and general metadata validity for both meta pages (0 and 1).

##### surgery meta update

- `surgery meta update` updates specific fields in a meta page for manual repair of corrupted metadata.
- usage:

  ```bash
  bbolt surgery meta update [path to the bbolt database] --output [output-file] --meta-page [0|1] --fields [field:value,...]
  ```

  Supported fields:
  - `pageSize` - Size of database pages
  - `root` - Root bucket page ID
  - `freelist` - Freelist page ID
  - `pgid` - Next page ID to allocate

  Example:

  ```bash
  $bbolt surgery meta update ~/default.etcd/member/snap/db --output fixed.db --meta-page 0 --fields root:16,freelist:8
  The meta page 0 has been updated!
  ```

  - It updates the specified meta page and automatically updates magic number, version, flags, and checksum to ensure consistency.


================================================
FILE: cmd/bbolt/command/command_bench.go
================================================
package command

import (
	"encoding/binary"
	"fmt"
	"io"
	"math"
	"math/rand"
	"os"
	"runtime"
	"runtime/pprof"
	"sync/atomic"
	"testing"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	bolt "go.etcd.io/bbolt"
	"go.etcd.io/bbolt/internal/common"
)

var benchBucketName = []byte("bench")

type benchOptions struct {
	profileMode     string
	writeMode       string
	readMode        string
	iterations      int64
	batchSize       int64
	keySize         int
	valueSize       int
	cpuProfile      string
	memProfile      string
	blockProfile    string
	fillPercent     float64
	noSync          bool
	work            bool
	path            string
	goBenchOutput   bool
	pageSize        int
	initialMmapSize int
	deleteFraction  float64 // Fraction of keys of last tx to delete during writes. works only with "seq-del" write mode.
}

func (o *benchOptions) AddFlags(fs *pflag.FlagSet) {
	fs.StringVar(&o.profileMode, "profile-mode", "rw", "")
	fs.StringVar(&o.writeMode, "write-mode", "seq", "")
	fs.StringVar(&o.readMode, "read-mode", "seq", "")
	fs.Int64Var(&o.iterations, "count", 1000, "")
	fs.Int64Var(&o.batchSize, "batch-size", 0, "")
	fs.IntVar(&o.keySize, "key-size", 8, "")
	fs.IntVar(&o.valueSize, "value-size", 32, "")
	fs.StringVar(&o.cpuProfile, "cpuprofile", "", "")
	fs.StringVar(&o.memProfile, "memprofile", "", "")
	fs.StringVar(&o.blockProfile, "blockprofile", "", "")
	fs.Float64Var(&o.fillPercent, "fill-percent", bolt.DefaultFillPercent, "")
	fs.BoolVar(&o.noSync, "no-sync", false, "")
	fs.BoolVar(&o.work, "work", false, "")
	fs.StringVar(&o.path, "path", "", "")
	fs.BoolVar(&o.goBenchOutput, "gobench-output", false, "")
	fs.IntVar(&o.pageSize, "page-size", common.DefaultPageSize, "Set page size in bytes.")
	fs.IntVar(&o.initialMmapSize, "initial-mmap-size", 0, "Set initial mmap size in bytes for database file.")
}

// Returns an error if `bench` options are not valid.
func (o *benchOptions) Validate() error {
	// Require that batch size can be evenly divided by the iteration count if set.
	if o.batchSize > 0 && o.iterations%o.batchSize != 0 {
		return ErrBatchNonDivisibleBatchSize
	}

	switch o.writeMode {
	case "seq", "rnd", "seq-nest", "rnd-nest":
	default:
		return ErrBatchInvalidWriteMode
	}

	// Generate temp path if one is not passed in.
	if o.path == "" {
		f, err := os.CreateTemp("", "bolt-bench-")
		if err != nil {
			return fmt.Errorf("temp file: %s", err)
		}
		f.Close()
		os.Remove(f.Name())
		o.path = f.Name()
	}

	return nil
}

// Sets the `bench` option values that are dependent on other options.
func (o *benchOptions) SetOptionValues() error {
	// Generate temp path if one is not passed in.
	if o.path == "" {
		f, err := os.CreateTemp("", "bolt-bench-")
		if err != nil {
			return fmt.Errorf("error creating temp file: %s", err)
		}
		f.Close()
		os.Remove(f.Name())
		o.path = f.Name()
	}

	// Set batch size to iteration size if not set.
	if o.batchSize == 0 {
		o.batchSize = o.iterations
	}

	return nil
}

func newBenchCommand() *cobra.Command {
	var o benchOptions

	benchCmd := &cobra.Command{
		Use:   "bench",
		Short: "run synthetic benchmark against bbolt",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := o.Validate(); err != nil {
				return err
			}
			if err := o.SetOptionValues(); err != nil {
				return err
			}
			return benchFunc(cmd, &o)
		},
	}

	o.AddFlags(benchCmd.Flags())

	return benchCmd
}

func benchFunc(cmd *cobra.Command, options *benchOptions) error {
	// Remove path if "-work" is not set. Otherwise keep path.
	if options.work {
		fmt.Fprintf(cmd.ErrOrStderr(), "work: %s\n", options.path)
	} else {
		defer os.Remove(options.path)
	}

	// Create database.
	dbOptions := *bolt.DefaultOptions
	dbOptions.PageSize = options.pageSize
	dbOptions.InitialMmapSize = options.initialMmapSize
	db, err := bolt.Open(options.path, 0600, &dbOptions)
	if err != nil {
		return err
	}
	db.NoSync = options.noSync
	defer db.Close()

	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	var writeResults benchResults

	fmt.Fprintf(cmd.ErrOrStderr(), "starting write benchmark.\n")
	keys, err := runWrites(cmd, db, options, &writeResults, r)
	if err != nil {
		return fmt.Errorf("write: %v", err)
	}

	if keys != nil {
		r.Shuffle(len(keys), func(i, j int) {
			keys[i], keys[j] = keys[j], keys[i]
		})
	}

	var readResults benchResults
	fmt.Fprintf(cmd.ErrOrStderr(), "starting read benchmark.\n")
	// Read from the database.
	if err := runReads(cmd, db, options, &readResults, keys); err != nil {
		return fmt.Errorf("bench: read: %s", err)
	}

	// Print results.
	if options.goBenchOutput {
		// below replicates the output of testing.B benchmarks, e.g. for external tooling
		benchWriteName := "BenchmarkWrite"
		benchReadName := "BenchmarkRead"
		maxLen := max(len(benchReadName), len(benchWriteName))
		printGoBenchResult(cmd.OutOrStdout(), writeResults, maxLen, benchWriteName)
		printGoBenchResult(cmd.OutOrStdout(), readResults, maxLen, benchReadName)
	} else {
		fmt.Fprintf(cmd.OutOrStdout(), "# Write\t%v(ops)\t%v\t(%v/op)\t(%v op/sec)\n", writeResults.getCompletedOps(), writeResults.getDuration(), writeResults.opDuration(), writeResults.opsPerSecond())
		fmt.Fprintf(cmd.OutOrStdout(), "# Read\t%v(ops)\t%v\t(%v/op)\t(%v op/sec)\n", readResults.getCompletedOps(), readResults.getDuration(), readResults.opDuration(), readResults.opsPerSecond())
	}
	fmt.Fprintln(cmd.OutOrStdout(), "")

	return nil
}

func runWrites(cmd *cobra.Command, db *bolt.DB, options *benchOptions, results *benchResults, r *rand.Rand) ([]nestedKey, error) {
	// Start profiling for writes.
	if options.profileMode == "rw" || options.profileMode == "w" {
		startProfiling(cmd, options)
	}

	finishChan := make(chan interface{})
	go checkProgress(results, finishChan, cmd.ErrOrStderr())
	defer close(finishChan)

	t := time.Now()

	var keys []nestedKey
	var err error
	switch options.writeMode {
	case "seq":
		keys, err = runWritesSequential(cmd, db, options, results)
	case "rnd":
		keys, err = runWritesRandom(cmd, db, options, results, r)
	case "seq-nest":
		keys, err = runWritesSequentialNested(cmd, db, options, results)
	case "rnd-nest":
		keys, err = runWritesRandomNested(cmd, db, options, results, r)
	case "seq-del":
		options.deleteFraction = 0.1
		keys, err = runWritesSequentialAndDelete(cmd, db, options, results)
	default:
		return nil, fmt.Errorf("invalid write mode: %s", options.writeMode)
	}

	// Save time to write.
	results.setDuration(time.Since(t))

	// Stop profiling for writes only.
	if options.profileMode == "w" {
		stopProfiling(cmd)
	}

	return keys, err
}

func runWritesSequential(cmd *cobra.Command, db *bolt.DB, options *benchOptions, results *benchResults) ([]nestedKey, error) {
	var i = uint32(0)
	return runWritesWithSource(cmd, db, options, results, func() uint32 { i++; return i })
}

func runWritesSequentialAndDelete(cmd *cobra.Command, db *bolt.DB, options *benchOptions, results 
Download .txt
gitextract_ich4mfot/

├── .gitattributes
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── benchmark-pr.yaml
│       ├── benchmark-releases.yaml
│       ├── benchmark-template.yaml
│       ├── cross-arch-template.yaml
│       ├── cross-arch-test.yaml
│       ├── failpoint_test.yaml
│       ├── gh-workflow-approve.yaml
│       ├── robustness_nightly.yaml
│       ├── robustness_template.yaml
│       ├── robustness_test.yaml
│       ├── stale.yaml
│       ├── tests-template.yml
│       ├── tests_amd64.yaml
│       ├── tests_arm64.yaml
│       └── tests_windows.yml
├── .gitignore
├── .go-version
├── .golangci.yaml
├── CHANGELOG/
│   ├── CHANGELOG-1.3.md
│   ├── CHANGELOG-1.4.md
│   └── CHANGELOG-1.5.md
├── LICENSE
├── Makefile
├── OWNERS
├── README.md
├── allocate_test.go
├── bolt_aix.go
├── bolt_android.go
├── bolt_linux.go
├── bolt_openbsd.go
├── bolt_solaris.go
├── bolt_unix.go
├── bolt_windows.go
├── boltsync_unix.go
├── bucket.go
├── bucket_test.go
├── cmd/
│   └── bbolt/
│       ├── OWNERS
│       ├── README.md
│       ├── command/
│       │   ├── command_bench.go
│       │   ├── command_bench_test.go
│       │   ├── command_buckets.go
│       │   ├── command_buckets_test.go
│       │   ├── command_check.go
│       │   ├── command_check_test.go
│       │   ├── command_compact.go
│       │   ├── command_compact_test.go
│       │   ├── command_dump.go
│       │   ├── command_dump_test.go
│       │   ├── command_get.go
│       │   ├── command_get_test.go
│       │   ├── command_info.go
│       │   ├── command_info_test.go
│       │   ├── command_inspect.go
│       │   ├── command_inspect_test.go
│       │   ├── command_keys.go
│       │   ├── command_keys_test.go
│       │   ├── command_page.go
│       │   ├── command_page_item.go
│       │   ├── command_page_item_test.go
│       │   ├── command_page_test.go
│       │   ├── command_pages.go
│       │   ├── command_pages_test.go
│       │   ├── command_root.go
│       │   ├── command_stats.go
│       │   ├── command_stats_test.go
│       │   ├── command_surgery.go
│       │   ├── command_surgery_freelist.go
│       │   ├── command_surgery_freelist_test.go
│       │   ├── command_surgery_meta.go
│       │   ├── command_surgery_meta_test.go
│       │   ├── command_surgery_test.go
│       │   ├── command_version.go
│       │   ├── errors.go
│       │   ├── utils.go
│       │   └── utils_test.go
│       └── main.go
├── code-of-conduct.md
├── compact.go
├── concurrent_test.go
├── cursor.go
├── cursor_test.go
├── db.go
├── db_test.go
├── db_whitebox_test.go
├── doc.go
├── errors/
│   └── errors.go
├── errors.go
├── go.mod
├── go.sum
├── internal/
│   ├── btesting/
│   │   └── btesting.go
│   ├── common/
│   │   ├── bolt_386.go
│   │   ├── bolt_amd64.go
│   │   ├── bolt_arm.go
│   │   ├── bolt_arm64.go
│   │   ├── bolt_loong64.go
│   │   ├── bolt_mips64x.go
│   │   ├── bolt_mipsx.go
│   │   ├── bolt_ppc.go
│   │   ├── bolt_ppc64.go
│   │   ├── bolt_ppc64le.go
│   │   ├── bolt_riscv64.go
│   │   ├── bolt_s390x.go
│   │   ├── bucket.go
│   │   ├── inode.go
│   │   ├── meta.go
│   │   ├── page.go
│   │   ├── page_test.go
│   │   ├── types.go
│   │   ├── unsafe.go
│   │   ├── utils.go
│   │   └── verify.go
│   ├── freelist/
│   │   ├── array.go
│   │   ├── array_test.go
│   │   ├── freelist.go
│   │   ├── freelist_test.go
│   │   ├── hashmap.go
│   │   ├── hashmap_test.go
│   │   └── shared.go
│   ├── guts_cli/
│   │   └── guts_cli.go
│   ├── surgeon/
│   │   ├── surgeon.go
│   │   ├── surgeon_test.go
│   │   ├── xray.go
│   │   └── xray_test.go
│   └── tests/
│       └── tx_check_test.go
├── logger.go
├── manydbs_test.go
├── mlock_unix.go
├── mlock_windows.go
├── movebucket_test.go
├── node.go
├── node_test.go
├── quick_test.go
├── scripts/
│   ├── compare_benchmarks.sh
│   ├── fix.sh
│   └── release.sh
├── simulation_no_freelist_sync_test.go
├── simulation_test.go
├── tests/
│   ├── dmflakey/
│   │   ├── dmflakey.go
│   │   ├── dmflakey_test.go
│   │   ├── dmsetup.go
│   │   └── loopback.go
│   ├── failpoint/
│   │   └── db_failpoint_test.go
│   ├── robustness/
│   │   ├── main_test.go
│   │   └── powerfailure_test.go
│   └── utils/
│       └── helpers.go
├── tx.go
├── tx_check.go
├── tx_check_test.go
├── tx_stats_test.go
├── tx_test.go
├── unix_test.go
├── utils_test.go
└── version/
    └── version.go
Download .txt
SYMBOL INDEX (1168 symbols across 115 files)

FILE: allocate_test.go
  function TestTx_allocatePageStats (line 10) | func TestTx_allocatePageStats(t *testing.T) {

FILE: bolt_aix.go
  function flock (line 17) | func flock(db *DB, exclusive bool, timeout time.Duration) error {
  function funlock (line 50) | func funlock(db *DB) error {
  function mmap (line 60) | func mmap(db *DB, sz int) error {
  function munmap (line 80) | func munmap(db *DB) error {

FILE: bolt_android.go
  function flock (line 15) | func flock(db *DB, exclusive bool, timeout time.Duration) error {
  function funlock (line 48) | func funlock(db *DB) error {
  function mmap (line 58) | func mmap(db *DB, sz int) error {
  function munmap (line 80) | func munmap(db *DB) error {

FILE: bolt_linux.go
  function fdatasync (line 8) | func fdatasync(db *DB) error {

FILE: bolt_openbsd.go
  function msync (line 7) | func msync(db *DB) error {
  function fdatasync (line 11) | func fdatasync(db *DB) error {

FILE: bolt_solaris.go
  function flock (line 15) | func flock(db *DB, exclusive bool, timeout time.Duration) error {
  function funlock (line 48) | func funlock(db *DB) error {
  function mmap (line 58) | func mmap(db *DB, sz int) error {
  function munmap (line 78) | func munmap(db *DB) error {

FILE: bolt_unix.go
  function flock (line 18) | func flock(db *DB, exclusive bool, timeout time.Duration) error {
  function funlock (line 50) | func funlock(db *DB) error {
  function mmap (line 55) | func mmap(db *DB, sz int) error {
  function munmap (line 77) | func munmap(db *DB) error {

FILE: bolt_windows.go
  function fdatasync (line 17) | func fdatasync(db *DB) error {
  function flock (line 22) | func flock(db *DB, exclusive bool, timeout time.Duration) error {
  function funlock (line 57) | func funlock(db *DB) error {
  function mmap (line 67) | func mmap(db *DB, sz int) error {
  function munmap (line 120) | func munmap(db *DB) error {

FILE: boltsync_unix.go
  function fdatasync (line 6) | func fdatasync(db *DB) error {

FILE: bucket.go
  constant MaxKeySize (line 14) | MaxKeySize = 32768
  constant MaxValueSize (line 17) | MaxValueSize = (1 << 31) - 2
  constant minFillPercent (line 21) | minFillPercent = 0.1
  constant maxFillPercent (line 22) | maxFillPercent = 1.0
  constant DefaultFillPercent (line 27) | DefaultFillPercent = 0.5
  type Bucket (line 30) | type Bucket struct
    method Tx (line 57) | func (b *Bucket) Tx() *Tx {
    method Root (line 62) | func (b *Bucket) Root() common.Pgid {
    method Writable (line 67) | func (b *Bucket) Writable() bool {
    method Cursor (line 74) | func (b *Bucket) Cursor() *Cursor {
    method Bucket (line 88) | func (b *Bucket) Bucket(name []byte) *Bucket {
    method openBucket (line 115) | func (b *Bucket) openBucket(value []byte) *Bucket {
    method CreateBucket (line 148) | func (b *Bucket) CreateBucket(key []byte) (rb *Bucket, err error) {
    method CreateBucketIfNotExists (line 205) | func (b *Bucket) CreateBucketIfNotExists(key []byte) (rb *Bucket, err ...
    method DeleteBucket (line 273) | func (b *Bucket) DeleteBucket(key []byte) (err error) {
    method MoveBucket (line 336) | func (b *Bucket) MoveBucket(key []byte, dstBucket *Bucket) (err error) {
    method Inspect (line 406) | func (b *Bucket) Inspect() BucketStructure {
    method recursivelyInspect (line 410) | func (b *Bucket) recursivelyInspect(name []byte) BucketStructure {
    method Get (line 433) | func (b *Bucket) Get(key []byte) []byte {
    method Put (line 452) | func (b *Bucket) Put(key []byte, value []byte) (err error) {
    method Delete (line 499) | func (b *Bucket) Delete(key []byte) (err error) {
    method Sequence (line 538) | func (b *Bucket) Sequence() uint64 {
    method SetSequence (line 543) | func (b *Bucket) SetSequence(v uint64) error {
    method NextSequence (line 562) | func (b *Bucket) NextSequence() (uint64, error) {
    method ForEach (line 585) | func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
    method ForEachBucket (line 598) | func (b *Bucket) ForEachBucket(fn func(k []byte) error) error {
    method Stats (line 614) | func (b *Bucket) Stats() BucketStats {
    method forEachPage (line 696) | func (b *Bucket) forEachPage(fn func(*common.Page, int, []common.Pgid)) {
    method forEachPageNode (line 709) | func (b *Bucket) forEachPageNode(fn func(*common.Page, *node, int)) {
    method _forEachPageNode (line 718) | func (b *Bucket) _forEachPageNode(pgId common.Pgid, depth int, fn func...
    method spill (line 742) | func (b *Bucket) spill() error {
    method inlineable (line 802) | func (b *Bucket) inlineable() bool {
    method maxInlineBucketSize (line 827) | func (b *Bucket) maxInlineBucketSize() uintptr {
    method write (line 832) | func (b *Bucket) write() []byte {
    method rebalance (line 849) | func (b *Bucket) rebalance() {
    method node (line 859) | func (b *Bucket) node(pgId common.Pgid, parent *node) *node {
    method free (line 898) | func (b *Bucket) free() {
    method dereference (line 915) | func (b *Bucket) dereference() {
    method pageNode (line 927) | func (b *Bucket) pageNode(id common.Pgid) (*common.Page, *node) {
  function newBucket (line 47) | func newBucket(tx *Tx) Bucket {
  type BucketStats (line 952) | type BucketStats struct
    method Add (line 975) | func (s *BucketStats) Add(other BucketStats) {
  function cloneBytes (line 995) | func cloneBytes(v []byte) []byte {
  type BucketStructure (line 1001) | type BucketStructure struct

FILE: bucket_test.go
  function TestBucket_Get_NonExistent (line 25) | func TestBucket_Get_NonExistent(t *testing.T) {
  function TestBucket_Get_FromNode (line 43) | func TestBucket_Get_FromNode(t *testing.T) {
  function TestBucket_Get_IncompatibleValue (line 64) | func TestBucket_Get_IncompatibleValue(t *testing.T) {
  function TestBucket_Get_Capacity (line 89) | func TestBucket_Get_Capacity(t *testing.T) {
  function TestBucket_Put (line 126) | func TestBucket_Put(t *testing.T) {
  function TestBucket_Put_Repeat (line 148) | func TestBucket_Put_Repeat(t *testing.T) {
  function TestBucket_Put_Large (line 173) | func TestBucket_Put_Large(t *testing.T) {
  function TestDB_Put_VeryLarge (line 207) | func TestDB_Put_VeryLarge(t *testing.T) {
  function TestBucket_Put_IncompatibleValue (line 238) | func TestBucket_Put_IncompatibleValue(t *testing.T) {
  function TestBucket_Put_Closed (line 260) | func TestBucket_Put_Closed(t *testing.T) {
  function TestBucket_Put_ReadOnly (line 282) | func TestBucket_Put_ReadOnly(t *testing.T) {
  function TestBucket_Delete (line 306) | func TestBucket_Delete(t *testing.T) {
  function TestBucket_Delete_Large (line 330) | func TestBucket_Delete_Large(t *testing.T) {
  function TestBucket_Delete_FreelistOverflow (line 376) | func TestBucket_Delete_FreelistOverflow(t *testing.T) {
  function TestBucket_Delete_NonExisting (line 439) | func TestBucket_Delete_NonExisting(t *testing.T) {
  function TestBucket_Nested (line 471) | func TestBucket_Nested(t *testing.T) {
  function TestBucket_Delete_Bucket (line 557) | func TestBucket_Delete_Bucket(t *testing.T) {
  function TestBucket_Delete_ReadOnly (line 577) | func TestBucket_Delete_ReadOnly(t *testing.T) {
  function TestBucket_Delete_Closed (line 600) | func TestBucket_Delete_Closed(t *testing.T) {
  function TestBucket_DeleteBucket_Nested (line 622) | func TestBucket_DeleteBucket_Nested(t *testing.T) {
  function TestBucket_DeleteBucket_Nested2 (line 653) | func TestBucket_DeleteBucket_Nested2(t *testing.T) {
  function TestBucket_DeleteBucket_Large (line 719) | func TestBucket_DeleteBucket_Large(t *testing.T) {
  function TestBucket_Bucket_IncompatibleValue (line 754) | func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
  function TestBucket_CreateBucket_IncompatibleValue (line 776) | func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
  function TestBucket_DeleteBucket_IncompatibleValue (line 797) | func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
  function TestBucket_Sequence (line 818) | func TestBucket_Sequence(t *testing.T) {
  function TestBucket_NextSequence (line 859) | func TestBucket_NextSequence(t *testing.T) {
  function TestBucket_NextSequence_Persist (line 901) | func TestBucket_NextSequence_Persist(t *testing.T) {
  function TestBucket_NextSequence_ReadOnly (line 936) | func TestBucket_NextSequence_ReadOnly(t *testing.T) {
  function TestBucket_NextSequence_Closed (line 960) | func TestBucket_NextSequence_Closed(t *testing.T) {
  function TestBucket_ForEach (line 979) | func TestBucket_ForEach(t *testing.T) {
  function TestBucket_ForEachBucket (line 1028) | func TestBucket_ForEachBucket(t *testing.T) {
  function TestBucket_ForEachBucket_NoBuckets (line 1072) | func TestBucket_ForEachBucket_NoBuckets(t *testing.T) {
  function TestBucket_ForEach_ShortCircuit (line 1110) | func TestBucket_ForEach_ShortCircuit(t *testing.T) {
  function TestBucket_ForEach_Closed (line 1148) | func TestBucket_ForEach_Closed(t *testing.T) {
  function TestBucket_Put_EmptyKey (line 1171) | func TestBucket_Put_EmptyKey(t *testing.T) {
  function TestBucket_Put_KeyTooLarge (line 1192) | func TestBucket_Put_KeyTooLarge(t *testing.T) {
  function TestBucket_Put_ValueTooLarge (line 1209) | func TestBucket_Put_ValueTooLarge(t *testing.T) {
  function TestBucket_Stats (line 1232) | func TestBucket_Stats(t *testing.T) {
  function TestBucket_Stats_RandomFill (line 1340) | func TestBucket_Stats_RandomFill(t *testing.T) {
  function TestBucket_Stats_Small (line 1407) | func TestBucket_Stats_Small(t *testing.T) {
  function TestBucket_Stats_EmptyBucket (line 1470) | func TestBucket_Stats_EmptyBucket(t *testing.T) {
  function TestBucket_Stats_Nested (line 1529) | func TestBucket_Stats_Nested(t *testing.T) {
  function TestBucket_Inspect (line 1629) | func TestBucket_Inspect(t *testing.T) {
  function TestBucket_Stats_Large (line 1735) | func TestBucket_Stats_Large(t *testing.T) {
  function TestBucket_Put_Single (line 1824) | func TestBucket_Put_Single(t *testing.T) {
  function TestBucket_Put_Multiple (line 1882) | func TestBucket_Put_Multiple(t *testing.T) {
  function TestBucket_Delete_Quick (line 1935) | func TestBucket_Delete_Quick(t *testing.T) {
  function BenchmarkBucket_CreateBucketIfNotExists (line 1994) | func BenchmarkBucket_CreateBucketIfNotExists(b *testing.B) {
  function ExampleBucket_Put (line 2022) | func ExampleBucket_Put() {
  function ExampleBucket_Delete (line 2065) | func ExampleBucket_Delete() {
  function ExampleBucket_ForEach (line 2123) | func ExampleBucket_ForEach() {

FILE: cmd/bbolt/command/command_bench.go
  type benchOptions (line 25) | type benchOptions struct
    method AddFlags (line 46) | func (o *benchOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 67) | func (o *benchOptions) Validate() error {
    method SetOptionValues (line 94) | func (o *benchOptions) SetOptionValues() error {
  function newBenchCommand (line 114) | func newBenchCommand() *cobra.Command {
  function benchFunc (line 136) | func benchFunc(cmd *cobra.Command, options *benchOptions) error {
  function runWrites (line 195) | func runWrites(cmd *cobra.Command, db *bolt.DB, options *benchOptions, r...
  function runWritesSequential (line 236) | func runWritesSequential(cmd *cobra.Command, db *bolt.DB, options *bench...
  function runWritesSequentialAndDelete (line 241) | func runWritesSequentialAndDelete(cmd *cobra.Command, db *bolt.DB, optio...
  function runWritesRandom (line 246) | func runWritesRandom(cmd *cobra.Command, db *bolt.DB, options *benchOpti...
  function runWritesSequentialNested (line 250) | func runWritesSequentialNested(cmd *cobra.Command, db *bolt.DB, options ...
  function runWritesRandomNested (line 255) | func runWritesRandomNested(cmd *cobra.Command, db *bolt.DB, options *ben...
  function runWritesWithSource (line 259) | func runWritesWithSource(cmd *cobra.Command, db *bolt.DB, options *bench...
  function runWritesDeletesWithSource (line 297) | func runWritesDeletesWithSource(cmd *cobra.Command, db *bolt.DB, options...
  function runWritesNestedWithSource (line 344) | func runWritesNestedWithSource(cmd *cobra.Command, db *bolt.DB, options ...
  function runReads (line 396) | func runReads(cmd *cobra.Command, db *bolt.DB, options *benchOptions, re...
  type nestedKey (line 439) | type nestedKey struct
  function runReadsSequential (line 441) | func runReadsSequential(cmd *cobra.Command, db *bolt.DB, options *benchO...
  function runReadsRandom (line 479) | func runReadsRandom(cmd *cobra.Command, db *bolt.DB, options *benchOptio...
  function runReadsSequentialNested (line 518) | func runReadsSequentialNested(cmd *cobra.Command, db *bolt.DB, options *...
  function runReadsRandomNested (line 555) | func runReadsRandomNested(cmd *cobra.Command, db *bolt.DB, options *benc...
  function checkProgress (line 596) | func checkProgress(results *benchResults, finishChan chan interface{}, s...
  function startProfiling (line 615) | func startProfiling(cmd *cobra.Command, options *benchOptions) {
  function stopProfiling (line 653) | func stopProfiling(cmd *cobra.Command) {
  type benchResults (line 681) | type benchResults struct
    method addCompletedOps (line 686) | func (r *benchResults) addCompletedOps(amount int64) {
    method getCompletedOps (line 690) | func (r *benchResults) getCompletedOps() int64 {
    method setDuration (line 694) | func (r *benchResults) setDuration(dur time.Duration) {
    method getDuration (line 698) | func (r *benchResults) getDuration() time.Duration {
    method opDuration (line 703) | func (r *benchResults) opDuration() time.Duration {
    method opsPerSecond (line 711) | func (r *benchResults) opsPerSecond() int {
  function printGoBenchResult (line 719) | func printGoBenchResult(w io.Writer, r benchResults, maxLen int, benchNa...

FILE: cmd/bbolt/command/command_bench_test.go
  type safeWriter (line 15) | type safeWriter struct
    method Write (line 20) | func (w *safeWriter) Write(p []byte) (n int, err error) {
    method String (line 26) | func (w *safeWriter) String() string {
  function newSafeWriter (line 32) | func newSafeWriter() *safeWriter {
  function TestBenchCommand_Run (line 37) | func TestBenchCommand_Run(t *testing.T) {

FILE: cmd/bbolt/command/command_buckets.go
  function newBucketsCommand (line 11) | func newBucketsCommand() *cobra.Command {
  function bucketsFunc (line 24) | func bucketsFunc(cmd *cobra.Command, dbPath string) error {

FILE: cmd/bbolt/command/command_buckets_test.go
  function TestBucketsCommand_Run (line 16) | func TestBucketsCommand_Run(t *testing.T) {

FILE: cmd/bbolt/command/command_check.go
  type checkOptions (line 13) | type checkOptions struct
    method AddFlags (line 17) | func (o *checkOptions) AddFlags(fs *pflag.FlagSet) {
  function newCheckCommand (line 21) | func newCheckCommand() *cobra.Command {
  function checkFunc (line 36) | func checkFunc(cmd *cobra.Command, dbPath string, cfg checkOptions) error {

FILE: cmd/bbolt/command/command_check_test.go
  function TestCheckCommand_Run (line 15) | func TestCheckCommand_Run(t *testing.T) {

FILE: cmd/bbolt/command/command_compact.go
  type compactOptions (line 14) | type compactOptions struct
    method AddFlags (line 41) | func (o *compactOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 48) | func (o *compactOptions) Validate(srcPath string) (err error) {
    method Run (line 56) | func (o *compactOptions) Run(cmd *cobra.Command, srcPath string) (err ...
  function newCompactCommand (line 20) | func newCompactCommand() *cobra.Command {

FILE: cmd/bbolt/command/command_compact_test.go
  function TestCompactCommand_Run (line 18) | func TestCompactCommand_Run(t *testing.T) {
  function TestCompactCommand_NoArgs (line 95) | func TestCompactCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_dump.go
  function newDumpCommand (line 14) | func newDumpCommand() *cobra.Command {
  function dumpFunc (line 34) | func dumpFunc(cmd *cobra.Command, dbPath string, pageIDs []uint64) (err ...
  function dumpPage (line 68) | func dumpPage(w io.Writer, r io.ReaderAt, pageID uint64, pageSize uint64...

FILE: cmd/bbolt/command/command_dump_test.go
  function TestDumpCommand_Run (line 17) | func TestDumpCommand_Run(t *testing.T) {
  function TestDumpCommand_NoArgs (line 38) | func TestDumpCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_get.go
  type getOptions (line 13) | type getOptions struct
    method AddFlags (line 56) | func (o *getOptions) AddFlags(fs *pflag.FlagSet) {
  function newGetCommand (line 18) | func newGetCommand() *cobra.Command {
  function getFunc (line 62) | func getFunc(cmd *cobra.Command, path string, buckets []string, key []by...

FILE: cmd/bbolt/command/command_get_test.go
  function TestGetCommand_Run (line 18) | func TestGetCommand_Run(t *testing.T) {
  function TestGetCommand_NoArgs (line 80) | func TestGetCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_info.go
  function newInfoCommand (line 11) | func newInfoCommand() *cobra.Command {
  function infoFunc (line 24) | func infoFunc(cmd *cobra.Command, dbPath string) error {

FILE: cmd/bbolt/command/command_info_test.go
  function TestInfoCommand_Run (line 16) | func TestInfoCommand_Run(t *testing.T) {
  function TestInfoCommand_NoArgs (line 36) | func TestInfoCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_inspect.go
  function newInspectCommand (line 13) | func newInspectCommand() *cobra.Command {
  function inspectFunc (line 26) | func inspectFunc(srcDBPath string) error {

FILE: cmd/bbolt/command/command_inspect_test.go
  function TestInspect (line 13) | func TestInspect(t *testing.T) {

FILE: cmd/bbolt/command/command_keys.go
  type keysOptions (line 10) | type keysOptions struct
    method AddFlags (line 14) | func (o *keysOptions) AddFlags(fs *pflag.FlagSet) {
  function newKeysCommand (line 18) | func newKeysCommand() *cobra.Command {
  function keysFunc (line 34) | func keysFunc(cmd *cobra.Command, cfg keysOptions, dbPath string, bucket...

FILE: cmd/bbolt/command/command_keys_test.go
  function TestKeysCommand_Run (line 18) | func TestKeysCommand_Run(t *testing.T) {
  function TestKeyCommand_NoArgs (line 88) | func TestKeyCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_page.go
  type getPageOptions (line 14) | type getPageOptions struct
    method AddFlags (line 42) | func (o *getPageOptions) AddFlags(fs *pflag.FlagSet) {
  function newPageCommand (line 19) | func newPageCommand() *cobra.Command {
  function pageFunc (line 47) | func pageFunc(cmd *cobra.Command, cfg getPageOptions, dbPath string, pag...
  function printPages (line 65) | func printPages(cmd *cobra.Command, pageIDs []uint64, path string, forma...
  function printPage (line 80) | func printPage(cmd *cobra.Command, path string, pageID uint64, formatVal...
  function printAllPages (line 117) | func printAllPages(cmd *cobra.Command, path string, formatValue string) {
  function pagePrintMeta (line 140) | func pagePrintMeta(w io.Writer, buf []byte) error {
  function pagePrintLeaf (line 147) | func pagePrintLeaf(w io.Writer, buf []byte, formatValue string) error {
  function pagePrintBranch (line 186) | func pagePrintBranch(w io.Writer, buf []byte) error {
  function pagePrintFreelist (line 212) | func pagePrintFreelist(w io.Writer, buf []byte) error {

FILE: cmd/bbolt/command/command_page_item.go
  type pageItemOptions (line 16) | type pageItemOptions struct
    method AddFlags (line 46) | func (o *pageItemOptions) AddFlags(fs *pflag.FlagSet) {
  function newPageItemCommand (line 22) | func newPageItemCommand() *cobra.Command {
  function pageItemFunc (line 52) | func pageItemFunc(cmd *cobra.Command, cfg pageItemOptions, dbPath string...
  function pageItemPrintLeafItemKey (line 83) | func pageItemPrintLeafItemKey(w io.Writer, pageBytes []byte, index uint1...
  function pageItemPrintLeafItemValue (line 92) | func pageItemPrintLeafItemValue(w io.Writer, pageBytes []byte, index uin...
  function pageItemLeafPageElement (line 100) | func pageItemLeafPageElement(pageBytes []byte, index uint16) ([]byte, []...

FILE: cmd/bbolt/command/command_page_item_test.go
  function TestPageItemCommand_Run (line 19) | func TestPageItemCommand_Run(t *testing.T) {
  function TestPageItemCommand_NoArgs (line 100) | func TestPageItemCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_page_test.go
  function TestPageCommand_Run (line 15) | func TestPageCommand_Run(t *testing.T) {
  function TestPageCommand_ExclusiveArgs (line 46) | func TestPageCommand_ExclusiveArgs(t *testing.T) {
  function TestPageCommand_NoArgs (line 93) | func TestPageCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_pages.go
  type PageError (line 13) | type PageError struct
    method Error (line 18) | func (e *PageError) Error() string {
  function newPagesCommand (line 22) | func newPagesCommand() *cobra.Command {
  function pagesFunc (line 44) | func pagesFunc(cmd *cobra.Command, dbPath string) error {

FILE: cmd/bbolt/command/command_pages_test.go
  function TestPagesCommand_Run (line 18) | func TestPagesCommand_Run(t *testing.T) {
  function TestPagesCommand_NoArgs (line 55) | func TestPagesCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_root.go
  constant cliName (line 8) | cliName        = "bbolt"
  constant cliDescription (line 9) | cliDescription = "A simple command line tool for inspecting bbolt databa...
  function NewRootCommand (line 12) | func NewRootCommand() *cobra.Command {

FILE: cmd/bbolt/command/command_stats.go
  function newStatsCommand (line 13) | func newStatsCommand() *cobra.Command {
  function statsFunc (line 63) | func statsFunc(cmd *cobra.Command, dbPath string, prefix string) error {

FILE: cmd/bbolt/command/command_stats_test.go
  function TestStatsCommand_Run_EmptyDatabase (line 19) | func TestStatsCommand_Run_EmptyDatabase(t *testing.T) {
  function TestStatsCommand_Run (line 66) | func TestStatsCommand_Run(t *testing.T) {
  function TestStatsCommand_NoArgs (line 148) | func TestStatsCommand_NoArgs(t *testing.T) {

FILE: cmd/bbolt/command/command_surgery.go
  function newSurgeryCommand (line 16) | func newSurgeryCommand() *cobra.Command {
  type surgeryBaseOptions (line 32) | type surgeryBaseOptions struct
    method AddFlags (line 36) | func (o *surgeryBaseOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 41) | func (o *surgeryBaseOptions) Validate() error {
  function newSurgeryRevertMetaPageCommand (line 48) | func newSurgeryRevertMetaPageCommand() *cobra.Command {
  function surgeryRevertMetaPageFunc (line 65) | func surgeryRevertMetaPageFunc(srcDBPath string, cfg surgeryBaseOptions)...
  type surgeryCopyPageOptions (line 83) | type surgeryCopyPageOptions struct
    method AddFlags (line 89) | func (o *surgeryCopyPageOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 97) | func (o *surgeryCopyPageOptions) Validate() error {
  function newSurgeryCopyPageCommand (line 107) | func newSurgeryCopyPageCommand() *cobra.Command {
  function surgeryCopyPageFunc (line 124) | func surgeryCopyPageFunc(srcDBPath string, cfg surgeryCopyPageOptions) e...
  type surgeryClearPageOptions (line 150) | type surgeryClearPageOptions struct
    method AddFlags (line 155) | func (o *surgeryClearPageOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 161) | func (o *surgeryClearPageOptions) Validate() error {
  function newSurgeryClearPageCommand (line 171) | func newSurgeryClearPageCommand() *cobra.Command {
  function surgeryClearPageFunc (line 188) | func surgeryClearPageFunc(srcDBPath string, cfg surgeryClearPageOptions)...
  type surgeryClearPageElementsOptions (line 211) | type surgeryClearPageElementsOptions struct
    method AddFlags (line 218) | func (o *surgeryClearPageElementsOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 228) | func (o *surgeryClearPageElementsOptions) Validate() error {
  function newSurgeryClearPageElementsCommand (line 238) | func newSurgeryClearPageElementsCommand() *cobra.Command {
  function surgeryClearPageElementFunc (line 255) | func surgeryClearPageElementFunc(srcDBPath string, cfg surgeryClearPageE...
  function readMetaPage (line 278) | func readMetaPage(path string) (*common.Meta, error) {

FILE: cmd/bbolt/command/command_surgery_freelist.go
  function newSurgeryFreelistCommand (line 14) | func newSurgeryFreelistCommand() *cobra.Command {
  function newSurgeryFreelistAbandonCommand (line 26) | func newSurgeryFreelistAbandonCommand() *cobra.Command {
  function surgeryFreelistAbandonFunc (line 44) | func surgeryFreelistAbandonFunc(srcDBPath string, cfg surgeryBaseOptions...
  function newSurgeryFreelistRebuildCommand (line 61) | func newSurgeryFreelistRebuildCommand() *cobra.Command {
  function surgeryFreelistRebuildFunc (line 79) | func surgeryFreelistRebuildFunc(srcDBPath string, cfg surgeryBaseOptions...

FILE: cmd/bbolt/command/command_surgery_freelist_test.go
  function TestSurgery_Freelist_Abandon (line 16) | func TestSurgery_Freelist_Abandon(t *testing.T) {
  function TestSurgery_Freelist_Rebuild (line 38) | func TestSurgery_Freelist_Rebuild(t *testing.T) {

FILE: cmd/bbolt/command/command_surgery_meta.go
  constant metaFieldPageSize (line 17) | metaFieldPageSize = "pageSize"
  constant metaFieldRoot (line 18) | metaFieldRoot     = "root"
  constant metaFieldFreelist (line 19) | metaFieldFreelist = "freelist"
  constant metaFieldPgid (line 20) | metaFieldPgid     = "pgid"
  function newSurgeryMetaCommand (line 23) | func newSurgeryMetaCommand() *cobra.Command {
  function newSurgeryMetaValidateCommand (line 35) | func newSurgeryMetaValidateCommand() *cobra.Command {
  function surgeryMetaValidateFunc (line 47) | func surgeryMetaValidateFunc(srcDBPath string) error {
  type surgeryMetaUpdateOptions (line 71) | type surgeryMetaUpdateOptions struct
    method AddFlags (line 87) | func (o *surgeryMetaUpdateOptions) AddFlags(fs *pflag.FlagSet) {
    method Validate (line 93) | func (o *surgeryMetaUpdateOptions) Validate() error {
  function newSurgeryMetaUpdateCommand (line 120) | func newSurgeryMetaUpdateCommand() *cobra.Command {
  function surgeryMetaUpdateFunc (line 137) | func surgeryMetaUpdateFunc(srcDBPath string, cfg surgeryMetaUpdateOption...
  function parseFields (line 184) | func parseFields(fields []string) map[string]uint64 {
  function updateMetaField (line 194) | func updateMetaField(m *common.Meta, fields map[string]uint64) bool {
  function ReadMetaPageAt (line 233) | func ReadMetaPageAt(dbPath string, metaPageId uint32, pageSize uint32) (...
  function writeMetaPageAt (line 258) | func writeMetaPageAt(dbPath string, buf []byte, metaPageId uint32, pageS...

FILE: cmd/bbolt/command/command_surgery_meta_test.go
  function TestSurgery_Meta_Validate (line 17) | func TestSurgery_Meta_Validate(t *testing.T) {
  function TestSurgery_Meta_Update (line 37) | func TestSurgery_Meta_Update(t *testing.T) {

FILE: cmd/bbolt/command/command_surgery_test.go
  function TestSurgery_RevertMetaPage (line 19) | func TestSurgery_RevertMetaPage(t *testing.T) {
  function TestSurgery_CopyPage (line 64) | func TestSurgery_CopyPage(t *testing.T) {
  function TestSurgery_ClearPage (line 104) | func TestSurgery_ClearPage(t *testing.T) {
  function TestSurgery_ClearPageElements_Without_Overflow (line 139) | func TestSurgery_ClearPageElements_Without_Overflow(t *testing.T) {
  function testSurgeryClearPageElementsWithoutOverflow (line 268) | func testSurgeryClearPageElementsWithoutOverflow(t *testing.T, startIdx,...
  function compareDataAfterClearingElement (line 348) | func compareDataAfterClearingElement(t *testing.T, srcPath, dstPath stri...
  function TestSurgery_ClearPageElements_With_Overflow (line 381) | func TestSurgery_ClearPageElements_With_Overflow(t *testing.T) {
  function testSurgeryClearPageElementsWithOverflow (line 487) | func testSurgeryClearPageElementsWithOverflow(t *testing.T, startIdx, en...
  function TestSurgeryRequiredFlags (line 554) | func TestSurgeryRequiredFlags(t *testing.T) {

FILE: cmd/bbolt/command/command_version.go
  function newVersionCommand (line 12) | func newVersionCommand() *cobra.Command {

FILE: cmd/bbolt/command/utils.go
  function checkSourceDBPath (line 17) | func checkSourceDBPath(srcPath string) (os.FileInfo, error) {
  constant FORMAT_MODES (line 27) | FORMAT_MODES = "auto|ascii-encoded|hex|bytes|redacted"
  function formatBytes (line 31) | func formatBytes(b []byte, format string) (string, error) {
  function parseBytes (line 50) | func parseBytes(str string, format string) ([]byte, error) {
  function writelnBytes (line 63) | func writelnBytes(w io.Writer, b []byte, format string) error {
  function isPrintable (line 73) | func isPrintable(s string) bool {
  function bytesToAsciiOrHex (line 85) | func bytesToAsciiOrHex(b []byte) string {
  function stringToPage (line 94) | func stringToPage(str string) (uint64, error) {
  function stringToPages (line 99) | func stringToPages(strs []string) ([]uint64, error) {
  type cmdKvStringer (line 114) | type cmdKvStringer struct
    method KeyToString (line 116) | func (cmdKvStringer) KeyToString(key []byte) string {
    method ValueToString (line 120) | func (cmdKvStringer) ValueToString(value []byte) string {
  function CmdKvStringer (line 124) | func CmdKvStringer() bolt.KVStringer {
  function findLastBucket (line 128) | func findLastBucket(tx *bolt.Tx, bucketNames []string) (*bolt.Bucket, er...

FILE: cmd/bbolt/command/utils_test.go
  function loadMetaPage (line 23) | func loadMetaPage(t *testing.T, dbPath string, pageID uint64) *common.Me...
  function readMetaPage (line 29) | func readMetaPage(t *testing.T, path string) *common.Meta {
  function readPage (line 37) | func readPage(t *testing.T, path string, pageId int, pageSize int) []byte {
  function pageDataWithoutPageId (line 54) | func pageDataWithoutPageId(buf []byte) []byte {
  type ConcurrentBuffer (line 58) | type ConcurrentBuffer struct
    method Read (line 63) | func (b *ConcurrentBuffer) Read(p []byte) (n int, err error) {
    method Write (line 70) | func (b *ConcurrentBuffer) Write(p []byte) (n int, err error) {
    method String (line 77) | func (b *ConcurrentBuffer) String() string {
  function fillBucket (line 84) | func fillBucket(b *bolt.Bucket, prefix []byte) error {
  function chkdb (line 116) | func chkdb(path string) ([]byte, error) {
  function walkBucket (line 134) | func walkBucket(parent *bolt.Bucket, k []byte, v []byte, w io.Writer) er...
  function dbData (line 151) | func dbData(t *testing.T, filePath string) []byte {
  function requireDBNoChange (line 157) | func requireDBNoChange(t *testing.T, oldData []byte, filePath string) {
  function convertInt64IntoBytes (line 165) | func convertInt64IntoBytes(num int64) []byte {
  function convertInt64KeysIntoHexString (line 171) | func convertInt64KeysIntoHexString(nums ...int64) string {

FILE: cmd/bbolt/main.go
  function main (line 10) | func main() {

FILE: compact.go
  function Compact (line 8) | func Compact(dst, src *DB, txMaxSize int64) error {
  type walkFunc (line 88) | type walkFunc
  function walk (line 91) | func walk(db *DB, walkFn walkFunc) error {
  function walkBucket (line 99) | func walkBucket(b *Bucket, keypath [][]byte, k, v []byte, seq uint64, fn...

FILE: concurrent_test.go
  constant bucketPrefix (line 27) | bucketPrefix = "bucket"
  constant keyPrefix (line 28) | keyPrefix    = "key"
  constant noopTxKey (line 29) | noopTxKey    = "%magic-no-op-key%"
  constant testConcurrentCaseDuration (line 33) | testConcurrentCaseDuration    = "TEST_CONCURRENT_CASE_DURATION"
  constant defaultConcurrentTestDuration (line 34) | defaultConcurrentTestDuration = 30 * time.Second
  type duration (line 37) | type duration struct
  type bytesRange (line 42) | type bytesRange struct
  type operationChance (line 47) | type operationChance struct
  type concurrentConfig (line 52) | type concurrentConfig struct
  function TestConcurrentGenericReadAndWrite (line 70) | func TestConcurrentGenericReadAndWrite(t *testing.T) {
  function concurrentTestDuration (line 145) | func concurrentTestDuration(t *testing.T) time.Duration {
  function concurrentReadAndWrite (line 162) | func concurrentReadAndWrite(t *testing.T,
  function mustCreateDB (line 218) | func mustCreateDB(t *testing.T, o *bolt.Options) *bolt.DB {
  function mustReOpenDB (line 224) | func mustReOpenDB(t *testing.T, db *bolt.DB, o *bolt.Options) *bolt.DB {
  function mustOpenDB (line 234) | func mustOpenDB(t *testing.T, dbPath string, o *bolt.Options) *bolt.DB {
  function checkConsistency (line 253) | func checkConsistency(t *testing.T, db *bolt.DB) error {
  function runWorkers (line 274) | func runWorkers(t *testing.T,
  function runWorker (line 321) | func runWorker(t *testing.T, w *worker, errCh chan error) (historyRecord...
  type worker (line 334) | type worker struct
    method name (line 346) | func (w *worker) name() string {
    method run (line 350) | func (w *worker) run() (historyRecords, error) {
    method pickBucket (line 395) | func (w *worker) pickBucket() []byte {
    method pickKey (line 404) | func (w *worker) pickKey() []byte {
    method pickOperation (line 409) | func (w *worker) pickOperation() OperationType {
  function bucketName (line 399) | func bucketName(index int) []byte {
  function executeOperation (line 424) | func executeOperation(op OperationType, tx *bolt.Tx, bucket []byte, key ...
  function executeRead (line 437) | func executeRead(tx *bolt.Tx, bucket []byte, key []byte, readInterval du...
  function executeWrite (line 465) | func executeWrite(tx *bolt.Tx, bucket []byte, key []byte, writeBytes byt...
  function executeDelete (line 504) | func executeDelete(tx *bolt.Tx, bucket []byte, key []byte) (historyRecor...
  function randomDurationInRange (line 522) | func randomDurationInRange(min, max time.Duration) time.Duration {
  function randomIntInRange (line 528) | func randomIntInRange(min, max int) int {
  function formatBytes (line 532) | func formatBytes(val []byte) string {
  function saveDataIfFailed (line 546) | func saveDataIfFailed(t *testing.T, db *bolt.DB, rs historyRecords, forc...
  function backupDB (line 559) | func backupDB(t *testing.T, srcPath string, dstPath string) {
  function copyFile (line 567) | func copyFile(srcPath, dstPath string) error {
  function persistHistoryRecords (line 611) | func persistHistoryRecords(t *testing.T, rs historyRecords, path string) {
  function testResultsDirectory (line 624) | func testResultsDirectory(t *testing.T) string {
  type OperationType (line 651) | type OperationType
  constant Read (line 654) | Read   OperationType = "read"
  constant Write (line 655) | Write  OperationType = "write"
  constant Delete (line 656) | Delete OperationType = "delete"
  type historyRecord (line 659) | type historyRecord struct
  type historyRecords (line 667) | type historyRecords
    method Len (line 669) | func (rs historyRecords) Len() int {
    method Less (line 673) | func (rs historyRecords) Less(i, j int) bool {
    method Swap (line 689) | func (rs historyRecords) Swap(i, j int) {
  function validateIncrementalTxid (line 693) | func validateIncrementalTxid(rs historyRecords) error {
  function validateSequential (line 706) | func validateSequential(rs historyRecords) error {
  function TestConcurrentRepeatableRead (line 764) | func TestConcurrentRepeatableRead(t *testing.T) {
  function executeLongRunningRead (line 930) | func executeLongRunningRead(t *testing.T, name string, db *bolt.DB, buck...

FILE: cursor.go
  type Cursor (line 22) | type Cursor struct
    method Bucket (line 28) | func (c *Cursor) Bucket() *Bucket {
    method First (line 35) | func (c *Cursor) First() (key []byte, value []byte) {
    method first (line 44) | func (c *Cursor) first() (key []byte, value []byte, flags uint32) {
    method Last (line 66) | func (c *Cursor) Last() (key []byte, value []byte) {
    method Next (line 95) | func (c *Cursor) Next() (key []byte, value []byte) {
    method Prev (line 107) | func (c *Cursor) Prev() (key []byte, value []byte) {
    method Seek (line 120) | func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) {
    method Delete (line 140) | func (c *Cursor) Delete() error {
    method seek (line 159) | func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags ui...
    method goToFirstElementOnTheStack (line 169) | func (c *Cursor) goToFirstElementOnTheStack() {
    method last (line 190) | func (c *Cursor) last() {
    method next (line 215) | func (c *Cursor) next() (key []byte, value []byte, flags uint32) {
    method prev (line 251) | func (c *Cursor) prev() (key []byte, value []byte, flags uint32) {
    method search (line 283) | func (c *Cursor) search(key []byte, pgId common.Pgid) {
    method searchNode (line 304) | func (c *Cursor) searchNode(key []byte, n *node) {
    method searchPage (line 324) | func (c *Cursor) searchPage(key []byte, p *common.Page) {
    method nsearch (line 348) | func (c *Cursor) nsearch(key []byte) {
    method keyValue (line 370) | func (c *Cursor) keyValue() ([]byte, []byte, uint32) {
    method node (line 390) | func (c *Cursor) node() *node {
  type elemRef (line 412) | type elemRef struct
    method isLeaf (line 419) | func (r *elemRef) isLeaf() bool {
    method count (line 427) | func (r *elemRef) count() int {

FILE: cursor_test.go
  function TestCursor_RepeatOperations (line 25) | func TestCursor_RepeatOperations(t *testing.T) {
  function testCursorRepeatOperations_PrepareData (line 61) | func testCursorRepeatOperations_PrepareData(t *testing.T, b *bolt.Bucket) {
  function testRepeatCursorOperations_NextPrevNext (line 70) | func testRepeatCursorOperations_NextPrevNext(t *testing.T, b *bolt.Bucke...
  function testRepeatCursorOperations_PrevNextPrev (line 111) | func testRepeatCursorOperations_PrevNextPrev(t *testing.T, b *bolt.Bucke...
  function TestCursor_Bucket (line 153) | func TestCursor_Bucket(t *testing.T) {
  function TestCursor_Seek (line 170) | func TestCursor_Seek(t *testing.T) {
  function TestCursor_Delete (line 239) | func TestCursor_Delete(t *testing.T) {
  function TestCursor_Seek_Large (line 301) | func TestCursor_Seek_Large(t *testing.T) {
  function TestCursor_EmptyBucket (line 364) | func TestCursor_EmptyBucket(t *testing.T) {
  function TestCursor_EmptyBucketReverse (line 388) | func TestCursor_EmptyBucketReverse(t *testing.T) {
  function TestCursor_Iterate_Leaf (line 412) | func TestCursor_Iterate_Leaf(t *testing.T) {
  function TestCursor_LeafRootReverse (line 482) | func TestCursor_LeafRootReverse(t *testing.T) {
  function TestCursor_Restart (line 545) | func TestCursor_Restart(t *testing.T) {
  function TestCursor_First_EmptyPages (line 590) | func TestCursor_First_EmptyPages(t *testing.T) {
  function TestCursor_Last_EmptyPages (line 636) | func TestCursor_Last_EmptyPages(t *testing.T) {
  function TestCursor_QuickCheck (line 682) | func TestCursor_QuickCheck(t *testing.T) {
  function TestCursor_QuickCheck_Reverse (line 740) | func TestCursor_QuickCheck_Reverse(t *testing.T) {
  function TestCursor_QuickCheck_BucketsOnly (line 797) | func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
  function TestCursor_QuickCheck_BucketsOnly_Reverse (line 838) | func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
  function ExampleCursor (line 878) | func ExampleCursor() {
  function ExampleCursor_reverse (line 932) | func ExampleCursor_reverse() {

FILE: db.go
  constant flockRetryTimeout (line 19) | flockRetryTimeout = 50 * time.Millisecond
  type FreelistType (line 22) | type FreelistType
  constant FreelistArrayType (line 30) | FreelistArrayType = FreelistType("array")
  constant FreelistMapType (line 32) | FreelistMapType = FreelistType("hashmap")
  type DB (line 38) | type DB struct
    method Path (line 160) | func (db *DB) Path() string {
    method GoString (line 165) | func (db *DB) GoString() string {
    method String (line 170) | func (db *DB) String() string {
    method getPageSize (line 332) | func (db *DB) getPageSize() (int, error) {
    method getPageSizeFromFirstMeta (line 369) | func (db *DB) getPageSizeFromFirstMeta() (int, bool, error) {
    method getPageSizeFromSecondMeta (line 382) | func (db *DB) getPageSizeFromSecondMeta() (int, bool, error) {
    method loadFreelist (line 422) | func (db *DB) loadFreelist() {
    method hasSyncedFreelist (line 438) | func (db *DB) hasSyncedFreelist() bool {
    method fileSize (line 442) | func (db *DB) fileSize() (int, error) {
    method mmap (line 456) | func (db *DB) mmap(minsz int) (err error) {
    method invalidate (line 538) | func (db *DB) invalidate() {
    method munmap (line 548) | func (db *DB) munmap() error {
    method mmapSize (line 564) | func (db *DB) mmapSize(size int) (int, error) {
    method munlock (line 598) | func (db *DB) munlock(fileSize int) error {
    method mlock (line 608) | func (db *DB) mlock(fileSize int) error {
    method mrelock (line 618) | func (db *DB) mrelock(fileSizeFrom, fileSizeTo int) error {
    method init (line 629) | func (db *DB) init() error {
    method Close (line 677) | func (db *DB) Close() error {
    method close (line 690) | func (db *DB) close() error {
    method Begin (line 750) | func (db *DB) Begin(writable bool) (t *Tx, err error) {
    method Logger (line 768) | func (db *DB) Logger() Logger {
    method beginTx (line 775) | func (db *DB) beginTx() (*Tx, error) {
    method beginRWTx (line 822) | func (db *DB) beginRWTx() (*Tx, error) {
    method removeTx (line 858) | func (db *DB) removeTx(tx *Tx) {
    method Update (line 888) | func (db *DB) Update(fn func(*Tx) error) error {
    method View (line 919) | func (db *DB) View(fn func(*Tx) error) error {
    method Batch (line 963) | func (db *DB) Batch(fn func(*Tx) error) error {
    method Sync (line 1078) | func (db *DB) Sync() (err error) {
    method Stats (line 1095) | func (db *DB) Stats() Stats {
    method Info (line 1107) | func (db *DB) Info() *Info {
    method page (line 1113) | func (db *DB) page(id common.Pgid) *common.Page {
    method pageInBuffer (line 1119) | func (db *DB) pageInBuffer(b []byte, id common.Pgid) *common.Page {
    method meta (line 1124) | func (db *DB) meta() *common.Meta {
    method allocate (line 1148) | func (db *DB) allocate(txid common.Txid, count int) (*common.Page, err...
    method grow (line 1186) | func (db *DB) grow(sz int) error {
    method IsReadOnly (line 1237) | func (db *DB) IsReadOnly() bool {
    method freepages (line 1241) | func (db *DB) freepages() []common.Pgid {
  function Open (line 178) | func Open(path string, mode os.FileMode, options *Options) (db *DB, err ...
  type call (line 988) | type call struct
  type batch (line 993) | type batch struct
    method trigger (line 1001) | func (b *batch) trigger() {
    method run (line 1007) | func (b *batch) run() {
  type panicked (line 1054) | type panicked struct
    method Error (line 1058) | func (p panicked) Error() string {
  function safelyCall (line 1065) | func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
  function newFreelist (line 1278) | func newFreelist(freelistType FreelistType) fl.Interface {
  type Options (line 1286) | type Options struct
    method String (line 1362) | func (o *Options) String() string {
  type Stats (line 1381) | type Stats struct
    method Sub (line 1402) | func (s *Stats) Sub(other *Stats) Stats {
  type Info (line 1416) | type Info struct

FILE: db_test.go
  constant pageSize (line 31) | pageSize = 4096
  constant pageHeaderSize (line 34) | pageHeaderSize = 16
  type meta (line 37) | type meta struct
  function TestOpen (line 50) | func TestOpen(t *testing.T) {
  function TestOpen_MultipleGoroutines (line 72) | func TestOpen_MultipleGoroutines(t *testing.T) {
  function TestOpen_ErrPathRequired (line 112) | func TestOpen_ErrPathRequired(t *testing.T) {
  function TestOpen_ErrNotExists (line 120) | func TestOpen_ErrNotExists(t *testing.T) {
  function TestOpen_ErrInvalid (line 128) | func TestOpen_ErrInvalid(t *testing.T) {
  function TestOpen_ErrVersionMismatch (line 149) | func TestOpen_ErrVersionMismatch(t *testing.T) {
  function TestOpen_ErrChecksum (line 185) | func TestOpen_ErrChecksum(t *testing.T) {
  function TestOpen_ReadPageSize_FromMeta1_OS (line 222) | func TestOpen_ReadPageSize_FromMeta1_OS(t *testing.T) {
  function TestOpen_ReadPageSize_FromMeta1_Given (line 249) | func TestOpen_ReadPageSize_FromMeta1_Given(t *testing.T) {
  function TestOpen_Size (line 282) | func TestOpen_Size(t *testing.T) {
  function TestOpen_Size_Large (line 331) | func TestOpen_Size_Large(t *testing.T) {
  function TestOpen_Check (line 397) | func TestOpen_Check(t *testing.T) {
  function TestOpen_MetaInitWriteError (line 425) | func TestOpen_MetaInitWriteError(t *testing.T) {
  function TestOpen_FileTooSmall (line 430) | func TestOpen_FileTooSmall(t *testing.T) {
  function TestDB_Open_InitialMmapSize (line 458) | func TestDB_Open_InitialMmapSize(t *testing.T) {
  function TestDB_Open_ReadOnly (line 543) | func TestDB_Open_ReadOnly(t *testing.T) {
  function TestDB_Open_ReadOnly_NoCreate (line 595) | func TestDB_Open_ReadOnly_NoCreate(t *testing.T) {
  function TestOpen_BigPage (line 603) | func TestOpen_BigPage(t *testing.T) {
  function TestOpen_RecoverFreeList (line 618) | func TestOpen_RecoverFreeList(t *testing.T) {
  function TestDB_Begin_ErrDatabaseNotOpen (line 679) | func TestDB_Begin_ErrDatabaseNotOpen(t *testing.T) {
  function TestDB_BeginRW (line 687) | func TestDB_BeginRW(t *testing.T) {
  function TestDB_Concurrent_WriteTo_and_ConsistentRead (line 703) | func TestDB_Concurrent_WriteTo_and_ConsistentRead(t *testing.T) {
  function TestDB_WriteTo_and_Overwrite (line 794) | func TestDB_WriteTo_and_Overwrite(t *testing.T) {
  function TestDB_BeginRW_Closed (line 900) | func TestDB_BeginRW_Closed(t *testing.T) {
  function TestDB_Close_PendingTx_RW (line 907) | func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t,...
  function TestDB_Close_PendingTx_RO (line 908) | func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t,...
  function testDB_Close_PendingTx (line 911) | func testDB_Close_PendingTx(t *testing.T, writable bool) {
  function TestDB_Update (line 964) | func TestDB_Update(t *testing.T) {
  function TestDB_Update_Closed (line 999) | func TestDB_Update_Closed(t *testing.T) {
  function TestDB_Update_ManualCommit (line 1012) | func TestDB_Update_ManualCommit(t *testing.T) {
  function TestDB_Update_ManualRollback (line 1037) | func TestDB_Update_ManualRollback(t *testing.T) {
  function TestDB_View_ManualCommit (line 1062) | func TestDB_View_ManualCommit(t *testing.T) {
  function TestDB_View_ManualRollback (line 1087) | func TestDB_View_ManualRollback(t *testing.T) {
  function TestDB_Update_Panic (line 1112) | func TestDB_Update_Panic(t *testing.T) {
  function TestDB_View_Error (line 1155) | func TestDB_View_Error(t *testing.T) {
  function TestDB_View_Panic (line 1166) | func TestDB_View_Panic(t *testing.T) {
  function TestDB_Stats (line 1208) | func TestDB_Stats(t *testing.T) {
  function TestDB_Consistency (line 1228) | func TestDB_Consistency(t *testing.T) {
  function TestDBStats_Sub (line 1295) | func TestDBStats_Sub(t *testing.T) {
  function TestDB_Batch (line 1313) | func TestDB_Batch(t *testing.T) {
  function TestDB_Batch_Panic (line 1357) | func TestDB_Batch_Panic(t *testing.T) {
  function TestDB_BatchFull (line 1387) | func TestDB_BatchFull(t *testing.T) {
  function TestDB_BatchTime (line 1445) | func TestDB_BatchTime(t *testing.T) {
  function TestDBUnmap (line 1493) | func TestDBUnmap(t *testing.T) {
  function fillDBWithKeys (line 1514) | func fillDBWithKeys(db *btesting.DB, numKeys int) error {
  function createFilledDB (line 1522) | func createFilledDB(t testing.TB, o *bolt.Options, allocSize int, numKey...
  function TestDB_MaxSizeNotExceeded (line 1540) | func TestDB_MaxSizeNotExceeded(t *testing.T) {
  function TestDB_MaxSizeExceededCanOpen (line 1591) | func TestDB_MaxSizeExceededCanOpen(t *testing.T) {
  function TestDB_MaxSizeExceededCanOpenWithHighMmap (line 1623) | func TestDB_MaxSizeExceededCanOpenWithHighMmap(t *testing.T) {
  function TestDB_MaxSizeExceededDoesNotGrow (line 1658) | func TestDB_MaxSizeExceededDoesNotGrow(t *testing.T) {
  function TestDB_HugeValue (line 1686) | func TestDB_HugeValue(t *testing.T) {
  function ExampleDB_Update (line 1714) | func ExampleDB_Update() {
  function ExampleDB_View (line 1754) | func ExampleDB_View() {
  function ExampleDB_Begin (line 1797) | func ExampleDB_Begin() {
  function BenchmarkDBBatchAutomatic (line 1856) | func BenchmarkDBBatchAutomatic(b *testing.B) {
  function BenchmarkDBBatchSingle (line 1901) | func BenchmarkDBBatchSingle(b *testing.B) {
  function BenchmarkDBBatchManual10x100 (line 1944) | func BenchmarkDBBatchManual10x100(b *testing.B) {
  function validateBatchBench (line 1998) | func validateBatchBench(b *testing.B, db *btesting.DB) {
  function tempfile (line 2034) | func tempfile() string {
  function trunc (line 2048) | func trunc(b []byte, length int) []byte {
  function fileSize (line 2055) | func fileSize(path string) int64 {
  function u64tob (line 2064) | func u64tob(v uint64) []byte {

FILE: db_whitebox_test.go
  function TestOpenWithPreLoadFreelist (line 13) | func TestOpenWithPreLoadFreelist(t *testing.T) {
  function TestMethodPage (line 58) | func TestMethodPage(t *testing.T) {
  function prepareData (line 115) | func prepareData(t *testing.T) (string, error) {

FILE: internal/btesting/btesting.go
  constant TestFreelistType (line 22) | TestFreelistType = "TEST_FREELIST_TYPE"
  constant TestEnableStrictMode (line 24) | TestEnableStrictMode = "TEST_ENABLE_STRICT_MODE"
  type DB (line 28) | type DB struct
    method PostTestCleanup (line 81) | func (db *DB) PostTestCleanup() {
    method Close (line 90) | func (db *DB) Close() error {
    method MustClose (line 107) | func (db *DB) MustClose() {
    method MustDeleteFile (line 112) | func (db *DB) MustDeleteFile() {
    method SetOptions (line 117) | func (db *DB) SetOptions(o *bolt.Options) {
    method MustReopen (line 122) | func (db *DB) MustReopen() {
    method MustCheck (line 134) | func (db *DB) MustCheck() {
    method Fill (line 170) | func (db *DB) Fill(bucket []byte, numTx int, numKeysPerTx int,
    method Path (line 190) | func (db *DB) Path() string {
    method CopyTempFile (line 195) | func (db *DB) CopyTempFile() {
    method PrintStats (line 205) | func (db *DB) PrintStats() {
    method strictModeEnabledDefault (line 223) | func (db *DB) strictModeEnabledDefault() {
    method ForceDisableStrictMode (line 228) | func (db *DB) ForceDisableStrictMode() {
  function MustCreateDB (line 36) | func MustCreateDB(t testing.TB) *DB {
  function MustCreateDBWithOption (line 41) | func MustCreateDBWithOption(t testing.TB, o *bolt.Options) *DB {
  function MustOpenDBWithOption (line 46) | func MustOpenDBWithOption(t testing.TB, f string, o *bolt.Options) *DB {
  function OpenDBWithOption (line 53) | func OpenDBWithOption(t testing.TB, f string, o *bolt.Options) (*DB, err...
  function truncDuration (line 219) | func truncDuration(d time.Duration) string {

FILE: internal/common/bolt_386.go
  constant MaxMapSize (line 4) | MaxMapSize = 0x7FFFFFFF
  constant MaxAllocSize (line 7) | MaxAllocSize = 0xFFFFFFF

FILE: internal/common/bolt_amd64.go
  constant MaxMapSize (line 4) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 7) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_arm.go
  constant MaxMapSize (line 4) | MaxMapSize = 0x7FFFFFFF
  constant MaxAllocSize (line 7) | MaxAllocSize = 0xFFFFFFF

FILE: internal/common/bolt_arm64.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_loong64.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_mips64x.go
  constant MaxMapSize (line 6) | MaxMapSize = 0x8000000000
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_mipsx.go
  constant MaxMapSize (line 6) | MaxMapSize = 0x40000000
  constant MaxAllocSize (line 9) | MaxAllocSize = 0xFFFFFFF

FILE: internal/common/bolt_ppc.go
  constant MaxMapSize (line 6) | MaxMapSize = 0x7FFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0xFFFFFFF

FILE: internal/common/bolt_ppc64.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_ppc64le.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_riscv64.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bolt_s390x.go
  constant MaxMapSize (line 6) | MaxMapSize = 0xFFFFFFFFFFFF
  constant MaxAllocSize (line 9) | MaxAllocSize = 0x7FFFFFFF

FILE: internal/common/bucket.go
  constant BucketHeaderSize (line 8) | BucketHeaderSize = int(unsafe.Sizeof(InBucket{}))
  type InBucket (line 14) | type InBucket struct
    method RootPage (line 26) | func (b *InBucket) RootPage() Pgid {
    method SetRootPage (line 30) | func (b *InBucket) SetRootPage(id Pgid) {
    method InSequence (line 36) | func (b *InBucket) InSequence() uint64 {
    method SetInSequence (line 40) | func (b *InBucket) SetInSequence(v uint64) {
    method IncSequence (line 44) | func (b *InBucket) IncSequence() {
    method InlinePage (line 48) | func (b *InBucket) InlinePage(v []byte) *Page {
    method String (line 52) | func (b *InBucket) String() string {
  function NewInBucket (line 19) | func NewInBucket(root Pgid, seq uint64) InBucket {

FILE: internal/common/inode.go
  type Inode (line 8) | type Inode struct
    method Flags (line 17) | func (in *Inode) Flags() uint32 {
    method SetFlags (line 21) | func (in *Inode) SetFlags(flags uint32) {
    method Pgid (line 25) | func (in *Inode) Pgid() Pgid {
    method SetPgid (line 29) | func (in *Inode) SetPgid(id Pgid) {
    method Key (line 33) | func (in *Inode) Key() []byte {
    method SetKey (line 37) | func (in *Inode) SetKey(key []byte) {
    method Value (line 41) | func (in *Inode) Value() []byte {
    method SetValue (line 45) | func (in *Inode) SetValue(value []byte) {
  type Inodes (line 15) | type Inodes
  function ReadInodeFromPage (line 49) | func ReadInodeFromPage(p *Page) Inodes {
  function WriteInodeToPage (line 70) | func WriteInodeToPage(inodes Inodes, p *Page) uint32 {
  function UsedSpaceInPage (line 107) | func UsedSpaceInPage(inodes Inodes, p *Page) uint32 {

FILE: internal/common/meta.go
  type Meta (line 12) | type Meta struct
    method Validate (line 25) | func (m *Meta) Validate() error {
    method Copy (line 37) | func (m *Meta) Copy(dest *Meta) {
    method Write (line 42) | func (m *Meta) Write(p *Page) {
    method Sum64 (line 61) | func (m *Meta) Sum64() uint64 {
    method Magic (line 67) | func (m *Meta) Magic() uint32 {
    method SetMagic (line 71) | func (m *Meta) SetMagic(v uint32) {
    method Version (line 75) | func (m *Meta) Version() uint32 {
    method SetVersion (line 79) | func (m *Meta) SetVersion(v uint32) {
    method PageSize (line 83) | func (m *Meta) PageSize() uint32 {
    method SetPageSize (line 87) | func (m *Meta) SetPageSize(v uint32) {
    method Flags (line 91) | func (m *Meta) Flags() uint32 {
    method SetFlags (line 95) | func (m *Meta) SetFlags(v uint32) {
    method SetRootBucket (line 99) | func (m *Meta) SetRootBucket(b InBucket) {
    method RootBucket (line 103) | func (m *Meta) RootBucket() *InBucket {
    method Freelist (line 107) | func (m *Meta) Freelist() Pgid {
    method SetFreelist (line 111) | func (m *Meta) SetFreelist(v Pgid) {
    method IsFreelistPersisted (line 115) | func (m *Meta) IsFreelistPersisted() bool {
    method Pgid (line 119) | func (m *Meta) Pgid() Pgid {
    method SetPgid (line 123) | func (m *Meta) SetPgid(id Pgid) {
    method Txid (line 127) | func (m *Meta) Txid() Txid {
    method SetTxid (line 131) | func (m *Meta) SetTxid(id Txid) {
    method IncTxid (line 135) | func (m *Meta) IncTxid() {
    method DecTxid (line 139) | func (m *Meta) DecTxid() {
    method Checksum (line 143) | func (m *Meta) Checksum() uint64 {
    method SetChecksum (line 147) | func (m *Meta) SetChecksum(v uint64) {
    method Print (line 151) | func (m *Meta) Print(w io.Writer) {

FILE: internal/common/page.go
  constant PageHeaderSize (line 10) | PageHeaderSize = unsafe.Sizeof(Page{})
  constant MinKeysPerPage (line 12) | MinKeysPerPage = 2
  constant BranchPageElementSize (line 14) | BranchPageElementSize = unsafe.Sizeof(branchPageElement{})
  constant LeafPageElementSize (line 15) | LeafPageElementSize = unsafe.Sizeof(leafPageElement{})
  constant pgidSize (line 16) | pgidSize = unsafe.Sizeof(Pgid(0))
  constant BranchPageFlag (line 19) | BranchPageFlag   = 0x01
  constant LeafPageFlag (line 20) | LeafPageFlag     = 0x02
  constant MetaPageFlag (line 21) | MetaPageFlag     = 0x04
  constant FreelistPageFlag (line 22) | FreelistPageFlag = 0x10
  constant BucketLeafFlag (line 26) | BucketLeafFlag = 0x01
  type Pgid (line 29) | type Pgid
  type Page (line 31) | type Page struct
    method Typ (line 48) | func (p *Page) Typ() string {
    method IsBranchPage (line 61) | func (p *Page) IsBranchPage() bool {
    method IsLeafPage (line 65) | func (p *Page) IsLeafPage() bool {
    method IsMetaPage (line 69) | func (p *Page) IsMetaPage() bool {
    method IsFreelistPage (line 73) | func (p *Page) IsFreelistPage() bool {
    method Meta (line 78) | func (p *Page) Meta() *Meta {
    method FastCheck (line 82) | func (p *Page) FastCheck(id Pgid) {
    method LeafPageElement (line 93) | func (p *Page) LeafPageElement(index uint16) *leafPageElement {
    method LeafPageElements (line 99) | func (p *Page) LeafPageElements() []leafPageElement {
    method BranchPageElement (line 109) | func (p *Page) BranchPageElement(index uint16) *branchPageElement {
    method BranchPageElements (line 115) | func (p *Page) BranchPageElements() []branchPageElement {
    method FreelistPageCount (line 124) | func (p *Page) FreelistPageCount() (int, int) {
    method FreelistPageIds (line 142) | func (p *Page) FreelistPageIds() []Pgid {
    method hexdump (line 158) | func (p *Page) hexdump(n int) {
    method PageElementSize (line 163) | func (p *Page) PageElementSize() uintptr {
    method Id (line 170) | func (p *Page) Id() Pgid {
    method SetId (line 174) | func (p *Page) SetId(target Pgid) {
    method Flags (line 178) | func (p *Page) Flags() uint16 {
    method SetFlags (line 182) | func (p *Page) SetFlags(v uint16) {
    method Count (line 186) | func (p *Page) Count() uint16 {
    method SetCount (line 190) | func (p *Page) SetCount(target uint16) {
    method Overflow (line 194) | func (p *Page) Overflow() uint32 {
    method SetOverflow (line 198) | func (p *Page) SetOverflow(target uint32) {
    method String (line 202) | func (p *Page) String() string {
  function NewPage (line 38) | func NewPage(id Pgid, flags, count uint16, overflow uint32) *Page {
  type Pages (line 206) | type Pages
    method Len (line 208) | func (s Pages) Len() int           { return len(s) }
    method Swap (line 209) | func (s Pages) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    method Less (line 210) | func (s Pages) Less(i, j int) bool { return s[i].id < s[j].id }
  type branchPageElement (line 213) | type branchPageElement struct
    method Pos (line 219) | func (n *branchPageElement) Pos() uint32 {
    method SetPos (line 223) | func (n *branchPageElement) SetPos(v uint32) {
    method Ksize (line 227) | func (n *branchPageElement) Ksize() uint32 {
    method SetKsize (line 231) | func (n *branchPageElement) SetKsize(v uint32) {
    method Pgid (line 235) | func (n *branchPageElement) Pgid() Pgid {
    method SetPgid (line 239) | func (n *branchPageElement) SetPgid(v Pgid) {
    method Key (line 244) | func (n *branchPageElement) Key() []byte {
  type leafPageElement (line 249) | type leafPageElement struct
    method Flags (line 265) | func (n *leafPageElement) Flags() uint32 {
    method SetFlags (line 269) | func (n *leafPageElement) SetFlags(v uint32) {
    method Pos (line 273) | func (n *leafPageElement) Pos() uint32 {
    method SetPos (line 277) | func (n *leafPageElement) SetPos(v uint32) {
    method Ksize (line 281) | func (n *leafPageElement) Ksize() uint32 {
    method SetKsize (line 285) | func (n *leafPageElement) SetKsize(v uint32) {
    method Vsize (line 289) | func (n *leafPageElement) Vsize() uint32 {
    method SetVsize (line 293) | func (n *leafPageElement) SetVsize(v uint32) {
    method Key (line 298) | func (n *leafPageElement) Key() []byte {
    method Value (line 305) | func (n *leafPageElement) Value() []byte {
    method IsBucketEntry (line 311) | func (n *leafPageElement) IsBucketEntry() bool {
    method Bucket (line 315) | func (n *leafPageElement) Bucket() *InBucket {
  function NewLeafPageElement (line 256) | func NewLeafPageElement(flags, pos, ksize, vsize uint32) *leafPageElement {
  type PageInfo (line 324) | type PageInfo struct
  type Pgids (line 331) | type Pgids
    method Len (line 333) | func (s Pgids) Len() int           { return len(s) }
    method Swap (line 334) | func (s Pgids) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    method Less (line 335) | func (s Pgids) Less(i, j int) bool { return s[i] < s[j] }
    method Merge (line 338) | func (s Pgids) Merge(b Pgids) Pgids {
  function Mergepgids (line 353) | func Mergepgids(dst, a, b Pgids) {

FILE: internal/common/page_test.go
  function TestPage_typ (line 11) | func TestPage_typ(t *testing.T) {
  function TestPage_dump (line 30) | func TestPage_dump(t *testing.T) {
  function TestPgids_merge (line 34) | func TestPgids_merge(t *testing.T) {
  function TestPgids_merge_quick (line 50) | func TestPgids_merge_quick(t *testing.T) {

FILE: internal/common/types.go
  constant MaxMmapStep (line 10) | MaxMmapStep = 1 << 30
  constant Version (line 13) | Version uint32 = 2
  constant Magic (line 16) | Magic uint32 = 0xED0CDAED
  constant PgidNoFreelist (line 18) | PgidNoFreelist Pgid = 0xffffffffffffffff
  constant IgnoreNoSync (line 24) | IgnoreNoSync = runtime.GOOS == "openbsd"
  constant DefaultMaxBatchSize (line 28) | DefaultMaxBatchSize  int = 1000
  constant DefaultMaxBatchDelay (line 29) | DefaultMaxBatchDelay     = 10 * time.Millisecond
  constant DefaultAllocSize (line 30) | DefaultAllocSize         = 16 * 1024 * 1024
  type Txid (line 37) | type Txid

FILE: internal/common/unsafe.go
  function UnsafeAdd (line 7) | func UnsafeAdd(base unsafe.Pointer, offset uintptr) unsafe.Pointer {
  function UnsafeIndex (line 11) | func UnsafeIndex(base unsafe.Pointer, offset uintptr, elemsz uintptr, n ...
  function UnsafeByteSlice (line 15) | func UnsafeByteSlice(base unsafe.Pointer, offset uintptr, i, j int) []by...

FILE: internal/common/utils.go
  function LoadBucket (line 10) | func LoadBucket(buf []byte) *InBucket {
  function LoadPage (line 14) | func LoadPage(buf []byte) *Page {
  function LoadPageMeta (line 18) | func LoadPageMeta(buf []byte) *Meta {
  function CopyFile (line 22) | func CopyFile(srcPath, dstPath string) error {

FILE: internal/common/verify.go
  constant ENV_VERIFY (line 10) | ENV_VERIFY = "BBOLT_VERIFY"
  type VerificationType (line 12) | type VerificationType
  constant ENV_VERIFY_VALUE_ALL (line 15) | ENV_VERIFY_VALUE_ALL    VerificationType = "all"
  constant ENV_VERIFY_VALUE_ASSERT (line 16) | ENV_VERIFY_VALUE_ASSERT VerificationType = "assert"
  function getEnvVerify (line 19) | func getEnvVerify() string {
  function IsVerificationEnabled (line 23) | func IsVerificationEnabled(verification VerificationType) bool {
  function EnableVerifications (line 30) | func EnableVerifications(verification VerificationType) func() {
  function EnableAllVerifications (line 40) | func EnableAllVerifications() func() {
  function DisableVerifications (line 46) | func DisableVerifications() func() {
  function Verify (line 56) | func Verify(f func()) {
  function Assert (line 63) | func Assert(condition bool, msg string, v ...any) {

FILE: internal/freelist/array.go
  type array (line 10) | type array struct
    method Init (line 16) | func (f *array) Init(ids common.Pgids) {
    method Allocate (line 21) | func (f *array) Allocate(txid common.Txid, n int) common.Pgid {
    method FreeCount (line 63) | func (f *array) FreeCount() int {
    method freePageIds (line 67) | func (f *array) freePageIds() common.Pgids {
    method mergeSpans (line 71) | func (f *array) mergeSpans(ids common.Pgids) {
  function NewArrayFreelist (line 101) | func NewArrayFreelist() Interface {

FILE: internal/freelist/array_test.go
  function TestFreelistArray_allocate (line 13) | func TestFreelistArray_allocate(t *testing.T) {
  function TestInvalidArrayAllocation (line 56) | func TestInvalidArrayAllocation(t *testing.T) {
  function Test_Freelist_Array_Rollback (line 66) | func Test_Freelist_Array_Rollback(t *testing.T) {
  function newTestArrayFreelist (line 88) | func newTestArrayFreelist() *array {

FILE: internal/freelist/freelist.go
  type ReadWriter (line 7) | type ReadWriter interface
  type Interface (line 19) | type Interface interface

FILE: internal/freelist/freelist_test.go
  constant TestFreelistType (line 21) | TestFreelistType = "TEST_FREELIST_TYPE"
  function TestFreelist_free (line 24) | func TestFreelist_free(t *testing.T) {
  function TestFreelist_free_overflow (line 33) | func TestFreelist_free_overflow(t *testing.T) {
  function TestFreelist_free_double_free_panics (line 42) | func TestFreelist_free_double_free_panics(t *testing.T) {
  function TestFreelist_free_meta_panics (line 51) | func TestFreelist_free_meta_panics(t *testing.T) {
  function TestFreelist_free_freelist (line 61) | func TestFreelist_free_freelist(t *testing.T) {
  function TestFreelist_free_freelist_alloctx (line 69) | func TestFreelist_free_freelist_alloctx(t *testing.T) {
  function TestFreelist_release (line 91) | func TestFreelist_release(t *testing.T) {
  function TestFreelist_releaseRange (line 109) | func TestFreelist_releaseRange(t *testing.T) {
  function TestFreeList_init (line 237) | func TestFreeList_init(t *testing.T) {
  function TestFreeList_reload (line 255) | func TestFreeList_reload(t *testing.T) {
  function TestTxidSorting (line 277) | func TestTxidSorting(t *testing.T) {
  function TestFreelist_read (line 301) | func TestFreelist_read(t *testing.T) {
  function TestFreelist_read_panics (line 324) | func TestFreelist_read_panics(t *testing.T) {
  function TestFreelist_write (line 336) | func TestFreelist_write(t *testing.T) {
  function TestFreelist_E2E_HappyPath (line 358) | func TestFreelist_E2E_HappyPath(t *testing.T) {
  function TestFreelist_E2E_MultiSpanOverflows (line 394) | func TestFreelist_E2E_MultiSpanOverflows(t *testing.T) {
  function TestFreelist_E2E_Rollbacks (line 419) | func TestFreelist_E2E_Rollbacks(t *testing.T) {
  function TestFreelist_E2E_RollbackPanics (line 437) | func TestFreelist_E2E_RollbackPanics(t *testing.T) {
  function TestFreelist_E2E_Reload (line 451) | func TestFreelist_E2E_Reload(t *testing.T) {
  function TestFreelist_E2E_SerDe_HappyPath (line 487) | func TestFreelist_E2E_SerDe_HappyPath(t *testing.T) {
  function TestFreelist_E2E_SerDe_AcrossImplementations (line 511) | func TestFreelist_E2E_SerDe_AcrossImplementations(t *testing.T) {
  function requirePages (line 541) | func requirePages(t *testing.T, f Interface, freePageIds common.Pgids, p...
  function allPendingPages (line 559) | func allPendingPages(p map[common.Txid]*txPending) common.Pgids {
  function Benchmark_FreelistRelease10K (line 568) | func Benchmark_FreelistRelease10K(b *testing.B)    { benchmark_FreelistR...
  function Benchmark_FreelistRelease100K (line 569) | func Benchmark_FreelistRelease100K(b *testing.B)   { benchmark_FreelistR...
  function Benchmark_FreelistRelease1000K (line 570) | func Benchmark_FreelistRelease1000K(b *testing.B)  { benchmark_FreelistR...
  function Benchmark_FreelistRelease10000K (line 571) | func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistR...
  function benchmark_FreelistRelease (line 573) | func benchmark_FreelistRelease(b *testing.B, size int) {
  function randomPgids (line 586) | func randomPgids(n int) []common.Pgid {
  function Test_freelist_ReadIDs_and_getFreePageIDs (line 595) | func Test_freelist_ReadIDs_and_getFreePageIDs(t *testing.T) {
  function newTestFreelist (line 616) | func newTestFreelist() Interface {

FILE: internal/freelist/hashmap.go
  type pidSet (line 12) | type pidSet
  type hashMap (line 14) | type hashMap struct
    method Init (line 23) | func (f *hashMap) Init(pgids common.Pgids) {
    method Allocate (line 61) | func (f *hashMap) Allocate(txid common.Txid, n int) common.Pgid {
    method FreeCount (line 108) | func (f *hashMap) FreeCount() int {
    method freePageIds (line 117) | func (f *hashMap) freePageIds() common.Pgids {
    method hashmapFreeCountSlow (line 142) | func (f *hashMap) hashmapFreeCountSlow() int {
    method addSpan (line 150) | func (f *hashMap) addSpan(start common.Pgid, size uint64) {
    method delSpan (line 161) | func (f *hashMap) delSpan(start common.Pgid, size uint64) {
    method mergeSpans (line 171) | func (f *hashMap) mergeSpans(ids common.Pgids) {
    method mergeWithExistingSpan (line 206) | func (f *hashMap) mergeWithExistingSpan(pid common.Pgid) {
    method idsFromFreemaps (line 235) | func (f *hashMap) idsFromFreemaps() map[common.Pgid]struct{} {
    method idsFromForwardMap (line 253) | func (f *hashMap) idsFromForwardMap() map[common.Pgid]struct{} {
    method idsFromBackwardMap (line 269) | func (f *hashMap) idsFromBackwardMap() map[common.Pgid]struct{} {
  function NewHashMapFreelist (line 283) | func NewHashMapFreelist() Interface {

FILE: internal/freelist/hashmap_test.go
  function TestFreelistHashmap_init_panics (line 14) | func TestFreelistHashmap_init_panics(t *testing.T) {
  function TestFreelistHashmap_allocate (line 22) | func TestFreelistHashmap_allocate(t *testing.T) {
  function TestFreelistHashmap_mergeWithExist (line 48) | func TestFreelistHashmap_mergeWithExist(t *testing.T) {
  function TestFreelistHashmap_GetFreePageIDs (line 119) | func TestFreelistHashmap_GetFreePageIDs(t *testing.T) {
  function Test_Freelist_Hashmap_Rollback (line 141) | func Test_Freelist_Hashmap_Rollback(t *testing.T) {
  function Benchmark_freelist_hashmapGetFreePageIDs (line 163) | func Benchmark_freelist_hashmapGetFreePageIDs(b *testing.B) {
  function newTestHashMapFreelist (line 184) | func newTestHashMapFreelist() *hashMap {

FILE: internal/freelist/shared.go
  type txPending (line 12) | type txPending struct
  type shared (line 18) | type shared struct
    method pendingPageIds (line 35) | func (t *shared) pendingPageIds() map[common.Txid]*txPending {
    method PendingCount (line 39) | func (t *shared) PendingCount() int {
    method Count (line 47) | func (t *shared) Count() int {
    method Freed (line 51) | func (t *shared) Freed(pgId common.Pgid) bool {
    method Free (line 56) | func (t *shared) Free(txid common.Txid, p *common.Page) {
    method Rollback (line 89) | func (t *shared) Rollback(txid common.Txid) {
    method AddReadonlyTXID (line 120) | func (t *shared) AddReadonlyTXID(tid common.Txid) {
    method RemoveReadonlyTXID (line 124) | func (t *shared) RemoveReadonlyTXID(tid common.Txid) {
    method ReleasePendingPages (line 141) | func (t *shared) ReleasePendingPages() {
    method release (line 160) | func (t *shared) release(txid common.Txid) {
    method releaseRange (line 173) | func (t *shared) releaseRange(begin, end common.Txid) {
    method Copyall (line 207) | func (t *shared) Copyall(dst []common.Pgid) {
    method Reload (line 216) | func (t *shared) Reload(p *common.Page) {
    method NoSyncReload (line 221) | func (t *shared) NoSyncReload(pgIds common.Pgids) {
    method reindex (line 243) | func (t *shared) reindex() {
    method Read (line 257) | func (t *shared) Read(p *common.Page) {
    method EstimatedWritePageSize (line 278) | func (t *shared) EstimatedWritePageSize() int {
    method Write (line 287) | func (t *shared) Write(p *common.Page) {
  function newShared (line 27) | func newShared() *shared {
  type txIDx (line 135) | type txIDx
    method Len (line 137) | func (t txIDx) Len() int           { return len(t) }
    method Swap (line 138) | func (t txIDx) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
    method Less (line 139) | func (t txIDx) Less(i, j int) bool { return t[i] < t[j] }

FILE: internal/guts_cli/guts_cli.go
  function ReadPage (line 21) | func ReadPage(path string, pageID uint64) (*common.Page, []byte, error) {
  function WritePage (line 72) | func WritePage(path string, pageBuf []byte) error {
  function ReadPageAndHWMSize (line 93) | func ReadPageAndHWMSize(path string) (uint64, common.Pgid, error) {
  function GetRootPage (line 116) | func GetRootPage(path string) (root common.Pgid, activeMeta common.Pgid,...
  function GetActiveMetaPage (line 125) | func GetActiveMetaPage(path string) (*common.Meta, common.Pgid, error) {

FILE: internal/surgeon/surgeon.go
  function CopyPage (line 10) | func CopyPage(path string, srcPage common.Pgid, target common.Pgid) error {
  function ClearPage (line 19) | func ClearPage(path string, pgId common.Pgid) (bool, error) {
  function ClearPageElements (line 36) | func ClearPageElements(path string, pgId common.Pgid, start, end int, ab...
  function ClearFreelist (line 115) | func ClearFreelist(path string) error {
  function clearFreelistInMetaPage (line 125) | func clearFreelistInMetaPage(path string, pageId uint64) error {
  function RevertMetaPage (line 146) | func RevertMetaPage(path string) error {

FILE: internal/surgeon/surgeon_test.go
  function TestRevertMetaPage (line 14) | func TestRevertMetaPage(t *testing.T) {

FILE: internal/surgeon/xray.go
  type XRay (line 16) | type XRay struct
    method traverse (line 24) | func (n XRay) traverse(stack []common.Pgid, callback func(page *common...
    method FindPathsToKey (line 77) | func (n XRay) FindPathsToKey(key []byte) ([][]common.Pgid, error) {
  function NewXRay (line 20) | func NewXRay(path string) XRay {

FILE: internal/surgeon/xray_test.go
  function TestFindPathsToKey (line 16) | func TestFindPathsToKey(t *testing.T) {
  function TestFindPathsToKey_Bucket (line 37) | func TestFindPathsToKey_Bucket(t *testing.T) {

FILE: internal/tests/tx_check_test.go
  function TestTx_RecursivelyCheckPages_MisplacedPage (line 15) | func TestTx_RecursivelyCheckPages_MisplacedPage(t *testing.T) {
  function TestTx_RecursivelyCheckPages_CorruptedLeaf (line 54) | func TestTx_RecursivelyCheckPages_CorruptedLeaf(t *testing.T) {

FILE: logger.go
  type Logger (line 11) | type Logger interface
  function getDiscardLogger (line 31) | func getDiscardLogger() Logger {
  constant calldepth (line 40) | calldepth = 2
  type DefaultLogger (line 44) | type DefaultLogger struct
    method EnableTimestamps (line 49) | func (l *DefaultLogger) EnableTimestamps() {
    method EnableDebug (line 53) | func (l *DefaultLogger) EnableDebug() {
    method Debug (line 57) | func (l *DefaultLogger) Debug(v ...interface{}) {
    method Debugf (line 63) | func (l *DefaultLogger) Debugf(format string, v ...interface{}) {
    method Info (line 69) | func (l *DefaultLogger) Info(v ...interface{}) {
    method Infof (line 73) | func (l *DefaultLogger) Infof(format string, v ...interface{}) {
    method Error (line 77) | func (l *DefaultLogger) Error(v ...interface{}) {
    method Errorf (line 81) | func (l *DefaultLogger) Errorf(format string, v ...interface{}) {
    method Warning (line 85) | func (l *DefaultLogger) Warning(v ...interface{}) {
    method Warningf (line 89) | func (l *DefaultLogger) Warningf(format string, v ...interface{}) {
    method Fatal (line 93) | func (l *DefaultLogger) Fatal(v ...interface{}) {
    method Fatalf (line 98) | func (l *DefaultLogger) Fatalf(format string, v ...interface{}) {
    method Panic (line 103) | func (l *DefaultLogger) Panic(v ...interface{}) {
    method Panicf (line 107) | func (l *DefaultLogger) Panicf(format string, v ...interface{}) {
  function header (line 111) | func header(lvl, msg string) string {

FILE: manydbs_test.go
  function createDb (line 11) | func createDb(t *testing.T) (*DB, func()) {
  function createAndPutKeys (line 33) | func createAndPutKeys(t *testing.T) {
  function TestManyDBs (line 65) | func TestManyDBs(t *testing.T) {

FILE: mlock_unix.go
  function mlock (line 8) | func mlock(db *DB, fileSize int) error {
  function munlock (line 21) | func munlock(db *DB, fileSize int) error {

FILE: mlock_windows.go
  function mlock (line 4) | func mlock(_ *DB, _ int) error {
  function munlock (line 9) | func munlock(_ *DB, _ int) error {

FILE: movebucket_test.go
  function TestTx_MoveBucket (line 17) | func TestTx_MoveBucket(t *testing.T) {
  function TestBucket_MoveBucket_DiffDB (line 219) | func TestBucket_MoveBucket_DiffDB(t *testing.T) {
  function TestBucket_MoveBucket_DiffTx (line 267) | func TestBucket_MoveBucket_DiffTx(t *testing.T) {
  function prepareBuckets (line 344) | func prepareBuckets(t testing.TB, tx *bbolt.Tx, buckets ...string) *bbol...
  function openBucket (line 357) | func openBucket(tx *bbolt.Tx, bk *bbolt.Bucket, bucketToOpen string) *bb...
  function createBucketAndPopulateData (line 364) | func createBucketAndPopulateData(t testing.TB, tx *bbolt.Tx, bk *bbolt.B...
  function populateSampleDataInBucket (line 378) | func populateSampleDataInBucket(t testing.TB, bk *bbolt.Bucket, n int) {

FILE: node.go
  type node (line 12) | type node struct
    method root (line 25) | func (n *node) root() *node {
    method minKeys (line 33) | func (n *node) minKeys() int {
    method size (line 41) | func (n *node) size() int {
    method sizeLessThan (line 53) | func (n *node) sizeLessThan(v uintptr) bool {
    method pageElementSize (line 66) | func (n *node) pageElementSize() uintptr {
    method childAt (line 74) | func (n *node) childAt(index int) *node {
    method childIndex (line 82) | func (n *node) childIndex(child *node) int {
    method numChildren (line 88) | func (n *node) numChildren() int {
    method nextSibling (line 93) | func (n *node) nextSibling() *node {
    method prevSibling (line 105) | func (n *node) prevSibling() *node {
    method put (line 117) | func (n *node) put(oldKey, newKey, value []byte, pgId common.Pgid, fla...
    method del (line 145) | func (n *node) del(key []byte) {
    method read (line 162) | func (n *node) read(p *common.Page) {
    method write (line 179) | func (n *node) write(p *common.Page) {
    method split (line 206) | func (n *node) split(pageSize uintptr) []*node {
    method splitTwo (line 229) | func (n *node) splitTwo(pageSize uintptr) (*node, *node) {
    method splitIndex (line 271) | func (n *node) splitIndex(threshold int) (index, sz uintptr) {
    method spill (line 295) | func (n *node) spill() error {
    method rebalance (line 365) | func (n *node) rebalance() {
    method removeChild (line 452) | func (n *node) removeChild(target *node) {
    method dereference (line 463) | func (n *node) dereference() {
    method free (line 494) | func (n *node) free() {
  function compareKeys (line 528) | func compareKeys(left, right []byte) int {
  type nodes (line 532) | type nodes
    method Len (line 534) | func (s nodes) Len() int      { return len(s) }
    method Swap (line 535) | func (s nodes) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    method Less (line 536) | func (s nodes) Less(i, j int) bool {

FILE: node_test.go
  function TestNode_put (line 11) | func TestNode_put(t *testing.T) {
  function TestNode_read_LeafPage (line 38) | func TestNode_read_LeafPage(t *testing.T) {
  function TestNode_write_LeafPage (line 76) | func TestNode_write_LeafPage(t *testing.T) {
  function TestNode_split (line 110) | func TestNode_split(t *testing.T) {
  function TestNode_split_MinKeys (line 137) | func TestNode_split_MinKeys(t *testing.T) {
  function TestNode_split_SinglePage (line 153) | func TestNode_split_SinglePage(t *testing.T) {

FILE: quick_test.go
  function TestMain (line 27) | func TestMain(m *testing.M) {
  function qconfig (line 40) | func qconfig() *quick.Config {
  type testdata (line 47) | type testdata
    method Len (line 49) | func (t testdata) Len() int           { return len(t) }
    method Swap (line 50) | func (t testdata) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
    method Less (line 51) | func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key,...
    method Generate (line 53) | func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value {
  type revtestdata (line 72) | type revtestdata
    method Len (line 74) | func (t revtestdata) Len() int           { return len(t) }
    method Swap (line 75) | func (t revtestdata) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
    method Less (line 76) | func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].K...
  type testdataitem (line 78) | type testdataitem struct
  function randByteSlice (line 83) | func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte {

FILE: simulation_no_freelist_sync_test.go
  function TestSimulateNoFreeListSync_1op_1p (line 9) | func TestSimulateNoFreeListSync_1op_1p(t *testing.T) {
  function TestSimulateNoFreeListSync_10op_1p (line 12) | func TestSimulateNoFreeListSync_10op_1p(t *testing.T) {
  function TestSimulateNoFreeListSync_100op_1p (line 15) | func TestSimulateNoFreeListSync_100op_1p(t *testing.T) {
  function TestSimulateNoFreeListSync_1000op_1p (line 18) | func TestSimulateNoFreeListSync_1000op_1p(t *testing.T) {
  function TestSimulateNoFreeListSync_10000op_1p (line 21) | func TestSimulateNoFreeListSync_10000op_1p(t *testing.T) {
  function TestSimulateNoFreeListSync_10op_10p (line 24) | func TestSimulateNoFreeListSync_10op_10p(t *testing.T) {
  function TestSimulateNoFreeListSync_100op_10p (line 27) | func TestSimulateNoFreeListSync_100op_10p(t *testing.T) {
  function TestSimulateNoFreeListSync_1000op_10p (line 30) | func TestSimulateNoFreeListSync_1000op_10p(t *testing.T) {
  function TestSimulateNoFreeListSync_10000op_10p (line 33) | func TestSimulateNoFreeListSync_10000op_10p(t *testing.T) {
  function TestSimulateNoFreeListSync_100op_100p (line 36) | func TestSimulateNoFreeListSync_100op_100p(t *testing.T) {
  function TestSimulateNoFreeListSync_1000op_100p (line 39) | func TestSimulateNoFreeListSync_1000op_100p(t *testing.T) {
  function TestSimulateNoFreeListSync_10000op_100p (line 42) | func TestSimulateNoFreeListSync_10000op_100p(t *testing.T) {
  function TestSimulateNoFreeListSync_10000op_1000p (line 45) | func TestSimulateNoFreeListSync_10000op_1000p(t *testing.T) {

FILE: simulation_test.go
  function TestSimulate_1op_1p (line 15) | func TestSimulate_1op_1p(t *testing.T)     { testSimulate(t, nil, 1, 1, ...
  function TestSimulate_10op_1p (line 16) | func TestSimulate_10op_1p(t *testing.T)    { testSimulate(t, nil, 1, 10,...
  function TestSimulate_100op_1p (line 17) | func TestSimulate_100op_1p(t *testing.T)   { testSimulate(t, nil, 1, 100...
  function TestSimulate_1000op_1p (line 18) | func TestSimulate_1000op_1p(t *testing.T)  { testSimulate(t, nil, 1, 100...
  function TestSimulate_10000op_1p (line 19) | func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, nil, 1, 100...
  function TestSimulate_10op_10p (line 21) | func TestSimulate_10op_10p(t *testing.T)    { testSimulate(t, nil, 1, 10...
  function TestSimulate_100op_10p (line 22) | func TestSimulate_100op_10p(t *testing.T)   { testSimulate(t, nil, 1, 10...
  function TestSimulate_1000op_10p (line 23) | func TestSimulate_1000op_10p(t *testing.T)  { testSimulate(t, nil, 1, 10...
  function TestSimulate_10000op_10p (line 24) | func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, nil, 1, 10...
  function TestSimulate_100op_100p (line 26) | func TestSimulate_100op_100p(t *testing.T)   { testSimulate(t, nil, 1, 1...
  function TestSimulate_1000op_100p (line 27) | func TestSimulate_1000op_100p(t *testing.T)  { testSimulate(t, nil, 1, 1...
  function TestSimulate_10000op_100p (line 28) | func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, nil, 1, 1...
  function TestSimulate_10000op_1000p (line 30) | func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, nil, 1, ...
  function testSimulate (line 33) | func testSimulate(t *testing.T, openOption *bolt.Options, round, threadC...
  type simulateHandler (line 155) | type simulateHandler
  function simulateGetHandler (line 158) | func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) {
  function simulatePutHandler (line 193) | func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) {
  type QuickDB (line 231) | type QuickDB struct
    method Get (line 242) | func (db *QuickDB) Get(keys [][]byte) []byte {
    method Put (line 268) | func (db *QuickDB) Put(keys [][]byte, value []byte) {
    method Rand (line 290) | func (db *QuickDB) Rand() [][]byte {
    method rand (line 301) | func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) {
    method Copy (line 317) | func (db *QuickDB) Copy() *QuickDB {
    method copy (line 323) | func (db *QuickDB) copy(m map[string]interface{}) map[string]interface...
  function NewQuickDB (line 237) | func NewQuickDB() *QuickDB {
  function randKey (line 336) | func randKey() []byte {
  function randKeys (line 346) | func randKeys() [][]byte {
  function randValue (line 355) | func randValue() []byte {

FILE: tests/dmflakey/dmflakey.go
  type featCfg (line 18) | type featCfg struct
  constant defaultImgSize (line 32) | defaultImgSize int64 = 1024 * 1024 * 1024 * 10
  constant defaultInterval (line 34) | defaultInterval = 2 * time.Minute
  type FeatOpt (line 41) | type FeatOpt
  function WithIntervalFeatOpt (line 44) | func WithIntervalFeatOpt(interval time.Duration) FeatOpt {
  function WithSyncFSFeatOpt (line 52) | func WithSyncFSFeatOpt(syncFS bool) FeatOpt {
  type Flakey (line 59) | type Flakey interface
  type FSType (line 80) | type FSType
  constant FSTypeEXT4 (line 84) | FSTypeEXT4 FSType = "ext4"
  constant FSTypeXFS (line 85) | FSTypeXFS  FSType = "xfs"
  function InitFlakey (line 93) | func InitFlakey(flakeyDevice, dataStorePath string, fsType FSType, mkfsO...
  type flakey (line 133) | type flakey struct
    method DevicePath (line 143) | func (f *flakey) DevicePath() string {
    method Filesystem (line 148) | func (f *flakey) Filesystem() FSType {
    method AllowWrites (line 153) | func (f *flakey) AllowWrites(opts ...FeatOpt) error {
    method DropWrites (line 184) | func (f *flakey) DropWrites(opts ...FeatOpt) error {
    method ErrorWrites (line 226) | func (f *flakey) ErrorWrites(opts ...FeatOpt) error {
    method Teardown (line 263) | func (f *flakey) Teardown() error {
  function createEmptyFSImage (line 296) | func createEmptyFSImage(imgPath string, fsType FSType, mkfsOpt string) e...
  function validateFSType (line 343) | func validateFSType(fsType FSType) error {

FILE: tests/dmflakey/dmflakey_test.go
  function TestMain (line 22) | func TestMain(m *testing.M) {
  function TestBasic (line 28) | func TestBasic(t *testing.T) {
  function TestDropWritesExt4 (line 57) | func TestDropWritesExt4(t *testing.T) {
  function TestErrorWritesExt4 (line 89) | func TestErrorWritesExt4(t *testing.T) {
  function initFlakey (line 115) | func initFlakey(t *testing.T, fsType FSType) (_ Flakey, root string) {
  function writeFile (line 131) | func writeFile(name string, data []byte, perm os.FileMode, sync bool) er...
  function syncfs (line 148) | func syncfs(file string) error {
  function mount (line 162) | func mount(target string, devPath string, opt string) error {
  function unmount (line 173) | func unmount(target string) error {

FILE: tests/dmflakey/dmsetup.go
  function newFlakeyDevice (line 18) | func newFlakeyDevice(flakeyDevice, loopDevice string, interval time.Dura...
  function reloadFlakeyDevice (line 39) | func reloadFlakeyDevice(flakeyDevice string, syncFS bool, table string) ...
  function deleteFlakeyDevice (line 73) | func deleteFlakeyDevice(flakeyDevice string) error {
  function getBlkSize64 (line 85) | func getBlkSize64(device string) (int64, error) {
  function getBlkSize (line 102) | func getBlkSize(device string) (int64, error) {

FILE: tests/dmflakey/loopback.go
  constant loopControlDevice (line 15) | loopControlDevice = "/dev/loop-control"
  constant loopDevicePattern (line 16) | loopDevicePattern = "/dev/loop%d"
  constant maxRetryToAttach (line 18) | maxRetryToAttach = 50
  function attachToLoopDevice (line 26) | func attachToLoopDevice(backingFile string) (string, error) {
  function detachLoopDevice (line 66) | func detachLoopDevice(loopDevice string) error {
  function getFreeLoopDevice (line 79) | func getFreeLoopDevice() (string, error) {

FILE: tests/failpoint/db_failpoint_test.go
  function TestFailpoint_MapFail (line 20) | func TestFailpoint_MapFail(t *testing.T) {
  function TestFailpoint_UnmapFail_DbClose (line 35) | func TestFailpoint_UnmapFail_DbClose(t *testing.T) {
  function TestFailpoint_mLockFail (line 56) | func TestFailpoint_mLockFail(t *testing.T) {
  function TestFailpoint_mLockFail_When_remap (line 73) | func TestFailpoint_mLockFail_When_remap(t *testing.T) {
  function TestFailpoint_ResizeFileFail (line 102) | func TestFailpoint_ResizeFileFail(t *testing.T) {
  function TestFailpoint_LackOfDiskSpace (line 130) | func TestFailpoint_LackOfDiskSpace(t *testing.T) {
  function TestIssue72 (line 172) | func TestIssue72(t *testing.T) {
  function TestTx_Rollback_Freelist (line 273) | func TestTx_Rollback_Freelist(t *testing.T) {
  function idToBytes (line 352) | func idToBytes(id int) []byte {
  function readFreelistPageIds (line 356) | func readFreelistPageIds(path string) ([]common.Pgid, error) {

FILE: tests/robustness/main_test.go
  function TestMain (line 13) | func TestMain(m *testing.M) {

FILE: tests/robustness/powerfailure_test.go
  function TestRestartFromPowerFailureExt4 (line 39) | func TestRestartFromPowerFailureExt4(t *testing.T) {
  function TestRestartFromPowerFailureXFS (line 86) | func TestRestartFromPowerFailureXFS(t *testing.T) {
  function doPowerFailure (line 142) | func doPowerFailure(t *testing.T, du time.Duration, fsType dmflakey.FSTy...
  function activeFailpoint (line 217) | func activeFailpoint(t *testing.T, targetUrl string, fpName, fpVal strin...
  type FlakeyDevice (line 234) | type FlakeyDevice interface
  function initFlakeyDevice (line 245) | func initFlakeyDevice(t *testing.T, name string, fsType dmflakey.FSType,...
  type flakeyT (line 268) | type flakeyT struct
    method RootFS (line 276) | func (f *flakeyT) RootFS() string {
    method PowerFailure (line 281) | func (f *flakeyT) PowerFailure(mntOpt string) error {
  function unmountAll (line 304) | func unmountAll(target string) error {
  function randomInt (line 322) | func randomInt(t *testing.T, max int) int {

FILE: tests/utils/helpers.go
  function init (line 11) | func init() {
  function RequiresRoot (line 16) | func RequiresRoot() {

FILE: tx.go
  type Tx (line 27) | type Tx struct
    method init (line 47) | func (tx *Tx) init(db *DB) {
    method ID (line 68) | func (tx *Tx) ID() int {
    method DB (line 76) | func (tx *Tx) DB() *DB {
    method Size (line 81) | func (tx *Tx) Size() int64 {
    method Writable (line 86) | func (tx *Tx) Writable() bool {
    method Cursor (line 94) | func (tx *Tx) Cursor() *Cursor {
    method Stats (line 99) | func (tx *Tx) Stats() TxStats {
    method Inspect (line 104) | func (tx *Tx) Inspect() BucketStructure {
    method Bucket (line 111) | func (tx *Tx) Bucket(name []byte) *Bucket {
    method CreateBucket (line 118) | func (tx *Tx) CreateBucket(name []byte) (*Bucket, error) {
    method CreateBucketIfNotExists (line 125) | func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error) {
    method DeleteBucket (line 131) | func (tx *Tx) DeleteBucket(name []byte) error {
    method MoveBucket (line 143) | func (tx *Tx) MoveBucket(child []byte, src *Bucket, dst *Bucket) error {
    method ForEach (line 156) | func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error {
    method OnCommit (line 163) | func (tx *Tx) OnCommit(fn func()) {
    method Commit (line 170) | func (tx *Tx) Commit() (err error) {
    method commitFreelist (line 285) | func (tx *Tx) commitFreelist() error {
    method Rollback (line 302) | func (tx *Tx) Rollback() error {
    method nonPhysicalRollback (line 312) | func (tx *Tx) nonPhysicalRollback() {
    method rollback (line 323) | func (tx *Tx) rollback() {
    method close (line 345) | func (tx *Tx) close() {
    method Copy (line 384) | func (tx *Tx) Copy(w io.Writer) error {
    method WriteTo (line 391) | func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
    method CopyFile (line 486) | func (tx *Tx) CopyFile(path string, mode os.FileMode) error {
    method allocate (line 501) | func (tx *Tx) allocate(count int) (*common.Page, error) {
    method write (line 520) | func (tx *Tx) write() error {
    method writeMeta (line 595) | func (tx *Tx) writeMeta() error {
    method page (line 629) | func (tx *Tx) page(id common.Pgid) *common.Page {
    method forEachPage (line 645) | func (tx *Tx) forEachPage(pgidnum common.Pgid, fn func(*common.Page, i...
    method forEachPageInternal (line 651) | func (tx *Tx) forEachPageInternal(pgidstack []common.Pgid, fn func(*co...
    method Page (line 668) | func (tx *Tx) Page(id int) (*common.PageInfo, error) {
  function sameFile (line 470) | func sameFile(f1, f2 *os.File) (bool, error) {
  type TxStats (line 698) | type TxStats struct
    method add (line 742) | func (s *TxStats) add(other *TxStats) {
    method Sub (line 760) | func (s *TxStats) Sub(other *TxStats) TxStats {
    method GetPageCount (line 778) | func (s *TxStats) GetPageCount() int64 {
    method IncPageCount (line 783) | func (s *TxStats) IncPageCount(delta int64) int64 {
    method GetPageAlloc (line 788) | func (s *TxStats) GetPageAlloc() int64 {
    method IncPageAlloc (line 793) | func (s *TxStats) IncPageAlloc(delta int64) int64 {
    method GetCursorCount (line 798) | func (s *TxStats) GetCursorCount() int64 {
    method IncCursorCount (line 803) | func (s *TxStats) IncCursorCount(delta int64) int64 {
    method GetNodeCount (line 808) | func (s *TxStats) GetNodeCount() int64 {
    method IncNodeCount (line 813) | func (s *TxStats) IncNodeCount(delta int64) int64 {
    method GetNodeDeref (line 818) | func (s *TxStats) GetNodeDeref() int64 {
    method IncNodeDeref (line 823) | func (s *TxStats) IncNodeDeref(delta int64) int64 {
    method GetRebalance (line 828) | func (s *TxStats) GetRebalance() int64 {
    method IncRebalance (line 833) | func (s *TxStats) IncRebalance(delta int64) int64 {
    method GetRebalanceTime (line 838) | func (s *TxStats) GetRebalanceTime() time.Duration {
    method IncRebalanceTime (line 843) | func (s *TxStats) IncRebalanceTime(delta time.Duration) time.Duration {
    method GetSplit (line 848) | func (s *TxStats) GetSplit() int64 {
    method IncSplit (line 853) | func (s *TxStats) IncSplit(delta int64) int64 {
    method GetSpill (line 858) | func (s *TxStats) GetSpill() int64 {
    method IncSpill (line 863) | func (s *TxStats) IncSpill(delta int64) int64 {
    method GetSpillTime (line 868) | func (s *TxStats) GetSpillTime() time.Duration {
    method IncSpillTime (line 873) | func (s *TxStats) IncSpillTime(delta time.Duration) time.Duration {
    method GetWrite (line 878) | func (s *TxStats) GetWrite() int64 {
    method IncWrite (line 883) | func (s *TxStats) IncWrite(delta int64) int64 {
    method GetWriteTime (line 888) | func (s *TxStats) GetWriteTime() time.Duration {
    method IncWriteTime (line 893) | func (s *TxStats) IncWriteTime(delta time.Duration) time.Duration {
  function atomicAddDuration (line 897) | func atomicAddDuration(ptr *time.Duration, du time.Duration) time.Durati...
  function atomicLoadDuration (line 901) | func atomicLoadDuration(ptr *time.Duration) time.Duration {

FILE: tx_check.go
  method Check (line 21) | func (tx *Tx) Check(options ...CheckOption) <-chan error {
  method check (line 38) | func (tx *Tx) check(cfg checkConfig, ch chan error) {
  method recursivelyCheckPage (line 91) | func (tx *Tx) recursivelyCheckPage(pageId common.Pgid, reachable map[com...
  method recursivelyCheckBucketInPage (line 97) | func (tx *Tx) recursivelyCheckBucketInPage(pageId common.Pgid, reachable...
  method recursivelyCheckBucket (line 128) | func (tx *Tx) recursivelyCheckBucket(b *Bucket, reachable map[common.Pgi...
  method checkInvariantProperties (line 146) | func (tx *Tx) checkInvariantProperties(pageId common.Pgid, reachable map...
  function verifyPageReachable (line 155) | func verifyPageReachable(p *common.Page, hwm common.Pgid, stack []common...
  method recursivelyCheckPageKeyOrder (line 181) | func (tx *Tx) recursivelyCheckPageKeyOrder(pgId common.Pgid, keyToString...
  method recursivelyCheckPageKeyOrderInternal (line 190) | func (tx *Tx) recursivelyCheckPageKeyOrderInternal(
  function verifyKeyOrder (line 232) | func verifyKeyOrder(pgId common.Pgid, pageType string, index int, key []...
  type checkConfig (line 256) | type checkConfig struct
  type CheckOption (line 261) | type CheckOption
  function WithKVStringer (line 263) | func WithKVStringer(kvStringer KVStringer) CheckOption {
  function WithPageId (line 270) | func WithPageId(pageId uint64) CheckOption {
  type KVStringer (line 277) | type KVStringer interface
  function HexKVStringer (line 283) | func HexKVStringer() KVStringer {
  type hexKvStringer (line 287) | type hexKvStringer struct
    method KeyToString (line 289) | func (hexKvStringer) KeyToString(key []byte) string {
    method ValueToString (line 293) | func (hexKvStringer) ValueToString(value []byte) string {

FILE: tx_check_test.go
  function TestTx_Check_CorruptPage (line 16) | func TestTx_Check_CorruptPage(t *testing.T) {
  function TestTx_Check_WithNestBucket (line 63) | func TestTx_Check_WithNestBucket(t *testing.T) {
  function TestTx_Check_Panic (line 123) | func TestTx_Check_Panic(t *testing.T) {
  function corruptRandomLeafPageInBucket (line 161) | func corruptRandomLeafPageInBucket(t testing.TB, db *bbolt.DB, bucketNam...
  function corruptRootPage (line 192) | func corruptRootPage(t testing.TB, db *bbolt.DB, bucketName []byte) {
  function mustGetBucketRootPage (line 205) | func mustGetBucketRootPage(t testing.TB, db *bbolt.DB, bucketName []byte...

FILE: tx_stats_test.go
  function TestTxStats_add (line 10) | func TestTxStats_add(t *testing.T) {

FILE: tx_test.go
  function TestTx_Check_ReadOnly (line 22) | func TestTx_Check_ReadOnly(t *testing.T) {
  function TestTx_Commit_ErrTxClosed (line 73) | func TestTx_Commit_ErrTxClosed(t *testing.T) {
  function TestTx_Rollback_ErrTxClosed (line 94) | func TestTx_Rollback_ErrTxClosed(t *testing.T) {
  function TestTx_Commit_ErrTxNotWritable (line 111) | func TestTx_Commit_ErrTxNotWritable(t *testing.T) {
  function TestTx_Cursor (line 128) | func TestTx_Cursor(t *testing.T) {
  function TestTx_CreateBucket_ErrTxNotWritable (line 165) | func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
  function TestTx_CreateBucket_ErrTxClosed (line 179) | func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
  function TestTx_Bucket (line 195) | func TestTx_Bucket(t *testing.T) {
  function TestTx_Get_NotFound (line 211) | func TestTx_Get_NotFound(t *testing.T) {
  function TestTx_CreateBucket (line 232) | func TestTx_CreateBucket(t *testing.T) {
  function TestTx_CreateBucketIfNotExists (line 260) | func TestTx_CreateBucketIfNotExists(t *testing.T) {
  function TestTx_CreateBucketIfNotExists_ErrBucketNameRequired (line 294) | func TestTx_CreateBucketIfNotExists_ErrBucketNameRequired(t *testing.T) {
  function TestTx_CreateBucket_ErrBucketExists (line 312) | func TestTx_CreateBucket_ErrBucketExists(t *testing.T) {
  function TestTx_CreateBucket_ErrBucketNameRequired (line 337) | func TestTx_CreateBucket_ErrBucketNameRequired(t *testing.T) {
  function TestTx_DeleteBucket (line 350) | func TestTx_DeleteBucket(t *testing.T) {
  function TestTx_DeleteBucket_ErrTxClosed (line 396) | func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
  function TestTx_DeleteBucket_ReadOnly (line 411) | func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
  function TestTx_DeleteBucket_NotFound (line 424) | func TestTx_DeleteBucket_NotFound(t *testing.T) {
  function TestTx_ForEach_NoError (line 438) | func TestTx_ForEach_NoError(t *testing.T) {
  function TestTx_ForEach_WithError (line 461) | func TestTx_ForEach_WithError(t *testing.T) {
  function TestTx_OnCommit (line 485) | func TestTx_OnCommit(t *testing.T) {
  function TestTx_OnCommit_Rollback (line 504) | func TestTx_OnCommit_Rollback(t *testing.T) {
  function TestTx_CopyFile (line 523) | func TestTx_CopyFile(t *testing.T) {
  type failWriterError (line 571) | type failWriterError struct
    method Error (line 573) | func (failWriterError) Error() string {
  type failWriter (line 577) | type failWriter struct
    method Write (line 582) | func (f *failWriter) Write(p []byte) (n int, err error) {
  function TestTx_CopyFile_Error_Meta (line 593) | func TestTx_CopyFile_Error_Meta(t *testing.T) {
  function TestTx_CopyFile_Error_Normal (line 619) | func TestTx_CopyFile_Error_Normal(t *testing.T) {
  function TestTx_Rollback (line 645) | func TestTx_Rollback(t *testing.T) {
  function TestTx_releaseRange (line 700) | func TestTx_releaseRange(t *testing.T) {
  function ExampleTx_Rollback (line 799) | func ExampleTx_Rollback() {
  function ExampleTx_CopyFile (line 853) | func ExampleTx_CopyFile() {
  function TestTxStats_GetAndIncAtomically (line 912) | func TestTxStats_GetAndIncAtomically(t *testing.T) {
  function TestTxStats_Sub (line 970) | func TestTxStats_Sub(t *testing.T) {
  function TestTx_TruncateBeforeWrite (line 1017) | func TestTx_TruncateBeforeWrite(t *testing.T) {

FILE: unix_test.go
  function TestMlock_DbOpen (line 15) | func TestMlock_DbOpen(t *testing.T) {
  function TestMlock_DbCanGrow_Small (line 23) | func TestMlock_DbCanGrow_Small(t *testing.T) {
  function TestMlock_DbCanGrow_Big (line 49) | func TestMlock_DbCanGrow_Big(t *testing.T) {
  function insertChunk (line 77) | func insertChunk(t *testing.T, db *btesting.DB, chunkId int) {
  function skipOnMemlockLimitBelow (line 102) | func skipOnMemlockLimitBelow(t *testing.T, memlockLimitRequest uint64) {

FILE: utils_test.go
  function dumpBucket (line 10) | func dumpBucket(srcBucketName []byte, srcBucket *bolt.Bucket, dstFilenam...
  function cloneBucket (line 30) | func cloneBucket(src *bolt.Bucket, dst *bolt.Bucket) error {
Condensed preview — 155 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (828K chars).
[
  {
    "path": ".gitattributes",
    "chars": 206,
    "preview": "# ensure that line endings for Windows builds are properly formatted\n# see https://github.com/golangci/golangci-lint-act"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 196,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: weekly\n\n  - pac"
  },
  {
    "path": ".github/workflows/benchmark-pr.yaml",
    "chars": 217,
    "preview": "---\nname: Benchmarks on PRs (AMD64)\npermissions: read-all\non: [pull_request]\njobs:\n  amd64:\n    uses: ./.github/workflow"
  },
  {
    "path": ".github/workflows/benchmark-releases.yaml",
    "chars": 354,
    "preview": "---\nname: Nightly Benchmarks against last release (AMD64)\npermissions: read-all\non:\n  schedule:\n    - cron: '10 5 * * *'"
  },
  {
    "path": ".github/workflows/benchmark-template.yaml",
    "chars": 2303,
    "preview": "---\nname: Reusable Benchmark Template\non:\n  workflow_call:\n    inputs:\n      # which git reference to benchmark against\n"
  },
  {
    "path": ".github/workflows/cross-arch-template.yaml",
    "chars": 807,
    "preview": "---\nname: Reusable Cross-Platform Build Workflow\non:\n  workflow_call:\n    inputs:\n      archs:\n        required: true\n  "
  },
  {
    "path": ".github/workflows/cross-arch-test.yaml",
    "chars": 983,
    "preview": "---\nname: Cross-Platform Build Tests\npermissions: read-all\non: [push, pull_request]\n\njobs:\n  build-aix:\n    uses: ./.git"
  },
  {
    "path": ".github/workflows/failpoint_test.yaml",
    "chars": 753,
    "preview": "---\nname: Failpoint test\non: [push, pull_request]\npermissions: read-all\njobs:\n  test:\n    strategy:\n      matrix:\n      "
  },
  {
    "path": ".github/workflows/gh-workflow-approve.yaml",
    "chars": 1273,
    "preview": "---\nname: Approve GitHub Workflows\npermissions: read-all\non:\n  pull_request_target:\n    types:\n      - labeled\n      - s"
  },
  {
    "path": ".github/workflows/robustness_nightly.yaml",
    "chars": 454,
    "preview": "---\nname: Robustness Nightly\npermissions: read-all\non:\n  schedule:\n    - cron: '25 9 * * *' # runs every day at 09:25 UT"
  },
  {
    "path": ".github/workflows/robustness_template.yaml",
    "chars": 1533,
    "preview": "---\nname: Reusable Robustness Workflow\non:\n  workflow_call:\n    inputs:\n      count:\n        required: true\n        type"
  },
  {
    "path": ".github/workflows/robustness_test.yaml",
    "chars": 374,
    "preview": "name: Robustness Test\non: [push, pull_request]\npermissions: read-all\njobs:\n  amd64:\n    uses: ./.github/workflows/robust"
  },
  {
    "path": ".github/workflows/stale.yaml",
    "chars": 432,
    "preview": "name: 'Close stale issues and PRs'\non:\n  schedule:\n    - cron: '0 0 * * *'  # every day at 00:00 UTC\n\npermissions:\n  iss"
  },
  {
    "path": ".github/workflows/tests-template.yml",
    "chars": 1579,
    "preview": "---\nname: Reusable unit test Workflow\non:\n  workflow_call:\n    inputs:\n      runs-on:\n        required: false\n        ty"
  },
  {
    "path": ".github/workflows/tests_amd64.yaml",
    "chars": 945,
    "preview": "---\nname: Tests AMD64\npermissions: read-all\non: [push, pull_request]\njobs:\n  test-linux-amd64:\n    uses: ./.github/workf"
  },
  {
    "path": ".github/workflows/tests_arm64.yaml",
    "chars": 993,
    "preview": "---\nname: Tests ARM64\npermissions: read-all\non: [push, pull_request]\njobs:\n  test-linux-arm64:\n    uses: ./.github/workf"
  },
  {
    "path": ".github/workflows/tests_windows.yml",
    "chars": 2057,
    "preview": "---\nname: Tests\non: [push, pull_request]\npermissions: read-all\njobs:\n  test-windows:\n    strategy:\n      fail-fast: fals"
  },
  {
    "path": ".gitignore",
    "chars": 96,
    "preview": "*.prof\n*.test\n*.swp\n/bin/\ncover.out\ncover-*.out\n/.idea\n*.iml\n/bbolt\n/cmd/bbolt/bbolt\n.DS_Store\n\n"
  },
  {
    "path": ".go-version",
    "chars": 8,
    "preview": "1.24.13\n"
  },
  {
    "path": ".golangci.yaml",
    "chars": 996,
    "preview": "formatters:\n  enable:\n    - gci\n    - gofmt\n    - goimports\n  settings: # please keep this alphabetized\n    gci:\n      s"
  },
  {
    "path": "CHANGELOG/CHANGELOG-1.3.md",
    "chars": 5077,
    "preview": "Note that we start to track changes starting from v1.3.7.\n\n<hr>\n\n## v1.3.12(2025-08-19)\n\n### BoltDB\n- [Add protection on"
  },
  {
    "path": "CHANGELOG/CHANGELOG-1.4.md",
    "chars": 4840,
    "preview": "\n<hr>\n\n## v1.4.3(2025-08-19)\n\n### BoltDB\n- Fix [potential data corruption in `(*Tx)WriteTo` if underlying db file is ove"
  },
  {
    "path": "CHANGELOG/CHANGELOG-1.5.md",
    "chars": 487,
    "preview": "<hr>\n\n## v1.5.0(TBD)\n\n### BoltDB\n- [Add support for data file size limit](https://github.com/etcd-io/bbolt/pull/929)\n- ["
  },
  {
    "path": "LICENSE",
    "chars": 1078,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2013 Ben Johnson\n\nPermission is hereby granted, free of charge, to any person obtai"
  },
  {
    "path": "Makefile",
    "chars": 3127,
    "preview": "BRANCH=`git rev-parse --abbrev-ref HEAD`\nCOMMIT=`git rev-parse --short HEAD`\nGOLDFLAGS=\"-X main.branch $(BRANCH) -X main"
  },
  {
    "path": "OWNERS",
    "chars": 546,
    "preview": "# See the OWNERS docs at https://go.k8s.io/owners\n\napprovers:\n  - ahrtr           # Benjamin Wang <benjamin.ahrtr@gmail."
  },
  {
    "path": "README.md",
    "chars": 42161,
    "preview": "bbolt\n=====\n\n[![Go Report Card](https://goreportcard.com/badge/go.etcd.io/bbolt?style=flat-square)](https://goreportcard"
  },
  {
    "path": "allocate_test.go",
    "chars": 909,
    "preview": "package bbolt\n\nimport (\n\t\"testing\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n\t\"go.etcd.io/bbolt/internal/freelist\"\n)\n\nfunc Te"
  },
  {
    "path": "bolt_aix.go",
    "chars": 2035,
    "preview": "//go:build aix\n\npackage bbolt\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"go.etcd.io/bbol"
  },
  {
    "path": "bolt_android.go",
    "chars": 2111,
    "preview": "package bbolt\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"go.etcd.io/bbolt/internal/commo"
  },
  {
    "path": "bolt_linux.go",
    "chars": 172,
    "preview": "package bbolt\n\nimport (\n\t\"syscall\"\n)\n\n// fdatasync flushes written data to a file descriptor.\nfunc fdatasync(db *DB) err"
  },
  {
    "path": "bolt_openbsd.go",
    "chars": 241,
    "preview": "package bbolt\n\nimport (\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc msync(db *DB) error {\n\treturn unix.Msync(db.data[:db.datasz], u"
  },
  {
    "path": "bolt_solaris.go",
    "chars": 2019,
    "preview": "package bbolt\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"go.etcd.io/bbolt/internal/commo"
  },
  {
    "path": "bolt_unix.go",
    "chars": 2034,
    "preview": "//go:build !windows && !plan9 && !solaris && !aix && !android\n\npackage bbolt\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsaf"
  },
  {
    "path": "bolt_windows.go",
    "chars": 3349,
    "preview": "package bbolt\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"go.etcd.io/bbolt/error"
  },
  {
    "path": "boltsync_unix.go",
    "chars": 180,
    "preview": "//go:build !windows && !plan9 && !linux && !openbsd\n\npackage bbolt\n\n// fdatasync flushes written data to a file descript"
  },
  {
    "path": "bucket.go",
    "chars": 28755,
    "preview": "package bbolt\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"unsafe\"\n\n\t\"go.etcd.io/bbolt/errors\"\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\ncon"
  },
  {
    "path": "bucket_test.go",
    "chars": 53718,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings"
  },
  {
    "path": "cmd/bbolt/OWNERS",
    "chars": 596,
    "preview": "# See the OWNERS docs at https://go.k8s.io/owners\n\napprovers:\n  - ahrtr           # Benjamin Wang <benjamin.ahrtr@gmail."
  },
  {
    "path": "cmd/bbolt/README.md",
    "chars": 17731,
    "preview": "# Introduction to bbolt command line\n\n`bbolt` provides a command line utility for inspecting and manipulating bbolt data"
  },
  {
    "path": "cmd/bbolt/command/command_bench.go",
    "chars": 20172,
    "preview": "package command\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"math/rand\"\n\t\"os\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"sync/"
  },
  {
    "path": "cmd/bbolt/command/command_bench_test.go",
    "chars": 1763,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\""
  },
  {
    "path": "cmd/bbolt/command/command_buckets.go",
    "chars": 905,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\nfunc newBucketsCommand() *cobra"
  },
  {
    "path": "cmd/bbolt/command/command_buckets_test.go",
    "chars": 1515,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt \"go.etcd.io/bbol"
  },
  {
    "path": "cmd/bbolt/command/command_check.go",
    "chars": 1627,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.etc"
  },
  {
    "path": "cmd/bbolt/command/command_check_test.go",
    "chars": 1576,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.etcd.io/bbolt/cmd"
  },
  {
    "path": "cmd/bbolt/command/command_compact.go",
    "chars": 2281,
    "preview": "package command\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tbolt \"go.etcd.io"
  },
  {
    "path": "cmd/bbolt/command/command_compact_test.go",
    "chars": 2543,
    "preview": "package command_test\n\nimport (\n\tcrypto \"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"testing\"\n\n\t\"github.com/stretchr/tes"
  },
  {
    "path": "cmd/bbolt/command/command_dump.go",
    "chars": 2556,
    "preview": "package command\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"go.etcd.io/bbolt/internal/guts_cli\"\n"
  },
  {
    "path": "cmd/bbolt/command/command_dump_test.go",
    "chars": 1201,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t"
  },
  {
    "path": "cmd/bbolt/command/command_get.go",
    "chars": 2128,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.etc"
  },
  {
    "path": "cmd/bbolt/command/command_get_test.go",
    "chars": 2192,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify"
  },
  {
    "path": "cmd/bbolt/command/command_info.go",
    "chars": 798,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\nfunc newInfoCommand() *cobra.Co"
  },
  {
    "path": "cmd/bbolt/command/command_info_test.go",
    "chars": 993,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.etcd.io"
  },
  {
    "path": "cmd/bbolt/command/command_inspect.go",
    "chars": 860,
    "preview": "package command\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\nfunc new"
  },
  {
    "path": "cmd/bbolt/command/command_inspect_test.go",
    "chars": 555,
    "preview": "package command_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.etcd.io"
  },
  {
    "path": "cmd/bbolt/command/command_keys.go",
    "chars": 1314,
    "preview": "package command\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\ntype keysOpti"
  },
  {
    "path": "cmd/bbolt/command/command_keys_test.go",
    "chars": 2462,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt"
  },
  {
    "path": "cmd/bbolt/command/command_page.go",
    "chars": 5630,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.etcd.io/bbolt/internal"
  },
  {
    "path": "cmd/bbolt/command/command_page_item.go",
    "chars": 2828,
    "preview": "package command\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.e"
  },
  {
    "path": "cmd/bbolt/command/command_page_item_test.go",
    "chars": 2810,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/te"
  },
  {
    "path": "cmd/bbolt/command/command_page_test.go",
    "chars": 2294,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt \"go.etcd.io/"
  },
  {
    "path": "cmd/bbolt/command/command_pages.go",
    "chars": 2147,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\ntype Page"
  },
  {
    "path": "cmd/bbolt/command/command_pages_test.go",
    "chars": 1450,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt"
  },
  {
    "path": "cmd/bbolt/command/command_root.go",
    "chars": 671,
    "preview": "package command\n\nimport (\n\t\"github.com/spf13/cobra\"\n)\n\nconst (\n\tcliName        = \"bbolt\"\n\tcliDescription = \"A simple com"
  },
  {
    "path": "cmd/bbolt/command/command_stats.go",
    "chars": 4165,
    "preview": "package command\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\nfunc newSta"
  },
  {
    "path": "cmd/bbolt/command/command_stats_test.go",
    "chars": 4390,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/requi"
  },
  {
    "path": "cmd/bbolt/command/command_surgery.go",
    "chars": 9063,
    "preview": "package command\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.etcd.io/bbol"
  },
  {
    "path": "cmd/bbolt/command/command_surgery_freelist.go",
    "chars": 3013,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.etcd.io/bbolt/internal/"
  },
  {
    "path": "cmd/bbolt/command/command_surgery_freelist_test.go",
    "chars": 2704,
    "preview": "package command_test\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/"
  },
  {
    "path": "cmd/bbolt/command/command_surgery_meta.go",
    "chars": 7253,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n"
  },
  {
    "path": "cmd/bbolt/command/command_surgery_meta_test.go",
    "chars": 2866,
    "preview": "package command_test\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tb"
  },
  {
    "path": "cmd/bbolt/command/command_surgery_test.go",
    "chars": 17922,
    "preview": "package command_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github."
  },
  {
    "path": "cmd/bbolt/command/command_version.go",
    "chars": 543,
    "preview": "package command\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"go.etcd.io/bbolt/version\"\n)\n\nfunc newVersionCo"
  },
  {
    "path": "cmd/bbolt/command/errors.go",
    "chars": 1505,
    "preview": "package command\n\nimport \"errors\"\n\nvar (\n\t// ErrBatchInvalidWriteMode is returned when the write mode is other than seq, "
  },
  {
    "path": "cmd/bbolt/command/utils.go",
    "chars": 3225,
    "preview": "package command\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strconv\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\tbo"
  },
  {
    "path": "cmd/bbolt/command/utils_test.go",
    "chars": 3891,
    "preview": "package command_test\n\nimport (\n\t\"bytes\"\n\tcrypto \"crypto/rand\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/ran"
  },
  {
    "path": "cmd/bbolt/main.go",
    "chars": 265,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"go.etcd.io/bbolt/cmd/bbolt/command\"\n)\n\nfunc main() {\n\trootCmd := command.NewRootC"
  },
  {
    "path": "code-of-conduct.md",
    "chars": 146,
    "preview": "# etcd Community Code of Conduct\n\nPlease refer to [etcd Community Code of Conduct](https://github.com/etcd-io/etcd/blob/"
  },
  {
    "path": "compact.go",
    "chars": 3148,
    "preview": "package bbolt\n\n// Compact will create a copy of the source DB and in the destination DB. This may\n// reclaim space that "
  },
  {
    "path": "concurrent_test.go",
    "chars": 23540,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\tcrand \"crypto/rand\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\tmrand \"math/ra"
  },
  {
    "path": "cursor.go",
    "chars": 12689,
    "preview": "package bbolt\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"go.etcd.io/bbolt/errors\"\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// Cu"
  },
  {
    "path": "cursor_test.go",
    "chars": 23376,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"reflect\"\n\t\"sort\"\n\t\"testing\"\n\t\"testing/qui"
  },
  {
    "path": "db.go",
    "chars": 41718,
    "preview": "package bbolt\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\t\"unsafe\"\n\n\tberrors \"go.etcd.io/bbolt/er"
  },
  {
    "path": "db_test.go",
    "chars": 50647,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/f"
  },
  {
    "path": "db_whitebox_test.go",
    "chars": 2797,
    "preview": "package bbolt\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify"
  },
  {
    "path": "doc.go",
    "chars": 1783,
    "preview": "/*\npackage bbolt implements a low-level key/value store in pure Go. It supports\nfully serializable transactions, ACID se"
  },
  {
    "path": "errors/errors.go",
    "chars": 3728,
    "preview": "// Package errors defines the error variables that may be returned\n// during bbolt operations.\npackage errors\n\nimport \"e"
  },
  {
    "path": "errors.go",
    "chars": 4225,
    "preview": "package bbolt\n\nimport \"go.etcd.io/bbolt/errors\"\n\n// These errors can be returned when opening or calling methods on a DB"
  },
  {
    "path": "go.mod",
    "chars": 774,
    "preview": "module go.etcd.io/bbolt\n\ngo 1.24.0\n\ntoolchain go1.24.13\n\nrequire (\n\tgithub.com/spf13/cobra v1.10.2\n\tgithub.com/spf13/pfl"
  },
  {
    "path": "go.sum",
    "chars": 3148,
    "preview": "github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794 h1:xlwdaKcTNVW4PtpQb8aKA4Pjy0CdJHEqvFbAnvR5m2g=\ngith"
  },
  {
    "path": "internal/btesting/btesting.go",
    "chars": 5645,
    "preview": "package btesting\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/s"
  },
  {
    "path": "internal/common/bolt_386.go",
    "chars": 214,
    "preview": "package common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0x7FFFFFFF // 2GB\n\n"
  },
  {
    "path": "internal/common/bolt_amd64.go",
    "chars": 221,
    "preview": "package common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0xFFFFFFFFFFFF // 2"
  },
  {
    "path": "internal/common/bolt_arm.go",
    "chars": 214,
    "preview": "package common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0x7FFFFFFF // 2GB\n\n"
  },
  {
    "path": "internal/common/bolt_arm64.go",
    "chars": 239,
    "preview": "//go:build arm64\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0"
  },
  {
    "path": "internal/common/bolt_loong64.go",
    "chars": 241,
    "preview": "//go:build loong64\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize ="
  },
  {
    "path": "internal/common/bolt_mips64x.go",
    "chars": 250,
    "preview": "//go:build mips64 || mips64le\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst M"
  },
  {
    "path": "internal/common/bolt_mipsx.go",
    "chars": 241,
    "preview": "//go:build mips || mipsle\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMa"
  },
  {
    "path": "internal/common/bolt_ppc.go",
    "chars": 230,
    "preview": "//go:build ppc\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0x7"
  },
  {
    "path": "internal/common/bolt_ppc64.go",
    "chars": 239,
    "preview": "//go:build ppc64\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0"
  },
  {
    "path": "internal/common/bolt_ppc64le.go",
    "chars": 241,
    "preview": "//go:build ppc64le\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize ="
  },
  {
    "path": "internal/common/bolt_riscv64.go",
    "chars": 241,
    "preview": "//go:build riscv64\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize ="
  },
  {
    "path": "internal/common/bolt_s390x.go",
    "chars": 239,
    "preview": "//go:build s390x\n\npackage common\n\n// MaxMapSize represents the largest mmap size supported by Bolt.\nconst MaxMapSize = 0"
  },
  {
    "path": "internal/common/bucket.go",
    "chars": 1282,
    "preview": "package common\n\nimport (\n\t\"fmt\"\n\t\"unsafe\"\n)\n\nconst BucketHeaderSize = int(unsafe.Sizeof(InBucket{}))\n\n// InBucket repres"
  },
  {
    "path": "internal/common/inode.go",
    "chars": 2790,
    "preview": "package common\n\nimport \"unsafe\"\n\n// Inode represents an internal node inside of a node.\n// It can be used to point to el"
  },
  {
    "path": "internal/common/meta.go",
    "chars": 3112,
    "preview": "package common\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"io\"\n\t\"unsafe\"\n\n\t\"go.etcd.io/bbolt/errors\"\n)\n\ntype Meta struct {\n\tmagic    "
  },
  {
    "path": "internal/common/page.go",
    "chars": 8647,
    "preview": "package common\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"unsafe\"\n)\n\nconst PageHeaderSize = unsafe.Sizeof(Page{})\n\nconst MinKeysPe"
  },
  {
    "path": "internal/common/page_test.go",
    "chars": 1784,
    "preview": "package common\n\nimport (\n\t\"reflect\"\n\t\"sort\"\n\t\"testing\"\n\t\"testing/quick\"\n)\n\n// Ensure that the page type can be returned "
  },
  {
    "path": "internal/common/types.go",
    "chars": 1105,
    "preview": "package common\n\nimport (\n\t\"os\"\n\t\"runtime\"\n\t\"time\"\n)\n\n// MaxMmapStep is the largest step that can be taken when remapping"
  },
  {
    "path": "internal/common/unsafe.go",
    "chars": 1077,
    "preview": "package common\n\nimport (\n\t\"unsafe\"\n)\n\nfunc UnsafeAdd(base unsafe.Pointer, offset uintptr) unsafe.Pointer {\n\treturn unsaf"
  },
  {
    "path": "internal/common/utils.go",
    "chars": 1513,
    "preview": "package common\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"unsafe\"\n)\n\nfunc LoadBucket(buf []byte) *InBucket {\n\treturn (*InBucket)(uns"
  },
  {
    "path": "internal/common/verify.go",
    "chars": 1822,
    "preview": "// Copied from https://github.com/etcd-io/etcd/blob/main/client/pkg/verify/verify.go\npackage common\n\nimport (\n\t\"fmt\"\n\t\"o"
  },
  {
    "path": "internal/freelist/array.go",
    "chars": 2477,
    "preview": "package freelist\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\ntype array struct {\n\t*shared\n\n\tids []c"
  },
  {
    "path": "internal/freelist/array_test.go",
    "chars": 2348,
    "preview": "package freelist\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.etcd.io/bbolt/internal/co"
  },
  {
    "path": "internal/freelist/freelist.go",
    "chars": 2704,
    "preview": "package freelist\n\nimport (\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\ntype ReadWriter interface {\n\t// Read calls Init with t"
  },
  {
    "path": "internal/freelist/freelist_test.go",
    "chars": 20203,
    "preview": "package freelist\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"os\"\n\t\"reflect\"\n\t\"slices\"\n\t\"sort\"\n\t\"testing\"\n\t\"testing/quick\"\n\t\""
  },
  {
    "path": "internal/freelist/hashmap.go",
    "chars": 7157,
    "preview": "package freelist\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// pidSet holds the set of "
  },
  {
    "path": "internal/freelist/hashmap_test.go",
    "chars": 4654,
    "preview": "package freelist\n\nimport (\n\t\"math/rand\"\n\t\"reflect\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.etcd"
  },
  {
    "path": "internal/freelist/shared.go",
    "chars": 7901,
    "preview": "package freelist\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"unsafe\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\ntype txPending struc"
  },
  {
    "path": "internal/guts_cli/guts_cli.go",
    "chars": 3834,
    "preview": "package guts_cli\n\n// Low level access to pages / data-structures of the bbolt file.\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"o"
  },
  {
    "path": "internal/surgeon/surgeon.go",
    "chars": 4632,
    "preview": "package surgeon\n\nimport (\n\t\"fmt\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n\t\"go.etcd.io/bbolt/internal/guts_cli\"\n)\n\nfunc Copy"
  },
  {
    "path": "internal/surgeon/surgeon_test.go",
    "chars": 1525,
    "preview": "package surgeon_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.e"
  },
  {
    "path": "internal/surgeon/xray.go",
    "chars": 2762,
    "preview": "package surgeon\n\n// Library contains raw access to bbolt files for sake of testing or fixing of corrupted files.\n//\n// T"
  },
  {
    "path": "internal/surgeon/xray_test.go",
    "chars": 1952,
    "preview": "package surgeon_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/re"
  },
  {
    "path": "internal/tests/tx_check_test.go",
    "chars": 3020,
    "preview": "package tests_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.et"
  },
  {
    "path": "logger.go",
    "chars": 2551,
    "preview": "package bbolt\n\n// See https://github.com/etcd-io/raft/blob/main/logger.go\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n)\n\ntype Log"
  },
  {
    "path": "manydbs_test.go",
    "chars": 1281,
    "preview": "package bbolt\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n)\n\nfunc createDb(t *testing.T) (*DB, fun"
  },
  {
    "path": "mlock_unix.go",
    "chars": 699,
    "preview": "//go:build !windows\n\npackage bbolt\n\nimport \"golang.org/x/sys/unix\"\n\n// mlock locks memory of db file\nfunc mlock(db *DB, "
  },
  {
    "path": "mlock_windows.go",
    "chars": 260,
    "preview": "package bbolt\n\n// mlock locks memory of db file\nfunc mlock(_ *DB, _ int) error {\n\tpanic(\"mlock is supported only on UNIX"
  },
  {
    "path": "movebucket_test.go",
    "chars": 12285,
    "preview": "package bbolt_test\n\nimport (\n\tcrand \"crypto/rand\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/"
  },
  {
    "path": "node.go",
    "chars": 14655,
    "preview": "package bbolt\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"sort\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// node represents an in-memory,"
  },
  {
    "path": "node_test.go",
    "chars": 6018,
    "preview": "package bbolt\n\nimport (\n\t\"testing\"\n\t\"unsafe\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// Ensure that a node can insert a "
  },
  {
    "path": "quick_test.go",
    "chars": 2514,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"reflect\"\n\t\"testing\"\n\t\"testing/quick\"\n\t\"time\"\n)"
  },
  {
    "path": "scripts/compare_benchmarks.sh",
    "chars": 2325,
    "preview": "#!/usr/bin/env bash\n# https://github.com/kubernetes/kube-state-metrics/blob/main/tests/compare_benchmarks.sh (originally"
  },
  {
    "path": "scripts/fix.sh",
    "chars": 625,
    "preview": "GO_CMD=\"go\"\n\n# TODO(ptabor): Expand to cover different architectures (GOOS GOARCH), or just list go files.\n\nGOFILES=$(${"
  },
  {
    "path": "scripts/release.sh",
    "chars": 3075,
    "preview": "#!/usr/bin/env bash\n\nset -o errexit\nset -o nounset\nset -o pipefail\n\n# === Function Definitions ===\nfunction get_gpg_key "
  },
  {
    "path": "simulation_no_freelist_sync_test.go",
    "chars": 1721,
    "preview": "package bbolt_test\n\nimport (\n\t\"testing\"\n\n\tbolt \"go.etcd.io/bbolt\"\n)\n\nfunc TestSimulateNoFreeListSync_1op_1p(t *testing.T"
  },
  {
    "path": "simulation_test.go",
    "chars": 8869,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\tbolt \"go.etcd.io/bbolt\"\n\t\""
  },
  {
    "path": "tests/dmflakey/dmflakey.go",
    "chars": 9648,
    "preview": "//go:build linux\n\npackage dmflakey\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"tim"
  },
  {
    "path": "tests/dmflakey/dmflakey_test.go",
    "chars": 4576,
    "preview": "//go:build linux\n\npackage dmflakey\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"tim"
  },
  {
    "path": "tests/dmflakey/dmsetup.go",
    "chars": 3057,
    "preview": "//go:build linux\n\npackage dmflakey\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\n// n"
  },
  {
    "path": "tests/dmflakey/loopback.go",
    "chars": 2337,
    "preview": "//go:build linux\n\npackage dmflakey\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nconst (\n\tloopCo"
  },
  {
    "path": "tests/failpoint/db_failpoint_test.go",
    "chars": 9861,
    "preview": "package failpoint\n\nimport (\n\tcrand \"crypto/rand\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testi"
  },
  {
    "path": "tests/robustness/main_test.go",
    "chars": 208,
    "preview": "//go:build linux\n\npackage robustness\n\nimport (\n\t\"flag\"\n\t\"os\"\n\t\"testing\"\n\n\ttestutils \"go.etcd.io/bbolt/tests/utils\"\n)\n\nfu"
  },
  {
    "path": "tests/robustness/powerfailure_test.go",
    "chars": 8190,
    "preview": "//go:build linux\n\npackage robustness\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"math/big\"\n\t\"net/http\"\n\t\"ne"
  },
  {
    "path": "tests/utils/helpers.go",
    "chars": 450,
    "preview": "package utils\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n)\n\nvar enableRoot bool\n\nfunc init() {\n\tflag.BoolVar(&enableRoot, \"test.root"
  },
  {
    "path": "tx.go",
    "chars": 26484,
    "preview": "package bbolt\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\t\"unsafe\"\n\n\tbe"
  },
  {
    "path": "tx_check.go",
    "chars": 10361,
    "preview": "package bbolt\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// Check performs several consist"
  },
  {
    "path": "tx_check_test.go",
    "chars": 6294,
    "preview": "package bbolt_test\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.etcd.io/bbolt\""
  },
  {
    "path": "tx_stats_test.go",
    "chars": 1462,
    "preview": "package bbolt\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTxStats_add(t *testing.T) "
  },
  {
    "path": "tx_test.go",
    "chars": 26065,
    "preview": "package bbolt_test\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr"
  },
  {
    "path": "unix_test.go",
    "chars": 2427,
    "preview": "//go:build !windows\n\npackage bbolt_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"golang.org/x/sys/unix\"\n\n\tbolt \"go.etcd.io/bbolt\"\n"
  },
  {
    "path": "utils_test.go",
    "chars": 1225,
    "preview": "package bbolt_test\n\nimport (\n\tbolt \"go.etcd.io/bbolt\"\n\t\"go.etcd.io/bbolt/internal/common\"\n)\n\n// `dumpBucket` dumps all t"
  },
  {
    "path": "version/version.go",
    "chars": 110,
    "preview": "package version\n\nvar (\n\t// Version shows the last bbolt binary version released.\n\tVersion = \"1.4.0-alpha.0\"\n)\n"
  }
]

About this extraction

This page contains the full source code of the etcd-io/bbolt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 155 files (734.3 KB), approximately 222.9k tokens, and a symbol index with 1168 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!