github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/journal_block_server.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 "github.com/keybase/client/go/kbfs/kbfsblock" 9 "github.com/keybase/client/go/kbfs/kbfscrypto" 10 "github.com/keybase/client/go/kbfs/tlf" 11 "github.com/pkg/errors" 12 "golang.org/x/net/context" 13 ) 14 15 type journalBlockServer struct { 16 jManager *JournalManager 17 BlockServer 18 enableAddBlockReference bool 19 } 20 21 var _ BlockServer = journalBlockServer{} 22 23 func (j journalBlockServer) getBlockFromJournal( 24 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID) ( 25 data []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf, 26 found bool, err error) { 27 tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil) 28 if !ok { 29 return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil 30 } 31 32 defer func() { 33 err = translateToBlockServerError(err) 34 }() 35 data, serverHalf, err = tlfJournal.getBlockData(ctx, id) 36 switch errors.Cause(err).(type) { 37 case nil: 38 return data, serverHalf, true, nil 39 case blockNonExistentError: 40 return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil 41 case errTLFJournalDisabled: 42 return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, nil 43 default: 44 return nil, kbfscrypto.BlockCryptKeyServerHalf{}, false, err 45 } 46 } 47 48 func (j journalBlockServer) getBlockSizeFromJournal( 49 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID) ( 50 size uint32, found bool, err error) { 51 tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil) 52 if !ok { 53 return 0, false, nil 54 } 55 56 defer func() { 57 err = translateToBlockServerError(err) 58 }() 59 size, err = tlfJournal.getBlockSize(ctx, id) 60 switch errors.Cause(err).(type) { 61 case nil: 62 return size, true, nil 63 case blockNonExistentError: 64 return 0, false, nil 65 case errTLFJournalDisabled: 66 return 0, false, nil 67 default: 68 return 0, false, err 69 } 70 } 71 72 func (j journalBlockServer) Get( 73 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 74 context kbfsblock.Context, cacheType DiskBlockCacheType) ( 75 data []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf, err error) { 76 j.jManager.log.LazyTrace(ctx, "jBServer: Get %s", id) 77 defer func() { 78 j.jManager.deferLog.LazyTrace(ctx, "jBServer: Get %s done (err=%v)", id, err) 79 }() 80 81 data, serverHalf, found, err := j.getBlockFromJournal(ctx, tlfID, id) 82 if err != nil { 83 return nil, kbfscrypto.BlockCryptKeyServerHalf{}, err 84 } 85 if found { 86 return data, serverHalf, nil 87 } 88 89 return j.BlockServer.Get(ctx, tlfID, id, context, cacheType) 90 } 91 92 func (j journalBlockServer) Put( 93 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 94 context kbfsblock.Context, buf []byte, 95 serverHalf kbfscrypto.BlockCryptKeyServerHalf, 96 cacheType DiskBlockCacheType) (err error) { 97 // Don't trace this function, as it gets too verbose and is 98 // called in parallel anyway. Rely on caller (usually 99 // doBlockPuts) to do the tracing. 100 101 if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok { 102 defer func() { 103 err = translateToBlockServerError(err) 104 }() 105 err := tlfJournal.putBlockData(ctx, id, context, buf, serverHalf) 106 switch e := errors.Cause(err).(type) { 107 case nil: 108 usedQuotaBytes, quotaBytes := tlfJournal.getQuotaInfo() 109 return j.jManager.maybeReturnOverQuotaError( 110 usedQuotaBytes, quotaBytes) 111 case errTLFJournalDisabled: 112 break 113 case *ErrDiskLimitTimeout: 114 return j.jManager.maybeMakeDiskLimitErrorReportable(e) 115 default: 116 return err 117 } 118 } 119 120 return j.BlockServer.Put( 121 ctx, tlfID, id, context, buf, serverHalf, cacheType) 122 } 123 124 func (j journalBlockServer) AddBlockReference( 125 ctx context.Context, tlfID tlf.ID, id kbfsblock.ID, 126 context kbfsblock.Context) (err error) { 127 j.jManager.log.LazyTrace(ctx, "jBServer: AddRef %s", id) 128 defer func() { 129 j.jManager.deferLog.LazyTrace(ctx, "jBServer: AddRef %s done (err=%v)", id, err) 130 }() 131 132 if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok { 133 if !j.enableAddBlockReference { 134 // TODO: Temporarily return an error until KBFS-1149 is 135 // fixed. This is needed despite 136 // journalBlockCache.CheckForBlockPtr, since 137 // CheckForBlockPtr may be called before journaling is 138 // turned on for a TLF. 139 return kbfsblock.ServerErrorBlockNonExistent{} 140 } 141 142 defer func() { 143 err = translateToBlockServerError(err) 144 }() 145 err := tlfJournal.addBlockReference(ctx, id, context) 146 switch errors.Cause(err).(type) { 147 case nil: 148 return nil 149 case errTLFJournalDisabled: 150 break 151 default: 152 return err 153 } 154 } 155 156 return j.BlockServer.AddBlockReference(ctx, tlfID, id, context) 157 } 158 159 func (j journalBlockServer) RemoveBlockReferences( 160 ctx context.Context, tlfID tlf.ID, 161 contexts kbfsblock.ContextMap) ( 162 liveCounts map[kbfsblock.ID]int, err error) { 163 j.jManager.log.LazyTrace(ctx, "jBServer: RemRef %v", contexts) 164 defer func() { 165 j.jManager.deferLog.LazyTrace(ctx, "jBServer: RemRef %v done (err=%v)", contexts, err) 166 }() 167 168 // Deletes always go straight to the server, since they slow down 169 // the journal and already only happen in the background anyway. 170 // Note that this means delete operations must be issued after the 171 // corresponding MD that unreferenced the block was flushed from 172 // the journal. 173 return j.BlockServer.RemoveBlockReferences(ctx, tlfID, contexts) 174 } 175 176 func (j journalBlockServer) ArchiveBlockReferences( 177 ctx context.Context, tlfID tlf.ID, 178 contexts kbfsblock.ContextMap) (err error) { 179 j.jManager.log.LazyTrace(ctx, "jBServer: ArchiveRef %v", contexts) 180 defer func() { 181 j.jManager.deferLog.LazyTrace(ctx, "jBServer: ArchiveRef %v done (err=%v)", contexts, err) 182 }() 183 184 // Archives always go straight to the server, since they slow down 185 // the journal and already only happen in the background anyway. 186 // Note that this means delete operations must be issued after the 187 // corresponding MD that unreferenced the block was flushed from 188 // the journal. 189 return j.BlockServer.ArchiveBlockReferences(ctx, tlfID, contexts) 190 } 191 192 func (j journalBlockServer) IsUnflushed(ctx context.Context, tlfID tlf.ID, 193 id kbfsblock.ID) (isLocal bool, err error) { 194 j.jManager.log.LazyTrace(ctx, "jBServer: IsUnflushed %s", id) 195 defer func() { 196 j.jManager.deferLog.LazyTrace(ctx, "jBServer: IsUnflushed %s done (err=%v)", id, err) 197 }() 198 199 if tlfJournal, ok := j.jManager.getTLFJournal(tlfID, nil); ok { 200 defer func() { 201 err = translateToBlockServerError(err) 202 }() 203 return tlfJournal.isBlockUnflushed(ctx, id) 204 } 205 206 return j.BlockServer.IsUnflushed(ctx, tlfID, id) 207 } 208 209 func (j journalBlockServer) Shutdown(ctx context.Context) { 210 j.jManager.shutdown(ctx) 211 j.BlockServer.Shutdown(ctx) 212 }