github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/block_ops.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 "time" 9 10 "github.com/keybase/client/go/kbfs/data" 11 "github.com/keybase/client/go/kbfs/env" 12 "github.com/keybase/client/go/kbfs/kbfsblock" 13 "github.com/keybase/client/go/kbfs/libkey" 14 "github.com/keybase/client/go/kbfs/tlf" 15 "github.com/keybase/client/go/protocol/keybase1" 16 "github.com/pkg/errors" 17 "golang.org/x/net/context" 18 ) 19 20 type blockOpsConfig interface { 21 data.Versioner 22 logMaker 23 blockCacher 24 blockServerGetter 25 codecGetter 26 cryptoPureGetter 27 keyGetterGetter 28 diskBlockCacheGetter 29 syncedTlfGetterSetter 30 initModeGetter 31 blockCryptVersioner 32 clockGetter 33 reporterGetter 34 settingsDBGetter 35 subscriptionManagerGetter 36 subscriptionManagerPublisherGetter 37 } 38 39 // BlockOpsStandard implements the BlockOps interface by relaying 40 // requests to the block server. 41 type BlockOpsStandard struct { 42 config blockOpsConfig 43 log traceLogger 44 queue *blockRetrievalQueue 45 } 46 47 var _ BlockOps = (*BlockOpsStandard)(nil) 48 49 // NewBlockOpsStandard creates a new BlockOpsStandard 50 func NewBlockOpsStandard( 51 config blockOpsConfig, queueSize, prefetchQueueSize int, 52 throttledPrefetchPeriod time.Duration, 53 appStateUpdater env.AppStateUpdater) *BlockOpsStandard { 54 bg := &realBlockGetter{config: config} 55 qConfig := &realBlockRetrievalConfig{ 56 blockRetrievalPartialConfig: config, 57 bg: bg, 58 } 59 q := newBlockRetrievalQueue( 60 queueSize, prefetchQueueSize, throttledPrefetchPeriod, qConfig, 61 appStateUpdater) 62 bops := &BlockOpsStandard{ 63 config: config, 64 log: traceLogger{config.MakeLogger("")}, 65 queue: q, 66 } 67 return bops 68 } 69 70 // Get implements the BlockOps interface for BlockOpsStandard. 71 func (b *BlockOpsStandard) Get(ctx context.Context, kmd libkey.KeyMetadata, 72 blockPtr data.BlockPointer, block data.Block, 73 lifetime data.BlockCacheLifetime, branch data.BranchName) error { 74 // Check the journal explicitly first, so we don't get stuck in 75 // the block-fetching queue. 76 if journalBServer, ok := b.config.BlockServer().(journalBlockServer); ok { 77 data, serverHalf, found, err := journalBServer.getBlockFromJournal( 78 ctx, kmd.TlfID(), blockPtr.ID) 79 if err != nil { 80 return err 81 } 82 if found { 83 return assembleBlockLocal( 84 ctx, b.config.keyGetter(), b.config.Codec(), 85 b.config.cryptoPure(), kmd, blockPtr, block, data, serverHalf) 86 } 87 } 88 89 b.log.LazyTrace(ctx, "BOps: Requesting %s", blockPtr.ID) 90 91 action := b.config.Mode().DefaultBlockRequestAction() 92 if branch != data.MasterBranch { 93 action = action.AddNonMasterBranch() 94 } 95 errCh := b.queue.Request( 96 ctx, defaultOnDemandRequestPriority, kmd, 97 blockPtr, block, lifetime, action) 98 err := <-errCh 99 100 b.log.LazyTrace(ctx, "BOps: Request fulfilled for %s (err=%v)", blockPtr.ID, err) 101 102 return err 103 } 104 105 // GetEncodedSizes implements the BlockOps interface for 106 // BlockOpsStandard. 107 func (b *BlockOpsStandard) GetEncodedSizes( 108 ctx context.Context, kmd libkey.KeyMetadata, 109 blockPtrs []data.BlockPointer) ( 110 sizes []uint32, statuses []keybase1.BlockStatus, err error) { 111 // Check the journal explicitly first, so we don't get stuck in 112 // the block-fetching queue. 113 114 var ids []kbfsblock.ID 115 var contexts []kbfsblock.Context 116 var indices []int 117 sizes = make([]uint32, len(blockPtrs)) 118 statuses = make([]keybase1.BlockStatus, len(blockPtrs)) 119 120 for i, blockPtr := range blockPtrs { 121 if journalBServer, ok := b.config.BlockServer().(journalBlockServer); ok { 122 size, found, err := journalBServer.getBlockSizeFromJournal( 123 ctx, kmd.TlfID(), blockPtr.ID) 124 if err != nil { 125 return nil, nil, err 126 } 127 if found && size > 0 { 128 sizes[i] = size 129 statuses[i] = keybase1.BlockStatus_LIVE 130 continue 131 } 132 } 133 134 // Not in journal. 135 ids = append(ids, blockPtr.ID) 136 contexts = append(contexts, blockPtr.Context) 137 indices = append(indices, i) 138 } 139 140 if len(ids) == 0 { 141 return sizes, statuses, nil 142 } 143 144 servSizes, servStatuses, err := b.config.BlockServer().GetEncodedSizes( 145 ctx, kmd.TlfID(), ids, contexts) 146 if err != nil { 147 return nil, nil, err 148 } 149 150 for i, j := range indices { 151 sizes[j] = servSizes[i] 152 statuses[j] = servStatuses[i] 153 } 154 return sizes, statuses, nil 155 } 156 157 // Ready implements the BlockOps interface for BlockOpsStandard. 158 func (b *BlockOpsStandard) Ready(ctx context.Context, kmd libkey.KeyMetadata, 159 block data.Block) (id kbfsblock.ID, plainSize int, readyBlockData data.ReadyBlockData, 160 err error) { 161 defer func() { 162 if err != nil { 163 id = kbfsblock.ID{} 164 plainSize = 0 165 readyBlockData = data.ReadyBlockData{} 166 } 167 }() 168 169 crypto := b.config.cryptoPure() 170 171 tlfCryptKey, err := b.config.keyGetter(). 172 GetTLFCryptKeyForEncryption(ctx, kmd) 173 if err != nil { 174 return 175 } 176 177 // New server key half for the block. 178 serverHalf, err := crypto.MakeRandomBlockCryptKeyServerHalf() 179 if err != nil { 180 return 181 } 182 183 plainSize, encryptedBlock, err := crypto.EncryptBlock( 184 block, tlfCryptKey, serverHalf) 185 if err != nil { 186 return 187 } 188 189 buf, err := b.config.Codec().Encode(encryptedBlock) 190 if err != nil { 191 return 192 } 193 194 readyBlockData = data.ReadyBlockData{ 195 Buf: buf, 196 ServerHalf: serverHalf, 197 } 198 199 encodedSize := readyBlockData.GetEncodedSize() 200 if encodedSize < plainSize { 201 err = TooLowByteCountError{ 202 ExpectedMinByteCount: plainSize, 203 ByteCount: encodedSize, 204 } 205 return 206 } 207 208 id, err = kbfsblock.MakePermanentID(buf, encryptedBlock.Version) 209 if err != nil { 210 return 211 } 212 213 // Cache the encoded size. 214 block.SetEncodedSize(uint32(encodedSize)) 215 216 return 217 } 218 219 // Delete implements the BlockOps interface for BlockOpsStandard. 220 func (b *BlockOpsStandard) Delete(ctx context.Context, tlfID tlf.ID, 221 ptrs []data.BlockPointer) (liveCounts map[kbfsblock.ID]int, err error) { 222 contexts := make(kbfsblock.ContextMap) 223 for _, ptr := range ptrs { 224 contexts[ptr.ID] = append(contexts[ptr.ID], ptr.Context) 225 } 226 return b.config.BlockServer().RemoveBlockReferences(ctx, tlfID, contexts) 227 } 228 229 // Archive implements the BlockOps interface for BlockOpsStandard. 230 func (b *BlockOpsStandard) Archive(ctx context.Context, tlfID tlf.ID, 231 ptrs []data.BlockPointer) error { 232 contexts := make(kbfsblock.ContextMap) 233 for _, ptr := range ptrs { 234 contexts[ptr.ID] = append(contexts[ptr.ID], ptr.Context) 235 } 236 237 return b.config.BlockServer().ArchiveBlockReferences(ctx, tlfID, contexts) 238 } 239 240 // GetLiveCount implements the BlockOps interface for BlockOpsStandard. 241 func (b *BlockOpsStandard) GetLiveCount( 242 ctx context.Context, tlfID tlf.ID, ptrs []data.BlockPointer) ( 243 liveCounts map[kbfsblock.ID]int, err error) { 244 contexts := make(kbfsblock.ContextMap) 245 for _, ptr := range ptrs { 246 contexts[ptr.ID] = append(contexts[ptr.ID], ptr.Context) 247 } 248 249 return b.config.BlockServer().GetLiveBlockReferences(ctx, tlfID, contexts) 250 } 251 252 // TogglePrefetcher implements the BlockOps interface for BlockOpsStandard. 253 func (b *BlockOpsStandard) TogglePrefetcher(enable bool) <-chan struct{} { 254 return b.queue.TogglePrefetcher(enable, nil, nil) 255 } 256 257 // Prefetcher implements the BlockOps interface for BlockOpsStandard. 258 func (b *BlockOpsStandard) Prefetcher() Prefetcher { 259 return b.queue.Prefetcher() 260 } 261 262 // BlockRetriever implements the BlockOps interface for BlockOpsStandard. 263 func (b *BlockOpsStandard) BlockRetriever() BlockRetriever { 264 return b.queue 265 } 266 267 // Shutdown implements the BlockOps interface for BlockOpsStandard. 268 func (b *BlockOpsStandard) Shutdown(ctx context.Context) error { 269 // Block on the queue being done. 270 select { 271 case <-b.queue.Shutdown(): 272 return nil 273 case <-ctx.Done(): 274 return errors.WithStack(ctx.Err()) 275 } 276 }