github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/modes.go (about) 1 // Copyright 2018 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package libkbfs 6 7 import ( 8 "fmt" 9 "math" 10 "os" 11 "strings" 12 "time" 13 14 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/syndtr/goleveldb/leveldb/opt" 16 ) 17 18 // NewInitModeFromType returns an InitMode object corresponding to the 19 // given type. 20 func NewInitModeFromType(t InitModeType) InitMode { 21 switch t { 22 case InitDefault: 23 return modeDefault{} 24 case InitMinimal: 25 return modeMinimal{} 26 case InitSingleOp: 27 return modeSingleOp{modeDefault{}} 28 case InitConstrained: 29 return modeConstrained{modeDefault{}} 30 case InitMemoryLimited: 31 return modeMemoryLimited{modeConstrained{modeDefault{}}} 32 case InitTestSearch: 33 return modeTestSearch{modeDefault{}} 34 case InitSingleOpWithQR: 35 return modeSingleOpWithQR{modeSingleOp{modeDefault{}}} 36 default: 37 panic(fmt.Sprintf("Unknown mode: %s", t)) 38 } 39 } 40 41 const ( 42 defaultQRPeriod = 1 * time.Hour 43 defaultQRMinUnrefAge = 2 * 7 * 24 * time.Hour // 2 weeks 44 ) 45 46 // Default mode: 47 48 type modeDefault struct { 49 } 50 51 func (md modeDefault) Type() InitModeType { 52 return InitDefault 53 } 54 55 func (md modeDefault) BlockWorkers() int { 56 return defaultBlockRetrievalWorkerQueueSize 57 } 58 59 func (md modeDefault) PrefetchWorkers() int { 60 return defaultPrefetchWorkerQueueSize 61 } 62 63 func (md modeDefault) ThrottledPrefetchPeriod() time.Duration { 64 return defaultThrottledPrefetchPeriod 65 } 66 67 func (md modeDefault) DefaultBlockRequestAction() BlockRequestAction { 68 return BlockRequestWithPrefetch 69 } 70 71 func (md modeDefault) RekeyWorkers() int { 72 return 16 73 } 74 75 func (md modeDefault) RekeyQueueSize() int { 76 return 2048 // 48 KB 77 } 78 79 func (md modeDefault) IsTestMode() bool { 80 return false 81 } 82 83 func (md modeDefault) IsSingleOp() bool { 84 return false 85 } 86 87 func (md modeDefault) DirtyBlockCacheEnabled() bool { 88 return true 89 } 90 91 func (md modeDefault) BackgroundFlushesEnabled() bool { 92 return true 93 } 94 95 func (md modeDefault) MetricsEnabled() bool { 96 return true 97 } 98 99 func (md modeDefault) ConflictResolutionEnabled() bool { 100 return true 101 } 102 103 func (md modeDefault) BlockManagementEnabled() bool { 104 return true 105 } 106 107 func (md modeDefault) MaxBlockPtrsToManageAtOnce() int { 108 return -1 /* unconstrained by default */ 109 } 110 111 func (md modeDefault) QuotaReclamationEnabled() bool { 112 return true 113 } 114 115 func (md modeDefault) QuotaReclamationPeriod() time.Duration { 116 return defaultQRPeriod 117 } 118 119 func (md modeDefault) QuotaReclamationMinUnrefAge() time.Duration { 120 return defaultQRMinUnrefAge 121 } 122 123 func (md modeDefault) QuotaReclamationMinHeadAge() time.Duration { 124 // How old must the most recent TLF revision be before another 125 // device can run QR on that TLF? This is large, to avoid 126 // unnecessary conflicts on the TLF between devices. 127 return defaultQRMinUnrefAge + 24*time.Hour 128 } 129 130 func (md modeDefault) NodeCacheEnabled() bool { 131 return true 132 } 133 134 func (md modeDefault) TLFUpdatesEnabled() bool { 135 return true 136 } 137 138 func (md modeDefault) KBFSServiceEnabled() bool { 139 return true 140 } 141 142 func (md modeDefault) JournalEnabled() bool { 143 return true 144 } 145 146 func (md modeDefault) UnmergedTLFsEnabled() bool { 147 return true 148 } 149 150 func (md modeDefault) ServiceKeepaliveEnabled() bool { 151 return true 152 } 153 154 func (md modeDefault) TLFEditHistoryEnabled() bool { 155 return true 156 } 157 158 func (md modeDefault) SendEditNotificationsEnabled() bool { 159 return true 160 } 161 162 func (md modeDefault) ClientType() keybase1.ClientType { 163 return keybase1.ClientType_KBFS 164 } 165 166 func (md modeDefault) LocalHTTPServerEnabled() bool { 167 return true 168 } 169 170 func (md modeDefault) MaxCleanBlockCacheCapacity() uint64 { 171 return math.MaxUint64 172 } 173 174 func (md modeDefault) OldStorageRootCleaningEnabled() bool { 175 return true 176 } 177 178 func (md modeDefault) DoRefreshFavoritesOnInit() bool { 179 return true 180 } 181 182 func (md modeDefault) DoLogObfuscation() bool { 183 return true 184 } 185 186 func (md modeDefault) BlockTLFEditHistoryIntialization() bool { 187 return false 188 } 189 190 func (md modeDefault) InitialDelayForBackgroundWork() time.Duration { 191 return 0 192 } 193 194 func (md modeDefault) BackgroundWorkPeriod() time.Duration { 195 return 0 196 } 197 198 func (md modeDefault) IndexingEnabled() bool { 199 return false 200 } 201 202 func (md modeDefault) DelayInitialConnect() bool { 203 return false 204 } 205 206 func (md modeDefault) DbWriteBufferSize() int { 207 return 10 * opt.MiB // 10 MB 208 } 209 210 func (md modeDefault) DiskCacheCompactionEnabled() bool { 211 return true 212 } 213 214 func (md modeDefault) EditHistoryPrefetchingEnabled() bool { 215 return false 216 } 217 218 // Minimal mode: 219 220 type modeMinimal struct { 221 } 222 223 func (mm modeMinimal) Type() InitModeType { 224 return InitMinimal 225 } 226 227 func (mm modeMinimal) BlockWorkers() int { 228 // In minimal mode, block re-embedding is not required, so we 229 // don't fetch the unembedded blocks.. 230 return 0 231 } 232 233 func (mm modeMinimal) PrefetchWorkers() int { 234 return 0 235 } 236 237 func (mm modeMinimal) ThrottledPrefetchPeriod() time.Duration { 238 return 0 239 } 240 241 func (mm modeMinimal) DefaultBlockRequestAction() BlockRequestAction { 242 return BlockRequestSolo 243 } 244 245 func (mm modeMinimal) RekeyWorkers() int { 246 return 4 247 } 248 249 func (mm modeMinimal) RekeyQueueSize() int { 250 return 512 // 12 KB 251 } 252 253 func (mm modeMinimal) IsTestMode() bool { 254 return false 255 } 256 257 func (mm modeMinimal) IsSingleOp() bool { 258 return false 259 } 260 261 func (mm modeMinimal) DirtyBlockCacheEnabled() bool { 262 // No blocks will be dirtied in minimal mode, so don't bother with 263 // the dirty block cache. 264 return false 265 } 266 267 func (mm modeMinimal) BackgroundFlushesEnabled() bool { 268 // Don't do background flushes when in minimal mode, since there 269 // shouldn't be any data writes. 270 return false 271 } 272 273 func (mm modeMinimal) MetricsEnabled() bool { 274 return false 275 } 276 277 func (mm modeMinimal) ConflictResolutionEnabled() bool { 278 // No need to run CR if there won't be any data writes on this 279 // device. (There may still be rekey writes, but we don't allow 280 // conflicts to happen in that case.) 281 return false 282 } 283 284 func (mm modeMinimal) BlockManagementEnabled() bool { 285 // If this device is in minimal mode and won't be doing any data 286 // writes, no need deal with block-level cleanup operations. 287 // TODO: in the future it might still be useful to have 288 // e.g. mobile devices doing QR. 289 return false 290 } 291 292 func (mm modeMinimal) MaxBlockPtrsToManageAtOnce() int { 293 panic("Shouldn't be called when block management is disabled") 294 } 295 296 func (mm modeMinimal) QuotaReclamationEnabled() bool { 297 return false 298 } 299 300 func (mm modeMinimal) QuotaReclamationPeriod() time.Duration { 301 return 0 302 } 303 304 func (mm modeMinimal) QuotaReclamationMinUnrefAge() time.Duration { 305 return 0 306 } 307 308 func (mm modeMinimal) QuotaReclamationMinHeadAge() time.Duration { 309 return 0 310 } 311 312 func (mm modeMinimal) NodeCacheEnabled() bool { 313 // If we're in minimal mode, let the node cache remain nil to 314 // ensure that the user doesn't try any data reads or writes. 315 return false 316 } 317 318 func (mm modeMinimal) TLFUpdatesEnabled() bool { 319 return true 320 } 321 322 func (mm modeMinimal) KBFSServiceEnabled() bool { 323 return false 324 } 325 326 func (mm modeMinimal) JournalEnabled() bool { 327 return false 328 } 329 330 func (mm modeMinimal) UnmergedTLFsEnabled() bool { 331 // Writes aren't allowed, so unmerged TLFs on this device 332 // shouldn't be possible. 333 return false 334 } 335 336 func (mm modeMinimal) ServiceKeepaliveEnabled() bool { 337 return false 338 } 339 340 func (mm modeMinimal) TLFEditHistoryEnabled() bool { 341 return false 342 } 343 344 func (mm modeMinimal) SendEditNotificationsEnabled() bool { 345 // Writes aren't allowed, so we shouldn't need to send any. 346 return false 347 } 348 349 func (mm modeMinimal) ClientType() keybase1.ClientType { 350 return keybase1.ClientType_KBFS 351 } 352 353 func (mm modeMinimal) LocalHTTPServerEnabled() bool { 354 return false 355 } 356 357 func (mm modeMinimal) MaxCleanBlockCacheCapacity() uint64 { 358 return math.MaxUint64 359 } 360 361 func (mm modeMinimal) OldStorageRootCleaningEnabled() bool { 362 return false 363 } 364 365 func (mm modeMinimal) DoRefreshFavoritesOnInit() bool { 366 return false 367 } 368 369 func (mm modeMinimal) DoLogObfuscation() bool { 370 return true 371 } 372 373 func (mm modeMinimal) BlockTLFEditHistoryIntialization() bool { 374 // Never used. 375 return false 376 } 377 378 func (mm modeMinimal) InitialDelayForBackgroundWork() time.Duration { 379 // No background work 380 return math.MaxInt64 381 } 382 383 func (mm modeMinimal) BackgroundWorkPeriod() time.Duration { 384 // No background work 385 return math.MaxInt64 386 } 387 388 func (mm modeMinimal) IndexingEnabled() bool { 389 return false 390 } 391 392 func (mm modeMinimal) DelayInitialConnect() bool { 393 return false 394 } 395 396 func (mm modeMinimal) DbWriteBufferSize() int { 397 return 1 * opt.KiB // 1 KB 398 } 399 400 func (mm modeMinimal) DiskCacheCompactionEnabled() bool { 401 return false 402 } 403 404 func (mm modeMinimal) EditHistoryPrefetchingEnabled() bool { 405 return false 406 } 407 408 // Single op mode: 409 410 type modeSingleOp struct { 411 InitMode 412 } 413 414 func (mso modeSingleOp) Type() InitModeType { 415 return InitSingleOp 416 } 417 418 func (mso modeSingleOp) RekeyWorkers() int { 419 // Just block all rekeys and don't bother cleaning up requests 420 // since the process is short lived anyway. 421 return 0 422 } 423 424 func (mso modeSingleOp) RekeyQueueSize() int { 425 return 0 426 } 427 428 func (mso modeSingleOp) QuotaReclamationEnabled() bool { 429 return false 430 } 431 432 func (mso modeSingleOp) QuotaReclamationPeriod() time.Duration { 433 return 0 434 } 435 436 func (mso modeSingleOp) QuotaReclamationMinUnrefAge() time.Duration { 437 return 0 438 } 439 440 func (mso modeSingleOp) QuotaReclamationMinHeadAge() time.Duration { 441 return 0 442 } 443 444 func (mso modeSingleOp) TLFUpdatesEnabled() bool { 445 return false 446 } 447 448 func (mso modeSingleOp) KBFSServiceEnabled() bool { 449 return false 450 } 451 452 func (mso modeSingleOp) UnmergedTLFsEnabled() bool { 453 // There's basically no way for a TLF to start off as unmerged 454 // since single-ops should be using a fresh journal. 455 return false 456 } 457 458 func (mso modeSingleOp) TLFEditHistoryEnabled() bool { 459 return false 460 } 461 462 func (mso modeSingleOp) MetricsEnabled() bool { 463 return false 464 } 465 466 func (mso modeSingleOp) SendEditNotificationsEnabled() bool { 467 // We don't want git, or other single op writes, showing up in the 468 // notification history. 469 return false 470 } 471 472 func (mso modeSingleOp) ClientType() keybase1.ClientType { 473 return keybase1.ClientType_NONE 474 } 475 476 func (mso modeSingleOp) LocalHTTPServerEnabled() bool { 477 return false 478 } 479 480 func (mso modeSingleOp) OldStorageRootCleaningEnabled() bool { 481 return false 482 } 483 484 func (mso modeSingleOp) DoRefreshFavoritesOnInit() bool { 485 return false 486 } 487 488 func (mso modeSingleOp) InitialDelayForBackgroundWork() time.Duration { 489 // No background work 490 return math.MaxInt64 491 } 492 493 func (mso modeSingleOp) BackgroundWorkPeriod() time.Duration { 494 // No background work 495 return math.MaxInt64 496 } 497 498 func (mso modeSingleOp) IsSingleOp() bool { 499 return true 500 } 501 502 func (mso modeSingleOp) DiskCacheCompactionEnabled() bool { 503 return false 504 } 505 506 // Single-op mode with QR: 507 508 type modeSingleOpWithQR struct { 509 modeSingleOp 510 } 511 512 func (msowq modeSingleOpWithQR) QuotaReclamationEnabled() bool { 513 return true 514 } 515 516 func (msowq modeSingleOpWithQR) QuotaReclamationPeriod() time.Duration { 517 // We might end up needing to make this much shorter, because it 518 // can take a while to get through all the revisions. But for now 519 // I want to make sure it doesn't wake up too often and cause too 520 // much CPU. 521 return 1 * time.Minute 522 } 523 524 func (msowq modeSingleOpWithQR) QuotaReclamationMinUnrefAge() time.Duration { 525 return 1 * time.Minute 526 } 527 528 func (msowq modeSingleOpWithQR) QuotaReclamationMinHeadAge() time.Duration { 529 // In the case of indexing, another device will never run QR on 530 // the TLFs in question, but might as well set it to something... 531 return 2 * time.Minute 532 } 533 534 // Constrained mode: 535 536 type modeConstrained struct { 537 InitMode 538 } 539 540 func (mc modeConstrained) Type() InitModeType { 541 return InitConstrained 542 } 543 544 func (mc modeConstrained) BlockWorkers() int { 545 return 1 546 } 547 548 func (mc modeConstrained) PrefetchWorkers() int { 549 return 1 550 } 551 552 func (mc modeConstrained) DefaultBlockRequestAction() BlockRequestAction { 553 return BlockRequestSolo 554 } 555 556 func (mc modeConstrained) RekeyWorkers() int { 557 return 4 558 } 559 560 func (mc modeConstrained) RekeyQueueSize() int { 561 return 1024 // 24 KB 562 } 563 564 func (mc modeConstrained) BackgroundFlushesEnabled() bool { 565 return true 566 } 567 568 func (mc modeConstrained) ConflictResolutionEnabled() bool { 569 return true 570 } 571 572 func (mc modeConstrained) MaxBlockPtrsToManageAtOnce() int { 573 return 10000 574 } 575 576 func (mc modeConstrained) QuotaReclamationEnabled() bool { 577 return true 578 } 579 580 func (mc modeConstrained) QuotaReclamationPeriod() time.Duration { 581 return defaultQRPeriod 582 } 583 584 func (mc modeConstrained) QuotaReclamationMinUnrefAge() time.Duration { 585 return defaultQRMinUnrefAge 586 } 587 588 func (mc modeConstrained) QuotaReclamationMinHeadAge() time.Duration { 589 // Don't ever run QR in constrained mode unless this device was 590 // the most recent writer. 591 return 0 592 } 593 594 func (mc modeConstrained) KBFSServiceEnabled() bool { 595 return false 596 } 597 598 func (mc modeConstrained) JournalEnabled() bool { 599 return true 600 } 601 602 func (mc modeConstrained) UnmergedTLFsEnabled() bool { 603 return true 604 } 605 606 func (mc modeConstrained) ServiceKeepaliveEnabled() bool { 607 return false 608 } 609 610 func (mc modeConstrained) TLFEditHistoryEnabled() bool { 611 return true 612 } 613 614 func (mc modeConstrained) SendEditNotificationsEnabled() bool { 615 return true 616 } 617 618 func (mc modeConstrained) LocalHTTPServerEnabled() bool { 619 return true 620 } 621 622 func (mc modeConstrained) BlockTLFEditHistoryIntialization() bool { 623 // In constrained mode, we don't want to incur this work in the 624 // background when it might interfere with other foreground tasks. 625 // Instead, make requests that depend on the edit history block 626 // and effectively foreground that initialization work. 627 return true 628 } 629 630 func (mc modeConstrained) InitialDelayForBackgroundWork() time.Duration { 631 return 10 * time.Second 632 } 633 634 func (mc modeConstrained) BackgroundWorkPeriod() time.Duration { 635 return 5 * time.Second 636 } 637 638 func (mc modeConstrained) DelayInitialConnect() bool { 639 return true 640 } 641 642 func (mc modeConstrained) DbWriteBufferSize() int { 643 return 100 * opt.KiB // 100 KB 644 } 645 646 func (mc modeConstrained) DiskCacheCompactionEnabled() bool { 647 return false 648 } 649 650 // Memory limited mode 651 652 type modeMemoryLimited struct { 653 InitMode 654 } 655 656 func (mml modeMemoryLimited) Type() InitModeType { 657 return InitMemoryLimited 658 } 659 660 func (mml modeMemoryLimited) RekeyWorkers() int { 661 return 0 662 } 663 664 func (mml modeMemoryLimited) RekeyQueueSize() int { 665 return 0 666 } 667 668 func (mml modeMemoryLimited) ConflictResolutionEnabled() bool { 669 return false 670 } 671 672 func (mml modeMemoryLimited) QuotaReclamationEnabled() bool { 673 return false 674 } 675 676 func (mml modeMemoryLimited) UnmergedTLFsEnabled() bool { 677 return false 678 } 679 680 func (mml modeMemoryLimited) SendEditNotificationsEnabled() bool { 681 return false 682 } 683 684 func (mml modeMemoryLimited) LocalHTTPServerEnabled() bool { 685 return false 686 } 687 688 func (mml modeMemoryLimited) MaxCleanBlockCacheCapacity() uint64 { 689 return 1 * (1 << 20) // 1 MB 690 } 691 692 func (mml modeMemoryLimited) TLFEditHistoryEnabled() bool { 693 return false 694 } 695 696 func (mml modeMemoryLimited) DbWriteBufferSize() int { 697 return 1 * opt.KiB // 1 KB 698 } 699 700 type modeTestSearch struct { 701 InitMode 702 } 703 704 func (mts modeTestSearch) IndexingEnabled() bool { 705 return true 706 } 707 708 func (mts modeTestSearch) InitialDelayForBackgroundWork() time.Duration { 709 // Delay background work like loading the synced TLFs, until the 710 // indexer has registered to receive notifications about them. 711 return 5 * time.Second 712 } 713 714 func (mts modeTestSearch) DelayInitialConnect() bool { 715 return false 716 } 717 718 // Wrapper for tests. 719 720 type modeTest struct { 721 InitMode 722 } 723 724 func (mt modeTest) IsTestMode() bool { 725 return true 726 } 727 728 func (mt modeTest) QuotaReclamationPeriod() time.Duration { 729 // No auto-reclamation during testing. 730 return 0 731 } 732 733 func (mt modeTest) QuotaReclamationMinUnrefAge() time.Duration { 734 // Smaller archival window by default during testing, for 735 // backwards compatibility with old tests. 736 return 1 * time.Minute 737 } 738 739 func (mt modeTest) QuotaReclamationMinHeadAge() time.Duration { 740 // No min head age during testing. 741 return 0 742 } 743 744 // EnvKeybaseTestObfuscateLogsForTest is "KEYBASE_TEST_OBFUSCATE_LOGS" and used 745 // to specify if log obfuscation should be enabled for test. 746 const EnvKeybaseTestObfuscateLogsForTest = "KEYBASE_TEST_OBFUSCATE_LOGS" 747 748 func (mt modeTest) DoLogObfuscation() bool { 749 e := os.Getenv(EnvKeybaseTestObfuscateLogsForTest) 750 return e != "" && e != "0" && strings.ToLower(e) != "false" 751 }