(ctx context.Context, txh blobcache.Handle, srcTxns []blobcache.Handle, cids []blobcache.CID, out *blobcache.BitMap)
| 160 | } |
| 161 | |
| 162 | func (sys *System) Copy(ctx context.Context, txh blobcache.Handle, srcTxns []blobcache.Handle, cids []blobcache.CID, out *blobcache.BitMap) error { |
| 163 | logctx.Debug(ctx, "begin", zap.String("method", "Copy"), zap.Stringer("oid", txh.OID)) |
| 164 | defer logctx.Debug(ctx, "done", zap.String("method", "Copy"), zap.Stringer("oid", txh.OID)) |
| 165 | dstTx, err := sys.resolveTx(txh, true, blobcache.Action_TX_COPY_TO) |
| 166 | if err != nil { |
| 167 | return err |
| 168 | } |
| 169 | if p := dstTx.backend.Params(); !p.Modify { |
| 170 | return blobcache.ErrTxReadOnly{Tx: txh.OID, Op: "COPY"} |
| 171 | } |
| 172 | |
| 173 | type srcTxn struct { |
| 174 | oid blobcache.OID |
| 175 | tx transaction |
| 176 | } |
| 177 | resolvedSrcs := make([]srcTxn, len(srcTxns)) |
| 178 | for i, srcH := range srcTxns { |
| 179 | src, err := sys.resolveTx(srcH, true, blobcache.Action_TX_COPY_FROM) |
| 180 | if err != nil { |
| 181 | return err |
| 182 | } |
| 183 | resolvedSrcs[i] = srcTxn{oid: srcH.OID, tx: src} |
| 184 | } |
| 185 | |
| 186 | var buf []byte |
| 187 | var exists blobcache.BitMap |
| 188 | for i, cid := range cids { |
| 189 | if len(resolvedSrcs) == 0 { |
| 190 | continue |
| 191 | } |
| 192 | start := int(cid[0]) % len(resolvedSrcs) |
| 193 | for j := range resolvedSrcs { |
| 194 | src := resolvedSrcs[(start+j)%len(resolvedSrcs)] |
| 195 | exists = exists[:0] |
| 196 | if err := src.tx.backend.Exists(ctx, []blobcache.CID{cid}, &exists); err != nil { |
| 197 | return fmt.Errorf("copy from tx %v: %w", src.oid, err) |
| 198 | } |
| 199 | if !exists.IsSet(0) { |
| 200 | continue |
| 201 | } |
| 202 | srcMax := src.tx.backend.MaxSize() |
| 203 | if cap(buf) < srcMax { |
| 204 | buf = make([]byte, srcMax) |
| 205 | } |
| 206 | n, err := src.tx.backend.Get(ctx, cid, buf[:srcMax], blobcache.GetOpts{}) |
| 207 | if err != nil { |
| 208 | if blobcache.IsErrNotFound(err) { |
| 209 | continue |
| 210 | } |
| 211 | return fmt.Errorf("copy from tx %v: %w", src.oid, err) |
| 212 | } |
| 213 | data := buf[:n] |
| 214 | if dstTx.backend.HashAlgo().Hash(data) != cid { |
| 215 | continue |
| 216 | } |
| 217 | cid2, err := dstTx.backend.Post(ctx, data, blobcache.PostOpts{}) |
| 218 | if err != nil { |
| 219 | var eTooLarge blobcache.ErrTooLarge |
nothing calls this directly
no test coverage detected