github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/bserver_remote.go (about) 1 // Copyright 2016 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 "sync" 9 "time" 10 11 "github.com/keybase/backoff" 12 "github.com/keybase/client/go/kbfs/idutil" 13 "github.com/keybase/client/go/kbfs/kbfsblock" 14 "github.com/keybase/client/go/kbfs/kbfscrypto" 15 "github.com/keybase/client/go/kbfs/tlf" 16 "github.com/keybase/client/go/libkb" 17 "github.com/keybase/client/go/logger" 18 "github.com/keybase/client/go/protocol/keybase1" 19 "github.com/keybase/go-framed-msgpack-rpc/rpc" 20 "github.com/pkg/errors" 21 "golang.org/x/net/context" 22 ) 23 24 const ( 25 // BServerDefaultPingIntervalSeconds is the default interval on which the 26 // client should contact the block server. 27 BServerDefaultPingIntervalSeconds = 10 28 // BServerPingTimeout is how long to wait for a ping response 29 // before breaking the connection and trying to reconnect. 30 BServerPingTimeout = 30 * time.Second 31 ) 32 33 // blockServerRemoteAuthTokenRefresher is a helper struct for 34 // refreshing auth tokens and managing connections. 35 type blockServerRemoteClientHandler struct { 36 kbCtx Context 37 name string 38 log logger.Logger 39 deferLog logger.Logger 40 csg idutil.CurrentSessionGetter 41 authToken *kbfscrypto.AuthToken 42 srvRemote rpc.Remote 43 connOpts rpc.ConnectionOpts 44 rpcLogFactory rpc.LogFactory 45 pinger pinger 46 47 connMu sync.RWMutex 48 conn *rpc.Connection 49 client keybase1.BlockInterface 50 } 51 52 func newBlockServerRemoteClientHandler( 53 kbCtx Context, initMode InitMode, name string, log logger.Logger, 54 signer kbfscrypto.Signer, csg idutil.CurrentSessionGetter, 55 srvRemote rpc.Remote, 56 rpcLogFactory rpc.LogFactory) *blockServerRemoteClientHandler { 57 deferLog := log.CloneWithAddedDepth(1) 58 b := &blockServerRemoteClientHandler{ 59 name: name, 60 log: log, 61 deferLog: deferLog, 62 csg: csg, 63 srvRemote: srvRemote, 64 rpcLogFactory: rpcLogFactory, 65 kbCtx: kbCtx, 66 } 67 68 b.pinger = pinger{ 69 name: name, 70 doPing: b.pingOnce, 71 timeout: BServerPingTimeout, 72 log: log, 73 } 74 75 b.authToken = kbfscrypto.NewAuthToken( 76 signer, kbfsblock.ServerTokenServer, kbfsblock.ServerTokenExpireIn, 77 "libkbfs_bserver_remote", VersionString(), b) 78 79 constBackoff := backoff.NewConstantBackOff(RPCReconnectInterval) 80 firstConnectDelay := time.Duration(0) 81 if initMode.DelayInitialConnect() { 82 firstConnectDelay = libkb.RandomJitter(bserverFirstConnectDelay) 83 } 84 b.connOpts = rpc.ConnectionOpts{ 85 DontConnectNow: true, // connect only on-demand 86 WrapErrorFunc: libkb.WrapError, 87 TagsFunc: libkb.LogTagsFromContext, 88 ReconnectBackoff: func() backoff.BackOff { return constBackoff }, 89 DialerTimeout: dialerTimeout, 90 FirstConnectDelayDuration: firstConnectDelay, 91 InitialReconnectBackoffWindow: func() time.Duration { return bserverReconnectBackoffWindow }, 92 } 93 b.initNewConnection() 94 return b 95 } 96 97 func (b *blockServerRemoteClientHandler) initNewConnection() { 98 b.connMu.Lock() 99 defer b.connMu.Unlock() 100 101 if b.conn != nil { 102 b.conn.Shutdown() 103 } 104 105 b.conn = rpc.NewTLSConnectionWithDialable( 106 b.srvRemote, kbfscrypto.GetRootCerts( 107 b.srvRemote.Peek(), libkb.GetBundledCAsFromHost), 108 kbfsblock.ServerErrorUnwrapper{}, b, b.rpcLogFactory, 109 b.kbCtx.NewNetworkInstrumenter(keybase1.NetworkSource_REMOTE), 110 logger.LogOutputWithDepthAdder{Logger: b.log}, 111 rpc.DefaultMaxFrameLength, b.connOpts, 112 libkb.NewProxyDialable(b.kbCtx.GetEnv())) 113 b.client = keybase1.BlockClient{Cli: b.conn.GetClient()} 114 } 115 116 func (b *blockServerRemoteClientHandler) reconnect() error { 117 b.connMu.Lock() 118 defer b.connMu.Unlock() 119 120 if b.conn != nil { 121 ctx, cancel := context.WithTimeout( 122 context.Background(), reconnectTimeout) 123 defer cancel() 124 return b.conn.ForceReconnect(ctx) 125 } 126 127 b.initNewConnection() 128 return nil 129 130 } 131 132 func (b *blockServerRemoteClientHandler) shutdown() { 133 if b.authToken != nil { 134 b.authToken.Shutdown() 135 } 136 137 b.connMu.Lock() 138 defer b.connMu.Unlock() 139 140 if b.conn != nil { 141 b.conn.Shutdown() 142 } 143 144 // cancel the ping ticker 145 b.pinger.cancelTicker() 146 } 147 148 func (b *blockServerRemoteClientHandler) getClient() keybase1.BlockInterface { 149 b.connMu.RLock() 150 defer b.connMu.RUnlock() 151 return b.client 152 } 153 154 type ctxBServerResetKeyType int 155 156 const ( 157 // ctxBServerResetKey identifies whether the current context has 158 // already passed through `BServerRemote.resetAuth`. 159 ctxBServerResetKey ctxBServerResetKeyType = iota 160 ) 161 162 // resetAuth is called to reset the authorization on a BlockServer 163 // connection. 164 func (b *blockServerRemoteClientHandler) resetAuth( 165 ctx context.Context, c keybase1.BlockInterface) (err error) { 166 ctx = context.WithValue(ctx, ctxBServerResetKey, b.name) 167 168 defer func() { 169 b.deferLog.CDebugf( 170 ctx, "BlockServerRemote: resetAuth called, err: %#v", err) 171 }() 172 173 session, err := b.csg.GetCurrentSession(ctx) 174 if err != nil { 175 b.log.CDebugf( 176 ctx, "%s: User logged out, skipping resetAuth", b.name) 177 return nil 178 } 179 180 _, hasDeadline := ctx.Deadline() 181 if !hasDeadline { 182 var cancel context.CancelFunc 183 ctx, cancel = context.WithTimeout(ctx, reconnectTimeout) 184 defer cancel() 185 } 186 187 // request a challenge 188 challenge, err := c.GetSessionChallenge(ctx) 189 if err != nil { 190 return err 191 } 192 193 // get a new signature 194 signature, err := b.authToken.Sign(ctx, session.Name, 195 session.UID, session.VerifyingKey, challenge) 196 if err != nil { 197 return err 198 } 199 200 return c.AuthenticateSession(ctx, signature) 201 } 202 203 // RefreshAuthToken implements the AuthTokenRefreshHandler interface. 204 func (b *blockServerRemoteClientHandler) RefreshAuthToken( 205 ctx context.Context) { 206 if v := ctx.Value(ctxBServerResetKey); v == b.name { 207 b.log.CDebugf(ctx, "Avoiding resetAuth recursion") 208 return 209 } 210 211 if err := b.resetAuth(ctx, b.client); err != nil { 212 b.log.CDebugf(ctx, "%s: error refreshing auth token: %v", b.name, err) 213 } 214 } 215 216 var _ kbfscrypto.AuthTokenRefreshHandler = (*blockServerRemoteClientHandler)(nil) 217 218 // HandlerName implements the ConnectionHandler interface. 219 func (b *blockServerRemoteClientHandler) HandlerName() string { 220 return b.name 221 } 222 223 // OnConnect implements the ConnectionHandler interface. 224 func (b *blockServerRemoteClientHandler) OnConnect(ctx context.Context, 225 conn *rpc.Connection, client rpc.GenericClient, _ *rpc.Server) error { 226 // reset auth -- using client here would cause problematic recursion. 227 c := keybase1.BlockClient{Cli: client} 228 err := b.resetAuth(ctx, c) 229 if err != nil { 230 return err 231 } 232 233 // Start pinging. 234 b.pinger.resetTicker(BServerDefaultPingIntervalSeconds) 235 return nil 236 } 237 238 // OnConnectError implements the ConnectionHandler interface. 239 func (b *blockServerRemoteClientHandler) OnConnectError(err error, wait time.Duration) { 240 b.log.Warning("%s: connection error: %v; retrying in %s", b.name, err, wait) 241 if b.authToken != nil { 242 b.authToken.Shutdown() 243 } 244 b.pinger.cancelTicker() 245 // TODO: it might make sense to show something to the user if this is 246 // due to authentication, for example. 247 } 248 249 // OnDoCommandError implements the ConnectionHandler interface. 250 func (b *blockServerRemoteClientHandler) OnDoCommandError(err error, wait time.Duration) { 251 b.log.Warning("%s: DoCommand error: %v; retrying in %s", b.name, err, wait) 252 } 253 254 // OnDisconnected implements the ConnectionHandler interface. 255 func (b *blockServerRemoteClientHandler) OnDisconnected(ctx context.Context, 256 status rpc.DisconnectStatus) { 257 if status == rpc.StartingNonFirstConnection { 258 b.log.CWarningf(ctx, "%s: disconnected", b.name) 259 } 260 if b.authToken != nil { 261 b.authToken.Shutdown() 262 } 263 b.pinger.cancelTicker() 264 } 265 266 // ShouldRetry implements the ConnectionHandler interface. 267 func (b *blockServerRemoteClientHandler) ShouldRetry(rpcName string, err error) bool { 268 // Do not let connection.go's DoCommand retry any batch rpcs 269 // since batchDowngradeReferences already handles retries. 270 switch rpcName { 271 case "keybase.1.block.delReferenceWithCount": 272 return false 273 case "keybase.1.block.archiveReferenceWithCount": 274 return false 275 } 276 return kbfsblock.IsThrottleError(err) 277 } 278 279 // ShouldRetryOnConnect implements the ConnectionHandler interface. 280 func (b *blockServerRemoteClientHandler) ShouldRetryOnConnect(err error) bool { 281 _, inputCanceled := err.(libkb.InputCanceledError) 282 return !inputCanceled 283 } 284 285 var _ rpc.ConnectionHandler = (*blockServerRemoteClientHandler)(nil) 286 287 func (b *blockServerRemoteClientHandler) pingOnce(ctx context.Context) { 288 _, err := b.getClient().BlockPing(ctx) 289 if err == context.DeadlineExceeded { 290 b.log.CDebugf( 291 ctx, "%s: Ping timeout -- reinitializing connection", b.name) 292 if err = b.reconnect(); err != nil { 293 b.log.CDebugf(ctx, "reconnect error: %v", err) 294 } 295 } else if err != nil { 296 b.log.CDebugf(ctx, "%s: ping error %s", b.name, err) 297 } 298 } 299 300 func (b *blockServerRemoteClientHandler) fastForwardBackoff() { 301 b.connMu.RLock() 302 defer b.connMu.RUnlock() 303 b.conn.FastForwardConnectDelayTimer() 304 } 305 306 type blockServerRemoteConfig interface { 307 diskBlockCacheGetter 308 codecGetter 309 signerGetter 310 currentSessionGetterGetter 311 logMaker 312 initModeGetter 313 } 314 315 // BlockServerRemote implements the BlockServer interface and 316 // represents a remote KBFS block server. 317 type BlockServerRemote struct { 318 config blockServerRemoteConfig 319 shutdownFn func() 320 log traceLogger 321 deferLog traceLogger 322 blkSrvRemote rpc.Remote 323 324 putConn *blockServerRemoteClientHandler 325 getConn *blockServerRemoteClientHandler 326 } 327 328 // Test that BlockServerRemote fully implements the BlockServer interface. 329 var _ BlockServer = (*BlockServerRemote)(nil) 330 331 // NewBlockServerRemote constructs a new BlockServerRemote for the 332 // given address. 333 func NewBlockServerRemote(kbCtx Context, config blockServerRemoteConfig, 334 blkSrvRemote rpc.Remote, rpcLogFactory rpc.LogFactory) *BlockServerRemote { 335 log := config.MakeLogger("BSR") 336 deferLog := log.CloneWithAddedDepth(1) 337 bs := &BlockServerRemote{ 338 config: config, 339 log: traceLogger{log}, 340 deferLog: traceLogger{deferLog}, 341 blkSrvRemote: blkSrvRemote, 342 } 343 // Use two separate auth clients -- one for writes and one for 344 // reads. This allows small reads to avoid getting trapped behind 345 // large asynchronous writes. TODO: use some real network QoS to 346 // achieve better prioritization within the actual network. 347 bs.putConn = newBlockServerRemoteClientHandler(kbCtx, config.Mode(), 348 "BlockServerRemotePut", log, config.Signer(), 349 config.CurrentSessionGetter(), blkSrvRemote, rpcLogFactory) 350 bs.getConn = newBlockServerRemoteClientHandler(kbCtx, config.Mode(), 351 "BlockServerRemoteGet", log, config.Signer(), 352 config.CurrentSessionGetter(), blkSrvRemote, rpcLogFactory) 353 354 bs.shutdownFn = func() { 355 bs.putConn.shutdown() 356 bs.getConn.shutdown() 357 } 358 return bs 359 } 360 361 // For testing. 362 func newBlockServerRemoteWithClient(kbCtx Context, config blockServerRemoteConfig, 363 client keybase1.BlockInterface) *BlockServerRemote { 364 log := config.MakeLogger("BSR") 365 deferLog := log.CloneWithAddedDepth(1) 366 bs := &BlockServerRemote{ 367 config: config, 368 log: traceLogger{log}, 369 deferLog: traceLogger{deferLog}, 370 putConn: &blockServerRemoteClientHandler{ 371 log: log, 372 deferLog: deferLog, 373 client: client, 374 kbCtx: kbCtx, 375 }, 376 getConn: &blockServerRemoteClientHandler{ 377 log: log, 378 deferLog: deferLog, 379 client: client, 380 kbCtx: kbCtx, 381 }, 382 } 383 return bs 384 } 385 386 // FastForwardBackoff implements the BlockServerinterface for 387 // BlockServerRemote. 388 func (b *BlockServerRemote) FastForwardBackoff() { 389 b.getConn.fastForwardBackoff() 390 b.putConn.fastForwardBackoff() 391 } 392 393 // RemoteAddress returns the remote bserver this client is talking to 394 func (b *BlockServerRemote) RemoteAddress() string { 395 return b.blkSrvRemote.String() 396 } 397 398 // RefreshAuthToken implements the AuthTokenRefreshHandler interface. 399 func (b *BlockServerRemote) RefreshAuthToken(ctx context.Context) { 400 b.putConn.RefreshAuthToken(ctx) 401 b.getConn.RefreshAuthToken(ctx) 402 } 403 404 // Get implements the BlockServer interface for BlockServerRemote. 405 func (b *BlockServerRemote) Get( 406 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 407 context kbfsblock.Context, cacheType DiskBlockCacheType) ( 408 buf []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf, err error) { 409 ctx = rpc.WithFireNow(ctx) 410 var res keybase1.GetBlockRes 411 b.log.LazyTrace(ctx, "BServer: Get %s", id) 412 413 // Once the block has been retrieved, cache it. 414 defer func() { 415 b.log.LazyTrace(ctx, "BServer: Get %s done (err=%v)", id, err) 416 if err != nil { 417 b.deferLog.CWarningf( 418 ctx, "Get id=%s tlf=%s context=%s sz=%d err=%v", 419 id, tlfID, context, len(buf), err) 420 } else { 421 // But don't cache it if it's archived data, except if 422 // it's going to the sync cache. Blocks marked for the 423 // sync cache must be cached, otherwise prefetching will 424 // never complete. 425 if res.Status == keybase1.BlockStatus_ARCHIVED && 426 cacheType != DiskBlockSyncCache { 427 return 428 } 429 430 b.deferLog.CDebugf( 431 ctx, "Get id=%s tlf=%s context=%s sz=%d", 432 id, tlfID, context, len(buf)) 433 dbc := b.config.DiskBlockCache() 434 if dbc != nil { 435 // This used to be called in a goroutine to prevent 436 // blocking the `Get`. But we need this cached 437 // synchronously so prefetch operations can work 438 // correctly. No need to log an error since `dbc` 439 // will already log it. 440 _ = dbc.Put(ctx, tlfID, id, buf, serverHalf, cacheType) 441 } 442 } 443 }() 444 445 arg := kbfsblock.MakeGetBlockArg(tlfID, id, context) 446 res, err = b.getConn.getClient().GetBlock(ctx, arg) 447 return kbfsblock.ParseGetBlockRes(res, err) 448 } 449 450 // GetEncodedSizes implements the BlockServer interface for BlockServerRemote. 451 func (b *BlockServerRemote) GetEncodedSizes( 452 ctx context.Context, tlfID tlf.ID, ids []kbfsblock.ID, 453 contexts []kbfsblock.Context) ( 454 sizes []uint32, statuses []keybase1.BlockStatus, err error) { 455 ctx = rpc.WithFireNow(ctx) 456 b.log.LazyTrace(ctx, "BServer: GetEncodedSizes %s", ids) 457 defer func() { 458 b.log.LazyTrace( 459 ctx, "BServer: GetEncodedSizes %s done (err=%v)", ids, err) 460 if err != nil { 461 b.deferLog.CWarningf( 462 ctx, "GetEncodedSizes ids=%s tlf=%s contexts=%s err=%v", 463 ids, tlfID, contexts, err) 464 } else { 465 b.deferLog.CDebugf( 466 ctx, "GetEncodedSizes ids=%s tlf=%s contexts=%s "+ 467 "szs=%d statuses=%s", 468 ids, tlfID, contexts, sizes, statuses) 469 } 470 }() 471 472 arg, err := kbfsblock.MakeGetBlockSizesArg(tlfID, ids, contexts) 473 if err != nil { 474 return nil, nil, err 475 } 476 res, err := b.getConn.getClient().GetBlockSizes(ctx, arg) 477 if err != nil { 478 return nil, nil, err 479 } 480 if len(res.Sizes) != len(res.Statuses) { 481 return nil, nil, errors.Errorf( 482 "Unexpected return param slice size difference: "+ 483 "len(sizes)=%d != len(statuses)=%d", 484 len(res.Sizes), len(res.Statuses)) 485 } 486 sizes = make([]uint32, len(res.Sizes)) 487 for i, size := range res.Sizes { 488 sizes[i] = uint32(size) 489 } 490 return sizes, res.Statuses, nil 491 } 492 493 // Put implements the BlockServer interface for BlockServerRemote. 494 func (b *BlockServerRemote) Put( 495 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 496 bContext kbfsblock.Context, buf []byte, 497 serverHalf kbfscrypto.BlockCryptKeyServerHalf, 498 cacheType DiskBlockCacheType) (err error) { 499 ctx = rpc.WithFireNow(ctx) 500 dbc := b.config.DiskBlockCache() 501 if dbc != nil { 502 err := dbc.Put(ctx, tlfID, id, buf, serverHalf, cacheType) 503 if err != nil { 504 return err 505 } 506 } 507 size := len(buf) 508 b.log.LazyTrace(ctx, "BServer: Put %s", id) 509 defer func() { 510 b.log.LazyTrace(ctx, "BServer: Put %s done (err=%v)", id, err) 511 if err != nil { 512 b.deferLog.CWarningf( 513 ctx, "Put id=%s tlf=%s context=%s sz=%d err=%v", 514 id, tlfID, bContext, size, err) 515 } else { 516 b.deferLog.CDebugf( 517 ctx, "Put id=%s tlf=%s context=%s sz=%d", 518 id, tlfID, bContext, size) 519 } 520 }() 521 522 arg := kbfsblock.MakePutBlockArg(tlfID, id, bContext, buf, serverHalf) 523 // Handle OverQuota errors at the caller 524 return b.putConn.getClient().PutBlock(ctx, arg) 525 } 526 527 // PutAgain implements the BlockServer interface for BlockServerRemote 528 func (b *BlockServerRemote) PutAgain( 529 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 530 bContext kbfsblock.Context, buf []byte, 531 serverHalf kbfscrypto.BlockCryptKeyServerHalf, 532 cacheType DiskBlockCacheType) (err error) { 533 ctx = rpc.WithFireNow(ctx) 534 dbc := b.config.DiskBlockCache() 535 if dbc != nil { 536 err := dbc.Put(ctx, tlfID, id, buf, serverHalf, cacheType) 537 if err != nil { 538 return err 539 } 540 } 541 size := len(buf) 542 b.log.LazyTrace(ctx, "BServer: Put %s", id) 543 defer func() { 544 b.log.LazyTrace(ctx, "BServer: Put %s done (err=%v)", id, err) 545 if err != nil { 546 b.deferLog.CWarningf( 547 ctx, "Put id=%s tlf=%s context=%s sz=%d err=%v", 548 id, tlfID, bContext, size, err) 549 } else { 550 b.deferLog.CDebugf( 551 ctx, "Put id=%s tlf=%s context=%s sz=%d", 552 id, tlfID, bContext, size) 553 } 554 }() 555 556 arg := kbfsblock.MakePutBlockAgainArg(tlfID, id, bContext, buf, serverHalf) 557 // Handle OverQuota errors at the caller 558 return b.putConn.getClient().PutBlockAgain(ctx, arg) 559 } 560 561 // AddBlockReference implements the BlockServer interface for BlockServerRemote 562 func (b *BlockServerRemote) AddBlockReference(ctx context.Context, tlfID tlf.ID, 563 id kbfsblock.ID, context kbfsblock.Context) (err error) { 564 ctx = rpc.WithFireNow(ctx) 565 b.log.LazyTrace(ctx, "BServer: AddRef %s", id) 566 defer func() { 567 b.log.LazyTrace(ctx, "BServer: AddRef %s done (err=%v)", id, err) 568 if err != nil { 569 b.deferLog.CWarningf( 570 ctx, "AddBlockReference id=%s tlf=%s context=%s err=%v", 571 id, tlfID, context, err) 572 } else { 573 b.deferLog.CDebugf( 574 ctx, "AddBlockReference id=%s tlf=%s context=%s", 575 id, tlfID, context) 576 } 577 }() 578 579 arg := kbfsblock.MakeAddReferenceArg(tlfID, id, context) 580 // Handle OverQuota errors at the caller 581 return b.putConn.getClient().AddReference(ctx, arg) 582 } 583 584 // RemoveBlockReferences implements the BlockServer interface for 585 // BlockServerRemote 586 func (b *BlockServerRemote) RemoveBlockReferences(ctx context.Context, 587 tlfID tlf.ID, contexts kbfsblock.ContextMap) (liveCounts map[kbfsblock.ID]int, err error) { 588 ctx = rpc.WithFireNow(ctx) 589 // TODO: Define a more compact printout of contexts. 590 b.log.LazyTrace(ctx, "BServer: RemRef %v", contexts) 591 defer func() { 592 b.log.LazyTrace(ctx, "BServer: RemRef %v done (err=%v)", contexts, err) 593 if err != nil { 594 b.deferLog.CWarningf(ctx, "RemoveBlockReferences batch size=%d err=%v", len(contexts), err) 595 } else { 596 b.deferLog.CDebugf(ctx, "RemoveBlockReferences batch size=%d", len(contexts)) 597 } 598 }() 599 doneRefs, err := kbfsblock.BatchDowngradeReferences(ctx, b.log, tlfID, contexts, false, b.putConn.getClient()) 600 return kbfsblock.GetLiveCounts(doneRefs), err 601 } 602 603 // ArchiveBlockReferences implements the BlockServer interface for 604 // BlockServerRemote 605 func (b *BlockServerRemote) ArchiveBlockReferences(ctx context.Context, 606 tlfID tlf.ID, contexts kbfsblock.ContextMap) (err error) { 607 ctx = rpc.WithFireNow(ctx) 608 b.log.LazyTrace(ctx, "BServer: ArchiveRef %v", contexts) 609 defer func() { 610 b.log.LazyTrace(ctx, "BServer: ArchiveRef %v done (err=%v)", contexts, err) 611 if err != nil { 612 b.deferLog.CWarningf(ctx, "ArchiveBlockReferences batch size=%d err=%v", len(contexts), err) 613 } else { 614 b.deferLog.CDebugf(ctx, "ArchiveBlockReferences batch size=%d", len(contexts)) 615 } 616 }() 617 _, err = kbfsblock.BatchDowngradeReferences(ctx, b.log, tlfID, contexts, true, b.putConn.getClient()) 618 return err 619 } 620 621 // GetLiveBlockReferences implements the BlockServer interface for 622 // BlockServerRemote. 623 func (b *BlockServerRemote) GetLiveBlockReferences( 624 ctx context.Context, tlfID tlf.ID, contexts kbfsblock.ContextMap) ( 625 liveCounts map[kbfsblock.ID]int, err error) { 626 return kbfsblock.GetReferenceCount( 627 ctx, tlfID, contexts, keybase1.BlockStatus_LIVE, b.getConn.getClient()) 628 } 629 630 // IsUnflushed implements the BlockServer interface for BlockServerRemote. 631 func (b *BlockServerRemote) IsUnflushed( 632 _ context.Context, _ tlf.ID, _ kbfsblock.ID) ( 633 bool, error) { 634 return false, nil 635 } 636 637 // GetUserQuotaInfo implements the BlockServer interface for BlockServerRemote 638 func (b *BlockServerRemote) GetUserQuotaInfo(ctx context.Context) (info *kbfsblock.QuotaInfo, err error) { 639 // This method called when kbfs process starts up. So if 640 // DelayInitialConnect() is set for the mode (usually means we're on 641 // mobile), don't set "fire now" in context, to avoid unintionally fast 642 // forwarding the delay timer for connecting to bserver. 643 if !b.config.Mode().DelayInitialConnect() { 644 ctx = rpc.WithFireNow(ctx) 645 } 646 b.log.LazyTrace(ctx, "BServer: GetUserQuotaInfo") 647 defer func() { 648 b.log.LazyTrace(ctx, "BServer: GetUserQuotaInfo done (err=%v)", err) 649 }() 650 res, err := b.getConn.getClient().GetUserQuotaInfo2( 651 ctx, false /* no TLFs */) 652 if err != nil { 653 return nil, err 654 } 655 return kbfsblock.QuotaInfoFromProtocol(res), nil 656 } 657 658 // GetTeamQuotaInfo implements the BlockServer interface for BlockServerRemote 659 func (b *BlockServerRemote) GetTeamQuotaInfo( 660 ctx context.Context, tid keybase1.TeamID) ( 661 info *kbfsblock.QuotaInfo, err error) { 662 ctx = rpc.WithFireNow(ctx) 663 b.log.LazyTrace(ctx, "BServer: GetTeamQuotaInfo") 664 defer func() { 665 b.log.LazyTrace(ctx, "BServer: GetTeamQuotaInfo done (err=%v)", err) 666 }() 667 arg := keybase1.GetTeamQuotaInfo2Arg{ 668 Tid: tid, 669 IncludeFolders: false, 670 } 671 res, err := b.getConn.getClient().GetTeamQuotaInfo2(ctx, arg) 672 if err != nil { 673 return nil, err 674 } 675 return kbfsblock.QuotaInfoFromProtocol(res), nil 676 } 677 678 // Shutdown implements the BlockServer interface for BlockServerRemote. 679 func (b *BlockServerRemote) Shutdown(ctx context.Context) { 680 if b.shutdownFn != nil { 681 b.shutdownFn() 682 } 683 b.getConn.shutdown() 684 b.putConn.shutdown() 685 }