github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/graveler/committed/manager.go (about) 1 package committed 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "fmt" 8 "sort" 9 10 "github.com/treeverse/lakefs/pkg/graveler" 11 "github.com/treeverse/lakefs/pkg/logging" 12 ) 13 14 type committedManager struct { 15 metaRangeManager MetaRangeManager 16 RangeManager RangeManager 17 params *Params 18 } 19 20 func NewCommittedManager(m MetaRangeManager, r RangeManager, p Params) graveler.CommittedManager { 21 return &committedManager{ 22 metaRangeManager: m, 23 RangeManager: r, 24 params: &p, 25 } 26 } 27 28 func (c *committedManager) Exists(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID) (bool, error) { 29 return c.metaRangeManager.Exists(ctx, ns, id) 30 } 31 32 func (c *committedManager) Get(ctx context.Context, ns graveler.StorageNamespace, rangeID graveler.MetaRangeID, key graveler.Key) (*graveler.Value, error) { 33 it, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, rangeID) 34 if err != nil { 35 return nil, err 36 } 37 valIt := NewValueIterator(it) 38 defer valIt.Close() 39 valIt.SeekGE(key) 40 // return the next value 41 if !valIt.Next() { 42 // error or not found 43 if err := valIt.Err(); err != nil { 44 return nil, err 45 } 46 return nil, graveler.ErrNotFound 47 } 48 // compare the key we found 49 rec := valIt.Value() 50 if !bytes.Equal(rec.Key, key) { 51 return nil, graveler.ErrNotFound 52 } 53 return rec.Value, nil 54 } 55 56 func (c *committedManager) List(ctx context.Context, ns graveler.StorageNamespace, rangeID graveler.MetaRangeID) (graveler.ValueIterator, error) { 57 it, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, rangeID) 58 if err != nil { 59 return nil, err 60 } 61 return NewValueIterator(it), nil 62 } 63 64 func (c *committedManager) WriteRange(ctx context.Context, ns graveler.StorageNamespace, it graveler.ValueIterator) (*graveler.RangeInfo, error) { 65 writer, err := c.RangeManager.GetWriter(ctx, Namespace(ns), nil) 66 if err != nil { 67 return nil, fmt.Errorf("failed creating range writer: %w", err) 68 } 69 writer.SetMetadata(MetadataTypeKey, MetadataRangesType) 70 71 defer func() { 72 if err := writer.Abort(); err != nil { 73 logging.FromContext(ctx).WithError(err).Error("Aborting write to range") 74 } 75 }() 76 77 for it.Next() { 78 record := it.Value() 79 // skip nil value (kv can hold value nil) and tombstones 80 if record == nil || record.Value == nil { 81 continue 82 } 83 v, err := MarshalValue(record.Value) 84 if err != nil { 85 return nil, err 86 } 87 88 if err := writer.WriteRecord(Record{Key: Key(record.Key), Value: v}); err != nil { 89 return nil, fmt.Errorf("writing record: %w", err) 90 } 91 if writer.ShouldBreakAtKey(record.Key, c.params) { 92 break 93 } 94 } 95 if err := it.Err(); err != nil { 96 return nil, fmt.Errorf("getting value from iterator: %w", err) 97 } 98 99 info, err := writer.Close() 100 if err != nil { 101 return nil, fmt.Errorf("closing writer: %w", err) 102 } 103 104 return &graveler.RangeInfo{ 105 ID: graveler.RangeID(info.RangeID), 106 MinKey: graveler.Key(info.First), 107 MaxKey: graveler.Key(info.Last), 108 Count: info.Count, 109 EstimatedRangeSizeBytes: info.EstimatedRangeSizeBytes, 110 }, nil 111 } 112 113 func (c *committedManager) WriteMetaRange(ctx context.Context, ns graveler.StorageNamespace, ranges []*graveler.RangeInfo) (*graveler.MetaRangeInfo, error) { 114 writer := c.metaRangeManager.NewWriter(ctx, ns, nil) 115 defer func() { 116 if err := writer.Abort(); err != nil { 117 logging.FromContext(ctx).WithError(err).Error("Aborting write to meta range") 118 } 119 }() 120 121 sort.Slice(ranges, func(i, j int) bool { 122 return bytes.Compare(ranges[i].MinKey, ranges[j].MinKey) < 0 123 }) 124 125 for _, r := range ranges { 126 if err := writer.WriteRange(Range{ 127 ID: ID(r.ID), 128 MinKey: Key(r.MinKey), 129 MaxKey: Key(r.MaxKey), 130 EstimatedSize: r.EstimatedRangeSizeBytes, 131 Count: int64(r.Count), 132 Tombstone: false, 133 }); err != nil { 134 logging.FromContext(ctx).WithError(err).Error("Aborting writing range to meta range") 135 return nil, fmt.Errorf("writing range: %w", err) 136 } 137 } 138 139 id, err := writer.Close(ctx) 140 if err != nil { 141 return nil, fmt.Errorf("closing metarange: %w", err) 142 } 143 144 return &graveler.MetaRangeInfo{ 145 ID: *id, 146 }, nil 147 } 148 149 func (c *committedManager) WriteMetaRangeByIterator(ctx context.Context, ns graveler.StorageNamespace, it graveler.ValueIterator, metadata graveler.Metadata) (*graveler.MetaRangeID, error) { 150 writer := c.metaRangeManager.NewWriter(ctx, ns, metadata) 151 defer func() { 152 if err := writer.Abort(); err != nil { 153 logging.FromContext(ctx).WithError(err).Error("Aborting write to meta range") 154 } 155 }() 156 157 for it.Next() { 158 if err := writer.WriteRecord(*it.Value()); err != nil { 159 return nil, fmt.Errorf("writing record: %w", err) 160 } 161 } 162 if err := it.Err(); err != nil { 163 return nil, fmt.Errorf("getting value from iterator: %w", err) 164 } 165 id, err := writer.Close(ctx) 166 if err != nil { 167 return nil, fmt.Errorf("closing writer: %w", err) 168 } 169 170 return id, nil 171 } 172 173 func (c *committedManager) Diff(ctx context.Context, ns graveler.StorageNamespace, left, right graveler.MetaRangeID) (graveler.DiffIterator, error) { 174 leftIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, left) 175 if err != nil { 176 return nil, err 177 } 178 rightIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, right) 179 if err != nil { 180 return nil, err 181 } 182 return NewDiffValueIterator(ctx, leftIt, rightIt), nil 183 } 184 185 func (c *committedManager) Import(ctx context.Context, ns graveler.StorageNamespace, destination, source graveler.MetaRangeID, prefixes []graveler.Prefix, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, error) { 186 destIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, destination) 187 if err != nil { 188 return "", fmt.Errorf("get destination iterator: %w", err) 189 } 190 destIt = NewSkipPrefixIterator(prefixes, destIt) 191 defer destIt.Close() 192 mctx := mergeContext{ 193 destIt: destIt, 194 strategy: graveler.MergeStrategyNone, 195 ns: ns, 196 destinationID: destination, 197 sourceID: source, 198 baseID: "", 199 } 200 return c.merge(ctx, mctx) 201 } 202 203 func (c *committedManager) Merge(ctx context.Context, ns graveler.StorageNamespace, destination, source, base graveler.MetaRangeID, strategy graveler.MergeStrategy, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, error) { 204 if source == base { 205 // no changes on source 206 return "", graveler.ErrNoChanges 207 } 208 if destination == base { 209 // changes introduced only on source 210 return source, nil 211 } 212 mctx := mergeContext{ 213 strategy: strategy, 214 ns: ns, 215 destinationID: destination, 216 sourceID: source, 217 baseID: base, 218 } 219 return c.merge(ctx, mctx) 220 } 221 222 type mergeContext struct { 223 destIt Iterator 224 srcIt Iterator 225 baseIt Iterator 226 strategy graveler.MergeStrategy 227 ns graveler.StorageNamespace 228 destinationID graveler.MetaRangeID 229 sourceID graveler.MetaRangeID 230 baseID graveler.MetaRangeID 231 } 232 233 func (c *committedManager) merge(ctx context.Context, mctx mergeContext) (graveler.MetaRangeID, error) { 234 var err error = nil 235 baseIt := mctx.baseIt 236 if baseIt == nil { 237 baseIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.baseID) 238 if err != nil { 239 return "", fmt.Errorf("get base iterator: %w", err) 240 } 241 defer baseIt.Close() 242 } 243 244 destIt := mctx.destIt 245 if destIt == nil { 246 destIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.destinationID) 247 if err != nil { 248 return "", fmt.Errorf("get destination iterator: %w", err) 249 } 250 defer destIt.Close() 251 } 252 253 srcIt := mctx.srcIt 254 if srcIt == nil { 255 srcIt, err = c.metaRangeManager.NewMetaRangeIterator(ctx, mctx.ns, mctx.sourceID) 256 if err != nil { 257 return "", fmt.Errorf("get source iterator: %w", err) 258 } 259 defer srcIt.Close() 260 } 261 262 mwWriter := c.metaRangeManager.NewWriter(ctx, mctx.ns, nil) 263 defer func() { 264 err = mwWriter.Abort() 265 if err != nil { 266 logging.FromContext(ctx).WithError(err).Error("Abort failed after Merge") 267 } 268 }() 269 270 err = Merge(ctx, mwWriter, baseIt, srcIt, destIt, mctx.strategy) 271 if err != nil { 272 if !errors.Is(err, graveler.ErrUserVisible) { 273 err = fmt.Errorf("merge ns=%s id=%s: %w", mctx.ns, mctx.destinationID, err) 274 } 275 return "", err 276 } 277 newID, err := mwWriter.Close(ctx) 278 if newID == nil { 279 return "", fmt.Errorf("close writer ns=%s id=%s: %w", mctx.ns, mctx.destinationID, err) 280 } 281 return *newID, err 282 } 283 284 func (c *committedManager) Commit(ctx context.Context, ns graveler.StorageNamespace, baseMetaRangeID graveler.MetaRangeID, changes graveler.ValueIterator, allowEmpty bool, _ ...graveler.SetOptionsFunc) (graveler.MetaRangeID, graveler.DiffSummary, error) { 285 mwWriter := c.metaRangeManager.NewWriter(ctx, ns, nil) 286 defer func() { 287 err := mwWriter.Abort() 288 if err != nil { 289 logging.FromContext(ctx).WithError(err).Error("Abort failed after Commit") 290 } 291 }() 292 metaRangeIterator, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, baseMetaRangeID) 293 summary := graveler.DiffSummary{ 294 Count: map[graveler.DiffType]int{}, 295 } 296 if err != nil { 297 return "", summary, fmt.Errorf("get metarange ns=%s id=%s: %w", ns, baseMetaRangeID, err) 298 } 299 defer metaRangeIterator.Close() 300 summary, err = Commit(ctx, mwWriter, metaRangeIterator, changes, &CommitOptions{AllowEmpty: allowEmpty}) 301 if err != nil { 302 if !errors.Is(err, graveler.ErrUserVisible) { 303 err = fmt.Errorf("commit ns=%s id=%s: %w", ns, baseMetaRangeID, err) 304 } 305 return "", summary, err 306 } 307 newID, err := mwWriter.Close(ctx) 308 if newID == nil { 309 return "", summary, fmt.Errorf("close writer ns=%s metarange id=%s: %w", ns, baseMetaRangeID, err) 310 } 311 return *newID, summary, err 312 } 313 314 func (c *committedManager) Compare(ctx context.Context, ns graveler.StorageNamespace, destination, source, base graveler.MetaRangeID) (graveler.DiffIterator, error) { 315 diffIt, err := c.Diff(ctx, ns, destination, source) 316 if err != nil { 317 return nil, fmt.Errorf("diff: %w", err) 318 } 319 baseIt, err := c.metaRangeManager.NewMetaRangeIterator(ctx, ns, base) 320 if err != nil { 321 diffIt.Close() 322 return nil, fmt.Errorf("get base iterator: %w", err) 323 } 324 return NewCompareValueIterator(ctx, NewDiffIteratorWrapper(diffIt), baseIt), nil 325 } 326 327 func (c *committedManager) GetMetaRange(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID) (graveler.MetaRangeAddress, error) { 328 uri, err := c.metaRangeManager.GetMetaRangeURI(ctx, ns, id) 329 return graveler.MetaRangeAddress(uri), err 330 } 331 332 func (c *committedManager) GetRange(ctx context.Context, ns graveler.StorageNamespace, id graveler.RangeID) (graveler.RangeAddress, error) { 333 uri, err := c.metaRangeManager.GetRangeURI(ctx, ns, id) 334 return graveler.RangeAddress(uri), err 335 } 336 337 func (c *committedManager) GetRangeIDByKey(ctx context.Context, ns graveler.StorageNamespace, id graveler.MetaRangeID, key graveler.Key) (graveler.RangeID, error) { 338 if id == "" { 339 return "", graveler.ErrNotFound 340 } 341 r, err := c.metaRangeManager.GetRangeByKey(ctx, ns, id, key) 342 if err != nil { 343 return "", fmt.Errorf("get range for key: %w", err) 344 } 345 return graveler.RangeID(r.ID), nil 346 }